[Pkg-samba-maint] r3989 - in branches/ctdb/squeeze-backports: . client common config config/events.d doc ib include lib lib/replace lib/replace/system lib/replace/tests lib/talloc lib/talloc/doc lib/talloc/web lib/tdb lib/tdb/ABI lib/tdb/common lib/tdb/docs lib/tdb/include lib/tdb/python lib/tdb/python/tests lib/tdb/script lib/tdb/tools lib/tdb/web lib/tevent lib/tevent/ABI lib/tevent/doc lib/tevent/script lib/util libctdb libctdb/test libctdb/test/tests libctdb/test/tools packaging packaging/RPM server tcp tests tests/complex tests/events.d tests/eventscripts tests/eventscripts/etc tests/eventscripts/etc/init.d tests/eventscripts/etc/samba tests/eventscripts/etc/sysconfig tests/eventscripts/etc-ctdb tests/eventscripts/multievent tests/eventscripts/simple tests/eventscripts/stubs tests/onnode tests/onnode/stubs tests/scripts tests/simple tests/src tests/takeover tests/takeover/testcases tools utils utils/ping_pong utils/pmda utils/scsi_io utils/smnotify web

bubulle at alioth.debian.org bubulle at alioth.debian.org
Sun Jan 15 21:10:19 UTC 2012


Author: bubulle
Date: 2012-01-15 21:10:16 +0000 (Sun, 15 Jan 2012)
New Revision: 3989

Added:
   branches/ctdb/squeeze-backports/COPYING
   branches/ctdb/squeeze-backports/Makefile.in
   branches/ctdb/squeeze-backports/README.Coding
   branches/ctdb/squeeze-backports/aclocal.m4
   branches/ctdb/squeeze-backports/autogen.sh
   branches/ctdb/squeeze-backports/client/
   branches/ctdb/squeeze-backports/client/ctdb_client.c
   branches/ctdb/squeeze-backports/common/
   branches/ctdb/squeeze-backports/common/cmdline.c
   branches/ctdb/squeeze-backports/common/ctdb_io.c
   branches/ctdb/squeeze-backports/common/ctdb_logging.c
   branches/ctdb/squeeze-backports/common/ctdb_ltdb.c
   branches/ctdb/squeeze-backports/common/ctdb_message.c
   branches/ctdb/squeeze-backports/common/ctdb_util.c
   branches/ctdb/squeeze-backports/common/rb_tree.c
   branches/ctdb/squeeze-backports/common/rb_tree.h
   branches/ctdb/squeeze-backports/common/system_aix.c
   branches/ctdb/squeeze-backports/common/system_common.c
   branches/ctdb/squeeze-backports/common/system_linux.c
   branches/ctdb/squeeze-backports/config.guess
   branches/ctdb/squeeze-backports/config.h.in
   branches/ctdb/squeeze-backports/config.mk
   branches/ctdb/squeeze-backports/config.sub
   branches/ctdb/squeeze-backports/config/
   branches/ctdb/squeeze-backports/config/README
   branches/ctdb/squeeze-backports/config/ctdb-crash-cleanup.sh
   branches/ctdb/squeeze-backports/config/ctdb.init
   branches/ctdb/squeeze-backports/config/ctdb.sysconfig
   branches/ctdb/squeeze-backports/config/events.d/
   branches/ctdb/squeeze-backports/config/events.d/00.ctdb
   branches/ctdb/squeeze-backports/config/events.d/01.reclock
   branches/ctdb/squeeze-backports/config/events.d/10.interface
   branches/ctdb/squeeze-backports/config/events.d/11.natgw
   branches/ctdb/squeeze-backports/config/events.d/11.routing
   branches/ctdb/squeeze-backports/config/events.d/13.per_ip_routing
   branches/ctdb/squeeze-backports/config/events.d/20.multipathd
   branches/ctdb/squeeze-backports/config/events.d/31.clamd
   branches/ctdb/squeeze-backports/config/events.d/40.fs_use
   branches/ctdb/squeeze-backports/config/events.d/40.vsftpd
   branches/ctdb/squeeze-backports/config/events.d/41.httpd
   branches/ctdb/squeeze-backports/config/events.d/50.samba
   branches/ctdb/squeeze-backports/config/events.d/60.ganesha
   branches/ctdb/squeeze-backports/config/events.d/60.nfs
   branches/ctdb/squeeze-backports/config/events.d/62.cnfs
   branches/ctdb/squeeze-backports/config/events.d/70.iscsi
   branches/ctdb/squeeze-backports/config/events.d/91.lvs
   branches/ctdb/squeeze-backports/config/events.d/99.timeout
   branches/ctdb/squeeze-backports/config/events.d/README
   branches/ctdb/squeeze-backports/config/functions
   branches/ctdb/squeeze-backports/config/gdb_backtrace
   branches/ctdb/squeeze-backports/config/interface_modify.sh
   branches/ctdb/squeeze-backports/config/notify.sh
   branches/ctdb/squeeze-backports/config/statd-callout
   branches/ctdb/squeeze-backports/configure
   branches/ctdb/squeeze-backports/configure.ac
   branches/ctdb/squeeze-backports/configure.rpm
   branches/ctdb/squeeze-backports/ctdb.pc.in
   branches/ctdb/squeeze-backports/doc/
   branches/ctdb/squeeze-backports/doc/ctdb.1
   branches/ctdb/squeeze-backports/doc/ctdb.1.html
   branches/ctdb/squeeze-backports/doc/ctdb.1.xml
   branches/ctdb/squeeze-backports/doc/ctdbd.1
   branches/ctdb/squeeze-backports/doc/ctdbd.1.html
   branches/ctdb/squeeze-backports/doc/ctdbd.1.xml
   branches/ctdb/squeeze-backports/doc/ltdbtool.1
   branches/ctdb/squeeze-backports/doc/ltdbtool.1.html
   branches/ctdb/squeeze-backports/doc/ltdbtool.1.xml
   branches/ctdb/squeeze-backports/doc/onnode.1
   branches/ctdb/squeeze-backports/doc/onnode.1.html
   branches/ctdb/squeeze-backports/doc/onnode.1.xml
   branches/ctdb/squeeze-backports/doc/ping_pong.1
   branches/ctdb/squeeze-backports/doc/ping_pong.1.html
   branches/ctdb/squeeze-backports/doc/ping_pong.1.xml
   branches/ctdb/squeeze-backports/doc/readonlyrecords.txt
   branches/ctdb/squeeze-backports/doc/recovery-process.txt
   branches/ctdb/squeeze-backports/ib/
   branches/ctdb/squeeze-backports/ib/README.txt
   branches/ctdb/squeeze-backports/ib/config.m4
   branches/ctdb/squeeze-backports/ib/ibw_ctdb.c
   branches/ctdb/squeeze-backports/ib/ibw_ctdb.h
   branches/ctdb/squeeze-backports/ib/ibw_ctdb_init.c
   branches/ctdb/squeeze-backports/ib/ibwrapper.c
   branches/ctdb/squeeze-backports/ib/ibwrapper.h
   branches/ctdb/squeeze-backports/ib/ibwrapper_internal.h
   branches/ctdb/squeeze-backports/ib/ibwrapper_test.c
   branches/ctdb/squeeze-backports/include/
   branches/ctdb/squeeze-backports/include/cmdline.h
   branches/ctdb/squeeze-backports/include/ctdb.h
   branches/ctdb/squeeze-backports/include/ctdb_client.h
   branches/ctdb/squeeze-backports/include/ctdb_private.h
   branches/ctdb/squeeze-backports/include/ctdb_protocol.h
   branches/ctdb/squeeze-backports/include/ctdb_typesafe_cb.h
   branches/ctdb/squeeze-backports/include/idtree.h
   branches/ctdb/squeeze-backports/include/includes.h
   branches/ctdb/squeeze-backports/install-sh
   branches/ctdb/squeeze-backports/lib/
   branches/ctdb/squeeze-backports/lib/replace/
   branches/ctdb/squeeze-backports/lib/replace/.checker_innocent
   branches/ctdb/squeeze-backports/lib/replace/Makefile.in
   branches/ctdb/squeeze-backports/lib/replace/README
   branches/ctdb/squeeze-backports/lib/replace/aclocal.m4
   branches/ctdb/squeeze-backports/lib/replace/autoconf-2.60.m4
   branches/ctdb/squeeze-backports/lib/replace/autogen.sh
   branches/ctdb/squeeze-backports/lib/replace/config.guess
   branches/ctdb/squeeze-backports/lib/replace/config.h.in
   branches/ctdb/squeeze-backports/lib/replace/config.sub
   branches/ctdb/squeeze-backports/lib/replace/configure.ac
   branches/ctdb/squeeze-backports/lib/replace/dlfcn.c
   branches/ctdb/squeeze-backports/lib/replace/dlfcn.m4
   branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.c
   branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.h
   branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.m4
   branches/ctdb/squeeze-backports/lib/replace/getifaddrs.c
   branches/ctdb/squeeze-backports/lib/replace/getifaddrs.m4
   branches/ctdb/squeeze-backports/lib/replace/getpass.c
   branches/ctdb/squeeze-backports/lib/replace/getpass.m4
   branches/ctdb/squeeze-backports/lib/replace/havenone.h
   branches/ctdb/squeeze-backports/lib/replace/inet_ntop.c
   branches/ctdb/squeeze-backports/lib/replace/inet_ntop.m4
   branches/ctdb/squeeze-backports/lib/replace/inet_pton.c
   branches/ctdb/squeeze-backports/lib/replace/inet_pton.m4
   branches/ctdb/squeeze-backports/lib/replace/install-sh
   branches/ctdb/squeeze-backports/lib/replace/libreplace.m4
   branches/ctdb/squeeze-backports/lib/replace/libreplace_cc.m4
   branches/ctdb/squeeze-backports/lib/replace/libreplace_ld.m4
   branches/ctdb/squeeze-backports/lib/replace/libreplace_macros.m4
   branches/ctdb/squeeze-backports/lib/replace/repdir.m4
   branches/ctdb/squeeze-backports/lib/replace/repdir_getdents.c
   branches/ctdb/squeeze-backports/lib/replace/repdir_getdirentries.c
   branches/ctdb/squeeze-backports/lib/replace/replace.c
   branches/ctdb/squeeze-backports/lib/replace/replace.h
   branches/ctdb/squeeze-backports/lib/replace/samba.m4
   branches/ctdb/squeeze-backports/lib/replace/snprintf.c
   branches/ctdb/squeeze-backports/lib/replace/strptime.c
   branches/ctdb/squeeze-backports/lib/replace/strptime.m4
   branches/ctdb/squeeze-backports/lib/replace/system/
   branches/ctdb/squeeze-backports/lib/replace/system/README
   branches/ctdb/squeeze-backports/lib/replace/system/aio.h
   branches/ctdb/squeeze-backports/lib/replace/system/capability.h
   branches/ctdb/squeeze-backports/lib/replace/system/config.m4
   branches/ctdb/squeeze-backports/lib/replace/system/dir.h
   branches/ctdb/squeeze-backports/lib/replace/system/filesys.h
   branches/ctdb/squeeze-backports/lib/replace/system/glob.h
   branches/ctdb/squeeze-backports/lib/replace/system/iconv.h
   branches/ctdb/squeeze-backports/lib/replace/system/kerberos.h
   branches/ctdb/squeeze-backports/lib/replace/system/locale.h
   branches/ctdb/squeeze-backports/lib/replace/system/network.h
   branches/ctdb/squeeze-backports/lib/replace/system/passwd.h
   branches/ctdb/squeeze-backports/lib/replace/system/printing.h
   branches/ctdb/squeeze-backports/lib/replace/system/readline.h
   branches/ctdb/squeeze-backports/lib/replace/system/select.h
   branches/ctdb/squeeze-backports/lib/replace/system/shmem.h
   branches/ctdb/squeeze-backports/lib/replace/system/syslog.h
   branches/ctdb/squeeze-backports/lib/replace/system/terminal.h
   branches/ctdb/squeeze-backports/lib/replace/system/time.h
   branches/ctdb/squeeze-backports/lib/replace/system/wait.h
   branches/ctdb/squeeze-backports/lib/replace/tests/
   branches/ctdb/squeeze-backports/lib/replace/tests/os2_delete.c
   branches/ctdb/squeeze-backports/lib/replace/tests/shared_mmap.c
   branches/ctdb/squeeze-backports/lib/replace/tests/testsuite.c
   branches/ctdb/squeeze-backports/lib/replace/timegm.c
   branches/ctdb/squeeze-backports/lib/replace/timegm.m4
   branches/ctdb/squeeze-backports/lib/replace/win32.m4
   branches/ctdb/squeeze-backports/lib/replace/win32_replace.h
   branches/ctdb/squeeze-backports/lib/talloc/
   branches/ctdb/squeeze-backports/lib/talloc/Makefile.in
   branches/ctdb/squeeze-backports/lib/talloc/aclocal.m4
   branches/ctdb/squeeze-backports/lib/talloc/autogen.sh
   branches/ctdb/squeeze-backports/lib/talloc/config.guess
   branches/ctdb/squeeze-backports/lib/talloc/config.h.in
   branches/ctdb/squeeze-backports/lib/talloc/config.mk
   branches/ctdb/squeeze-backports/lib/talloc/config.sub
   branches/ctdb/squeeze-backports/lib/talloc/configure.ac
   branches/ctdb/squeeze-backports/lib/talloc/doc/
   branches/ctdb/squeeze-backports/lib/talloc/doc/mainpage.dox
   branches/ctdb/squeeze-backports/lib/talloc/doxy.config
   branches/ctdb/squeeze-backports/lib/talloc/install-sh
   branches/ctdb/squeeze-backports/lib/talloc/libtalloc.m4
   branches/ctdb/squeeze-backports/lib/talloc/talloc.3
   branches/ctdb/squeeze-backports/lib/talloc/talloc.3.html
   branches/ctdb/squeeze-backports/lib/talloc/talloc.3.xml
   branches/ctdb/squeeze-backports/lib/talloc/talloc.c
   branches/ctdb/squeeze-backports/lib/talloc/talloc.h
   branches/ctdb/squeeze-backports/lib/talloc/talloc.pc
   branches/ctdb/squeeze-backports/lib/talloc/talloc.pc.in
   branches/ctdb/squeeze-backports/lib/talloc/talloc_guide.txt
   branches/ctdb/squeeze-backports/lib/talloc/testsuite.c
   branches/ctdb/squeeze-backports/lib/talloc/testsuite_main.c
   branches/ctdb/squeeze-backports/lib/talloc/web/
   branches/ctdb/squeeze-backports/lib/talloc/web/index.html
   branches/ctdb/squeeze-backports/lib/tdb/
   branches/ctdb/squeeze-backports/lib/tdb/ABI/
   branches/ctdb/squeeze-backports/lib/tdb/ABI/tdb-1.2.6.sigs
   branches/ctdb/squeeze-backports/lib/tdb/Makefile.in
   branches/ctdb/squeeze-backports/lib/tdb/aclocal.m4
   branches/ctdb/squeeze-backports/lib/tdb/autogen.sh
   branches/ctdb/squeeze-backports/lib/tdb/build_macros.m4
   branches/ctdb/squeeze-backports/lib/tdb/common/
   branches/ctdb/squeeze-backports/lib/tdb/common/check.c
   branches/ctdb/squeeze-backports/lib/tdb/common/dump.c
   branches/ctdb/squeeze-backports/lib/tdb/common/error.c
   branches/ctdb/squeeze-backports/lib/tdb/common/freelist.c
   branches/ctdb/squeeze-backports/lib/tdb/common/freelistcheck.c
   branches/ctdb/squeeze-backports/lib/tdb/common/hash.c
   branches/ctdb/squeeze-backports/lib/tdb/common/io.c
   branches/ctdb/squeeze-backports/lib/tdb/common/lock.c
   branches/ctdb/squeeze-backports/lib/tdb/common/open.c
   branches/ctdb/squeeze-backports/lib/tdb/common/tdb.c
   branches/ctdb/squeeze-backports/lib/tdb/common/tdb_private.h
   branches/ctdb/squeeze-backports/lib/tdb/common/transaction.c
   branches/ctdb/squeeze-backports/lib/tdb/common/traverse.c
   branches/ctdb/squeeze-backports/lib/tdb/config.guess
   branches/ctdb/squeeze-backports/lib/tdb/config.mk
   branches/ctdb/squeeze-backports/lib/tdb/config.sub
   branches/ctdb/squeeze-backports/lib/tdb/configure.ac
   branches/ctdb/squeeze-backports/lib/tdb/docs/
   branches/ctdb/squeeze-backports/lib/tdb/docs/README
   branches/ctdb/squeeze-backports/lib/tdb/docs/tdb.magic
   branches/ctdb/squeeze-backports/lib/tdb/docs/tracing.txt
   branches/ctdb/squeeze-backports/lib/tdb/include/
   branches/ctdb/squeeze-backports/lib/tdb/include/tdb.h
   branches/ctdb/squeeze-backports/lib/tdb/install-sh
   branches/ctdb/squeeze-backports/lib/tdb/libtdb.m4
   branches/ctdb/squeeze-backports/lib/tdb/pytdb.c
   branches/ctdb/squeeze-backports/lib/tdb/python.mk
   branches/ctdb/squeeze-backports/lib/tdb/python/
   branches/ctdb/squeeze-backports/lib/tdb/python/tdbdump.py
   branches/ctdb/squeeze-backports/lib/tdb/python/tests/
   branches/ctdb/squeeze-backports/lib/tdb/python/tests/simple.py
   branches/ctdb/squeeze-backports/lib/tdb/rules.mk
   branches/ctdb/squeeze-backports/lib/tdb/script/
   branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks.sh
   branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks_gcc.sh
   branches/ctdb/squeeze-backports/lib/tdb/script/mksigs.pl
   branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.awk
   branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.sh
   branches/ctdb/squeeze-backports/lib/tdb/script/release-script.sh
   branches/ctdb/squeeze-backports/lib/tdb/tdb.exports
   branches/ctdb/squeeze-backports/lib/tdb/tdb.mk
   branches/ctdb/squeeze-backports/lib/tdb/tdb.pc.in
   branches/ctdb/squeeze-backports/lib/tdb/tdb.signatures
   branches/ctdb/squeeze-backports/lib/tdb/tools/
   branches/ctdb/squeeze-backports/lib/tdb/tools/tdbbackup.c
   branches/ctdb/squeeze-backports/lib/tdb/tools/tdbdump.c
   branches/ctdb/squeeze-backports/lib/tdb/tools/tdbrestore.c
   branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtest.c
   branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtool.c
   branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtorture.c
   branches/ctdb/squeeze-backports/lib/tdb/web/
   branches/ctdb/squeeze-backports/lib/tdb/web/index.html
   branches/ctdb/squeeze-backports/lib/tevent/
   branches/ctdb/squeeze-backports/lib/tevent/ABI/
   branches/ctdb/squeeze-backports/lib/tevent/ABI/tevent-0.9.9.sigs
   branches/ctdb/squeeze-backports/lib/tevent/Makefile.in
   branches/ctdb/squeeze-backports/lib/tevent/autogen-waf.sh
   branches/ctdb/squeeze-backports/lib/tevent/autogen.sh
   branches/ctdb/squeeze-backports/lib/tevent/build_macros.m4
   branches/ctdb/squeeze-backports/lib/tevent/config.guess
   branches/ctdb/squeeze-backports/lib/tevent/config.sub
   branches/ctdb/squeeze-backports/lib/tevent/configure.ac
   branches/ctdb/squeeze-backports/lib/tevent/doc/
   branches/ctdb/squeeze-backports/lib/tevent/doc/mainpage.dox
   branches/ctdb/squeeze-backports/lib/tevent/doc/tutorials.dox
   branches/ctdb/squeeze-backports/lib/tevent/doxy.config
   branches/ctdb/squeeze-backports/lib/tevent/install-sh
   branches/ctdb/squeeze-backports/lib/tevent/libtalloc.m4
   branches/ctdb/squeeze-backports/lib/tevent/libtevent.m4
   branches/ctdb/squeeze-backports/lib/tevent/pkg.m4
   branches/ctdb/squeeze-backports/lib/tevent/release-script.sh
   branches/ctdb/squeeze-backports/lib/tevent/rules.mk
   branches/ctdb/squeeze-backports/lib/tevent/samba.m4
   branches/ctdb/squeeze-backports/lib/tevent/script/
   branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks.sh
   branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks_gcc.sh
   branches/ctdb/squeeze-backports/lib/tevent/script/mksigs.pl
   branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.awk
   branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.sh
   branches/ctdb/squeeze-backports/lib/tevent/testsuite.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent.exports
   branches/ctdb/squeeze-backports/lib/tevent/tevent.h
   branches/ctdb/squeeze-backports/lib/tevent/tevent.mk
   branches/ctdb/squeeze-backports/lib/tevent/tevent.pc.in
   branches/ctdb/squeeze-backports/lib/tevent/tevent.signatures
   branches/ctdb/squeeze-backports/lib/tevent/tevent_debug.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_epoll.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_fd.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_immediate.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_internal.h
   branches/ctdb/squeeze-backports/lib/tevent/tevent_liboop.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_queue.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_req.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_select.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_signal.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_standard.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_timed.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_util.c
   branches/ctdb/squeeze-backports/lib/tevent/tevent_util.h
   branches/ctdb/squeeze-backports/lib/tevent/tevent_wakeup.c
   branches/ctdb/squeeze-backports/lib/tevent/wscript
   branches/ctdb/squeeze-backports/lib/util/
   branches/ctdb/squeeze-backports/lib/util/db_wrap.c
   branches/ctdb/squeeze-backports/lib/util/db_wrap.h
   branches/ctdb/squeeze-backports/lib/util/debug.c
   branches/ctdb/squeeze-backports/lib/util/debug.h
   branches/ctdb/squeeze-backports/lib/util/dlinklist.h
   branches/ctdb/squeeze-backports/lib/util/fault.c
   branches/ctdb/squeeze-backports/lib/util/fault.m4
   branches/ctdb/squeeze-backports/lib/util/idtree.c
   branches/ctdb/squeeze-backports/lib/util/signal.c
   branches/ctdb/squeeze-backports/lib/util/signal.m4
   branches/ctdb/squeeze-backports/lib/util/strlist.c
   branches/ctdb/squeeze-backports/lib/util/substitute.c
   branches/ctdb/squeeze-backports/lib/util/util.c
   branches/ctdb/squeeze-backports/lib/util/util.h
   branches/ctdb/squeeze-backports/lib/util/util_file.c
   branches/ctdb/squeeze-backports/lib/util/util_time.c
   branches/ctdb/squeeze-backports/libctdb/
   branches/ctdb/squeeze-backports/libctdb/TODO
   branches/ctdb/squeeze-backports/libctdb/control.c
   branches/ctdb/squeeze-backports/libctdb/ctdb.c
   branches/ctdb/squeeze-backports/libctdb/io_elem.c
   branches/ctdb/squeeze-backports/libctdb/io_elem.h
   branches/ctdb/squeeze-backports/libctdb/libctdb_private.h
   branches/ctdb/squeeze-backports/libctdb/local_tdb.c
   branches/ctdb/squeeze-backports/libctdb/local_tdb.h
   branches/ctdb/squeeze-backports/libctdb/logging.c
   branches/ctdb/squeeze-backports/libctdb/messages.c
   branches/ctdb/squeeze-backports/libctdb/messages.h
   branches/ctdb/squeeze-backports/libctdb/sync.c
   branches/ctdb/squeeze-backports/libctdb/test/
   branches/ctdb/squeeze-backports/libctdb/test/Makefile
   branches/ctdb/squeeze-backports/libctdb/test/attachdb.c
   branches/ctdb/squeeze-backports/libctdb/test/ctdb-test.c
   branches/ctdb/squeeze-backports/libctdb/test/ctdb-test.h
   branches/ctdb/squeeze-backports/libctdb/test/databases.c
   branches/ctdb/squeeze-backports/libctdb/test/expect.c
   branches/ctdb/squeeze-backports/libctdb/test/expect.h
   branches/ctdb/squeeze-backports/libctdb/test/failtest.c
   branches/ctdb/squeeze-backports/libctdb/test/failtest.h
   branches/ctdb/squeeze-backports/libctdb/test/log.c
   branches/ctdb/squeeze-backports/libctdb/test/log.h
   branches/ctdb/squeeze-backports/libctdb/test/readrecordlock.c
   branches/ctdb/squeeze-backports/libctdb/test/run.sh
   branches/ctdb/squeeze-backports/libctdb/test/tests/
   branches/ctdb/squeeze-backports/libctdb/test/tests/attachdb1.txt
   branches/ctdb/squeeze-backports/libctdb/test/tests/connect1.txt
   branches/ctdb/squeeze-backports/libctdb/test/tests/connect2.txt
   branches/ctdb/squeeze-backports/libctdb/test/tests/lockrecord1.txt
   branches/ctdb/squeeze-backports/libctdb/test/tests/lockrecord2.txt
   branches/ctdb/squeeze-backports/libctdb/test/tools/
   branches/ctdb/squeeze-backports/libctdb/test/tools/create-links
   branches/ctdb/squeeze-backports/libctdb/test/tools/extract-help
   branches/ctdb/squeeze-backports/libctdb/test/tools/gen-help
   branches/ctdb/squeeze-backports/libctdb/test/tools/gen-usage
   branches/ctdb/squeeze-backports/libctdb/test/tools/text.xsl
   branches/ctdb/squeeze-backports/libctdb/test/tools/usage.xsl
   branches/ctdb/squeeze-backports/libctdb/test/tui.c
   branches/ctdb/squeeze-backports/libctdb/test/tui.h
   branches/ctdb/squeeze-backports/libctdb/test/utils.h
   branches/ctdb/squeeze-backports/libctdb/tst.c
   branches/ctdb/squeeze-backports/packaging/
   branches/ctdb/squeeze-backports/packaging/RPM/
   branches/ctdb/squeeze-backports/packaging/RPM/ctdb.spec.in
   branches/ctdb/squeeze-backports/packaging/RPM/makerpms.sh
   branches/ctdb/squeeze-backports/packaging/maketarball.sh
   branches/ctdb/squeeze-backports/server/
   branches/ctdb/squeeze-backports/server/ctdb_banning.c
   branches/ctdb/squeeze-backports/server/ctdb_call.c
   branches/ctdb/squeeze-backports/server/ctdb_control.c
   branches/ctdb/squeeze-backports/server/ctdb_daemon.c
   branches/ctdb/squeeze-backports/server/ctdb_freeze.c
   branches/ctdb/squeeze-backports/server/ctdb_keepalive.c
   branches/ctdb/squeeze-backports/server/ctdb_lockwait.c
   branches/ctdb/squeeze-backports/server/ctdb_logging.c
   branches/ctdb/squeeze-backports/server/ctdb_ltdb_server.c
   branches/ctdb/squeeze-backports/server/ctdb_monitor.c
   branches/ctdb/squeeze-backports/server/ctdb_persistent.c
   branches/ctdb/squeeze-backports/server/ctdb_recover.c
   branches/ctdb/squeeze-backports/server/ctdb_recoverd.c
   branches/ctdb/squeeze-backports/server/ctdb_server.c
   branches/ctdb/squeeze-backports/server/ctdb_serverids.c
   branches/ctdb/squeeze-backports/server/ctdb_statistics.c
   branches/ctdb/squeeze-backports/server/ctdb_takeover.c
   branches/ctdb/squeeze-backports/server/ctdb_traverse.c
   branches/ctdb/squeeze-backports/server/ctdb_tunables.c
   branches/ctdb/squeeze-backports/server/ctdb_uptime.c
   branches/ctdb/squeeze-backports/server/ctdb_vacuum.c
   branches/ctdb/squeeze-backports/server/ctdbd.c
   branches/ctdb/squeeze-backports/server/eventscript.c
   branches/ctdb/squeeze-backports/tcp/
   branches/ctdb/squeeze-backports/tcp/ctdb_tcp.h
   branches/ctdb/squeeze-backports/tcp/tcp_connect.c
   branches/ctdb/squeeze-backports/tcp/tcp_init.c
   branches/ctdb/squeeze-backports/tcp/tcp_io.c
   branches/ctdb/squeeze-backports/tests/
   branches/ctdb/squeeze-backports/tests/README
   branches/ctdb/squeeze-backports/tests/TODO
   branches/ctdb/squeeze-backports/tests/complex/
   branches/ctdb/squeeze-backports/tests/complex/01_ctdb_nfs_skip_share_check.sh
   branches/ctdb/squeeze-backports/tests/complex/02_ctdb_samba_skip_share_check.sh
   branches/ctdb/squeeze-backports/tests/complex/31_nfs_tickle.sh
   branches/ctdb/squeeze-backports/tests/complex/32_cifs_tickle.sh
   branches/ctdb/squeeze-backports/tests/complex/33_gratuitous_arp.sh
   branches/ctdb/squeeze-backports/tests/complex/41_failover_ping_discrete.sh
   branches/ctdb/squeeze-backports/tests/complex/42_failover_ssh_hostname.sh
   branches/ctdb/squeeze-backports/tests/complex/43_failover_nfs_basic.sh
   branches/ctdb/squeeze-backports/tests/complex/44_failover_nfs_oneway.sh
   branches/ctdb/squeeze-backports/tests/events.d/
   branches/ctdb/squeeze-backports/tests/events.d/00.test
   branches/ctdb/squeeze-backports/tests/eventscripts/
   branches/ctdb/squeeze-backports/tests/eventscripts/README
   branches/ctdb/squeeze-backports/tests/eventscripts/common.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/
   branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/events.d
   branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/functions
   branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/interface_modify.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/public_addresses
   branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local
   branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local.nfs.monitor.get-limits
   branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/statd-callout
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfs
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfslock
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/samba/
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/samba/smb.conf
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/ctdb
   branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/nfs
   branches/ctdb/squeeze-backports/tests/eventscripts/multievent/
   branches/ctdb/squeeze-backports/tests/eventscripts/multievent/10.interface.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.002.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.003.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.004.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.005.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.006.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/run_tests.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.002.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.002.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.003.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.004.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.005.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.006.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.007.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.008.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.009.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.010.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.011.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.012.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.013.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.002.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.002.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.002.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.003.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/40.vsftpd.monitor.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/41.httpd.monitor.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.050.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.051.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.101.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.102.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.103.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.104.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.105.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.106.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.107.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.108.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.109.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.110.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.111.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.001.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.100.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.101.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.111.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.112.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.121.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.122.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.131.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.132.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.141.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.142.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.151.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.152.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.153.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.161.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.162.sh
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ctdb
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ethtool
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/exportfs
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ip
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/iptables
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/kill
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/killall
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/net
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/netstat
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/nmap
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/pkill
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.lockd
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.mountd
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.rquotad
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.statd
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpcinfo
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/service
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/sleep
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/testparm
   branches/ctdb/squeeze-backports/tests/eventscripts/stubs/wbinfo
   branches/ctdb/squeeze-backports/tests/onnode/
   branches/ctdb/squeeze-backports/tests/onnode/0001.sh
   branches/ctdb/squeeze-backports/tests/onnode/0002.sh
   branches/ctdb/squeeze-backports/tests/onnode/0003.sh
   branches/ctdb/squeeze-backports/tests/onnode/0004.sh
   branches/ctdb/squeeze-backports/tests/onnode/0005.sh
   branches/ctdb/squeeze-backports/tests/onnode/0006.sh
   branches/ctdb/squeeze-backports/tests/onnode/0070.sh
   branches/ctdb/squeeze-backports/tests/onnode/0071.sh
   branches/ctdb/squeeze-backports/tests/onnode/0072.sh
   branches/ctdb/squeeze-backports/tests/onnode/0075.sh
   branches/ctdb/squeeze-backports/tests/onnode/0080.sh
   branches/ctdb/squeeze-backports/tests/onnode/0081.sh
   branches/ctdb/squeeze-backports/tests/onnode/0090.sh
   branches/ctdb/squeeze-backports/tests/onnode/0091.sh
   branches/ctdb/squeeze-backports/tests/onnode/README
   branches/ctdb/squeeze-backports/tests/onnode/common.sh
   branches/ctdb/squeeze-backports/tests/onnode/nodes
   branches/ctdb/squeeze-backports/tests/onnode/run_tests.sh
   branches/ctdb/squeeze-backports/tests/onnode/stubs/
   branches/ctdb/squeeze-backports/tests/onnode/stubs/ctdb
   branches/ctdb/squeeze-backports/tests/onnode/stubs/onnode-buggy-001
   branches/ctdb/squeeze-backports/tests/onnode/stubs/ssh
   branches/ctdb/squeeze-backports/tests/recover.sh
   branches/ctdb/squeeze-backports/tests/run_tests.sh
   branches/ctdb/squeeze-backports/tests/scripts/
   branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_env
   branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_functions.bash
   branches/ctdb/squeeze-backports/tests/scripts/run_tests
   branches/ctdb/squeeze-backports/tests/scripts/test_wrap
   branches/ctdb/squeeze-backports/tests/simple/
   branches/ctdb/squeeze-backports/tests/simple/00_ctdb_init.sh
   branches/ctdb/squeeze-backports/tests/simple/00_ctdb_onnode.sh
   branches/ctdb/squeeze-backports/tests/simple/01_ctdb_version.sh
   branches/ctdb/squeeze-backports/tests/simple/02_ctdb_listvars.sh
   branches/ctdb/squeeze-backports/tests/simple/03_ctdb_getvar.sh
   branches/ctdb/squeeze-backports/tests/simple/04_ctdb_setvar.sh
   branches/ctdb/squeeze-backports/tests/simple/05_ctdb_listnodes.sh
   branches/ctdb/squeeze-backports/tests/simple/06_ctdb_getpid.sh
   branches/ctdb/squeeze-backports/tests/simple/07_ctdb_process_exists.sh
   branches/ctdb/squeeze-backports/tests/simple/08_ctdb_isnotrecmaster.sh
   branches/ctdb/squeeze-backports/tests/simple/09_ctdb_ping.sh
   branches/ctdb/squeeze-backports/tests/simple/11_ctdb_ip.sh
   branches/ctdb/squeeze-backports/tests/simple/12_ctdb_getdebug.sh
   branches/ctdb/squeeze-backports/tests/simple/13_ctdb_setdebug.sh
   branches/ctdb/squeeze-backports/tests/simple/14_ctdb_statistics.sh
   branches/ctdb/squeeze-backports/tests/simple/15_ctdb_statisticsreset.sh
   branches/ctdb/squeeze-backports/tests/simple/16_ctdb_config_add_ip.sh
   branches/ctdb/squeeze-backports/tests/simple/17_ctdb_config_delete_ip.sh
   branches/ctdb/squeeze-backports/tests/simple/23_ctdb_moveip.sh
   branches/ctdb/squeeze-backports/tests/simple/24_ctdb_getdbmap.sh
   branches/ctdb/squeeze-backports/tests/simple/25_dumpmemory.sh
   branches/ctdb/squeeze-backports/tests/simple/26_ctdb_config_check_error_on_unreachable_ctdb.sh
   branches/ctdb/squeeze-backports/tests/simple/31_ctdb_disable.sh
   branches/ctdb/squeeze-backports/tests/simple/32_ctdb_enable.sh
   branches/ctdb/squeeze-backports/tests/simple/41_ctdb_stop.sh
   branches/ctdb/squeeze-backports/tests/simple/42_ctdb_continue.sh
   branches/ctdb/squeeze-backports/tests/simple/43_stop_recmaster_yield.sh
   branches/ctdb/squeeze-backports/tests/simple/51_ctdb_bench.sh
   branches/ctdb/squeeze-backports/tests/simple/52_ctdb_fetch.sh
   branches/ctdb/squeeze-backports/tests/simple/53_ctdb_transaction.sh
   branches/ctdb/squeeze-backports/tests/simple/54_ctdb_transaction_recovery.sh
   branches/ctdb/squeeze-backports/tests/src/
   branches/ctdb/squeeze-backports/tests/src/ctdb_bench.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_fetch.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_lock_once.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_one.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_readonly_loop.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_readonly_once.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_persistent.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_randrec.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_store.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_takeover_tests.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_trackingdb_test.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_transaction.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_traverse.c
   branches/ctdb/squeeze-backports/tests/src/ctdb_update_record.c
   branches/ctdb/squeeze-backports/tests/src/rb_perftest.c
   branches/ctdb/squeeze-backports/tests/src/rb_test.c
   branches/ctdb/squeeze-backports/tests/takeover/
   branches/ctdb/squeeze-backports/tests/takeover/README
   branches/ctdb/squeeze-backports/tests/takeover/common.sh
   branches/ctdb/squeeze-backports/tests/takeover/ctdb_takeover.py
   branches/ctdb/squeeze-backports/tests/takeover/ip_groups1.py
   branches/ctdb/squeeze-backports/tests/takeover/ip_groups2.py
   branches/ctdb/squeeze-backports/tests/takeover/ip_groups3.py
   branches/ctdb/squeeze-backports/tests/takeover/ip_groups4.py
   branches/ctdb/squeeze-backports/tests/takeover/ip_groups5.py
   branches/ctdb/squeeze-backports/tests/takeover/mgmt_simple.py
   branches/ctdb/squeeze-backports/tests/takeover/node_group.py
   branches/ctdb/squeeze-backports/tests/takeover/node_group_extra.py
   branches/ctdb/squeeze-backports/tests/takeover/node_group_simple.py
   branches/ctdb/squeeze-backports/tests/takeover/nondet_path_01.py
   branches/ctdb/squeeze-backports/tests/takeover/run_tests.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.001.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.002.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.003.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.004.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.005.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.006.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.007.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.008.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.009.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.001.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.002.sh
   branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.003.sh
   branches/ctdb/squeeze-backports/tests/test_check_tcp_ports.sh
   branches/ctdb/squeeze-backports/tools/
   branches/ctdb/squeeze-backports/tools/ctdb.c
   branches/ctdb/squeeze-backports/tools/ctdb_diagnostics
   branches/ctdb/squeeze-backports/tools/ctdb_vacuum.c
   branches/ctdb/squeeze-backports/tools/ltdbtool.c
   branches/ctdb/squeeze-backports/tools/onnode
   branches/ctdb/squeeze-backports/utils/
   branches/ctdb/squeeze-backports/utils/ping_pong/
   branches/ctdb/squeeze-backports/utils/ping_pong/ping_pong.c
   branches/ctdb/squeeze-backports/utils/pmda/
   branches/ctdb/squeeze-backports/utils/pmda/Install
   branches/ctdb/squeeze-backports/utils/pmda/README
   branches/ctdb/squeeze-backports/utils/pmda/Remove
   branches/ctdb/squeeze-backports/utils/pmda/domain.h
   branches/ctdb/squeeze-backports/utils/pmda/help
   branches/ctdb/squeeze-backports/utils/pmda/pmda_ctdb.c
   branches/ctdb/squeeze-backports/utils/pmda/pmns
   branches/ctdb/squeeze-backports/utils/pmda/root
   branches/ctdb/squeeze-backports/utils/scsi_io/
   branches/ctdb/squeeze-backports/utils/scsi_io/scsi_io.c
   branches/ctdb/squeeze-backports/utils/smnotify/
   branches/ctdb/squeeze-backports/utils/smnotify/smnotify.c
   branches/ctdb/squeeze-backports/utils/smnotify/smnotify.x
   branches/ctdb/squeeze-backports/web/
   branches/ctdb/squeeze-backports/web/bar1.jpg
   branches/ctdb/squeeze-backports/web/building.html
   branches/ctdb/squeeze-backports/web/clamd.html
   branches/ctdb/squeeze-backports/web/configuring.html
   branches/ctdb/squeeze-backports/web/ctdblogo.png
   branches/ctdb/squeeze-backports/web/documentation.html
   branches/ctdb/squeeze-backports/web/download.html
   branches/ctdb/squeeze-backports/web/footer.html
   branches/ctdb/squeeze-backports/web/ftp.html
   branches/ctdb/squeeze-backports/web/header.html
   branches/ctdb/squeeze-backports/web/index.html
   branches/ctdb/squeeze-backports/web/iscsi.html
   branches/ctdb/squeeze-backports/web/nfs.html
   branches/ctdb/squeeze-backports/web/prerequisites.html
   branches/ctdb/squeeze-backports/web/samba.html
   branches/ctdb/squeeze-backports/web/testing.html
Log:
Add upstream source code

Added: branches/ctdb/squeeze-backports/COPYING
===================================================================
--- branches/ctdb/squeeze-backports/COPYING	                        (rev 0)
+++ branches/ctdb/squeeze-backports/COPYING	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

Added: branches/ctdb/squeeze-backports/Makefile.in
===================================================================
--- branches/ctdb/squeeze-backports/Makefile.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/Makefile.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,320 @@
+#!gmake
+
+
+CC = @CC@
+AR = ar
+ARFLAGS = cru
+RANLIB = ranlib
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
+includedir = @includedir@
+docdir = @docdir@
+libdir = @libdir@
+bindir = @bindir@
+sbindir = @sbindir@
+mandir = @mandir@
+localstatedir = @localstatedir@
+logdir = @LOGDIR@
+VPATH = @srcdir@:@tdbdir@:@tallocdir@:@libreplacedir@:@poptdir@:@teventdir@:
+srcdir = @srcdir@
+etcdir = @sysconfdir@
+builddir = @builddir@
+DESTDIR = /
+EXTRA_OBJ=@EXTRA_OBJ@
+XSLTPROC = /usr/bin/xsltproc
+INSTALLCMD = @INSTALL@
+
+POPT_LIBS = @POPT_LIBS@
+POPT_CFLAGS = @POPT_CFLAGS@
+POPT_OBJ = @POPT_OBJ@
+
+PMDA_LIBS = -lpcp -lpcp_pmda
+PMDA_INSTALL = @CTDB_PMDA_INSTALL@
+PMDA_DEST_DIR = /var/lib/pcp/pmdas
+
+CFLAGS=-g -I$(srcdir)/include -Iinclude -Ilib -Ilib/util -I$(srcdir) \
+       -I at tallocdir@ -I at tdbdir@/include -I at libreplacedir@ \
+	-DVARDIR=\"$(localstatedir)\" -DETCDIR=\"$(etcdir)\" \
+	-DLOGDIR=\"$(logdir)\" \
+	-DUSE_MMAP=1 @CFLAGS@ $(POPT_CFLAGS)
+
+LIB_FLAGS=@LDFLAGS@ -Llib @LIBS@ $(POPT_LIBS) @INFINIBAND_LIBS@ @CTDB_PCAP_LDFLAGS@
+
+UTIL_OBJ = lib/util/idtree.o lib/util/db_wrap.o lib/util/strlist.o lib/util/util.o \
+	lib/util/util_time.o lib/util/util_file.o lib/util/fault.o lib/util/substitute.o \
+	lib/util/signal.o
+
+CTDB_COMMON_OBJ =  common/ctdb_io.o common/ctdb_util.o \
+	common/ctdb_ltdb.o common/ctdb_message.o common/cmdline.o  \
+	lib/util/debug.o common/rb_tree.o @CTDB_SYSTEM_OBJ@ common/system_common.o \
+	common/ctdb_logging.c
+
+CTDB_LIB_OBJ = libctdb/ctdb.o libctdb/io_elem.o libctdb/local_tdb.o \
+	libctdb/messages.o libctdb/sync.o libctdb/control.o \
+	libctdb/logging.o
+
+CTDB_TCP_OBJ = tcp/tcp_connect.o tcp/tcp_io.o tcp/tcp_init.o
+
+CTDB_CLIENT_OBJ = client/ctdb_client.o \
+	$(CTDB_COMMON_OBJ) $(POPT_OBJ) $(UTIL_OBJ) @TALLOC_OBJ@ @TDB_OBJ@ \
+	@LIBREPLACEOBJ@ $(EXTRA_OBJ) @TEVENT_OBJ@
+
+CTDB_SERVER_OBJ = server/ctdbd.o server/ctdb_daemon.o server/ctdb_lockwait.o \
+	server/ctdb_recoverd.o server/ctdb_recover.o server/ctdb_freeze.o \
+	server/ctdb_tunables.o server/ctdb_monitor.o server/ctdb_server.o \
+	server/ctdb_control.o server/ctdb_call.o server/ctdb_ltdb_server.o \
+	server/ctdb_traverse.o server/eventscript.o server/ctdb_takeover.o \
+	server/ctdb_serverids.o server/ctdb_persistent.o \
+	server/ctdb_keepalive.o server/ctdb_logging.o server/ctdb_uptime.o \
+	server/ctdb_vacuum.o server/ctdb_banning.o server/ctdb_statistics.o \
+	$(CTDB_CLIENT_OBJ) $(CTDB_TCP_OBJ) @INFINIBAND_WRAPPER_OBJ@
+
+TEST_BINS=tests/bin/ctdb_bench tests/bin/ctdb_fetch tests/bin/ctdb_fetch_one \
+	tests/bin/ctdb_fetch_lock_once \
+	tests/bin/ctdb_fetch_readonly_once tests/bin/ctdb_fetch_readonly_loop \
+	tests/bin/ctdb_store tests/bin/ctdb_trackingdb_test \
+	tests/bin/ctdb_randrec tests/bin/ctdb_persistent \
+	tests/bin/ctdb_traverse tests/bin/rb_test tests/bin/ctdb_transaction \
+	tests/bin/ctdb_takeover_tests tests/bin/ctdb_update_record \
+	@INFINIBAND_BINS@
+
+BINS = bin/ctdb @CTDB_SCSI_IO@ bin/smnotify bin/ping_pong bin/ltdbtool @CTDB_PMDA@
+
+SBINS = bin/ctdbd
+
+DIRS = lib bin tests/bin
+
+.SUFFIXES: .c .o .h .1 .1.xml .1.html
+
+all: showflags dirs doc $(CTDB_SERVER_OBJ) $(CTDB_CLIENT_OBJ) $(CTDB_LIB_OBJ) $(BINS) $(SBINS) $(TEST_BINS)
+
+showflags:
+	@echo 'ctdb will be compiled with flags:'
+	@echo '  CFLAGS = $(CFLAGS)'
+	@echo '  LIBS = $(LIBS)'
+
+showlayout::
+	@echo "ctdb will be installed into:"
+	@echo "  prefix:      $(prefix)"
+	@echo "  bindir:      $(bindir)"
+	@echo "  sbindir:     $(sbindir)"
+	@echo "  libdir:      $(libdir)"
+	@echo "  vardir:      $(localstatedir)"
+	@echo "  logdir:      $(logdir)"
+	@echo "  mandir:      $(mandir)"
+	@echo "  etcdir:      $(etcdir)"
+
+.c.o:
+	@echo Compiling $*.c
+	@mkdir -p `dirname $@`
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+dirs:
+	@mkdir -p $(DIRS)
+
+bin/ctdbd: $(CTDB_SERVER_OBJ)
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ $(CTDB_SERVER_OBJ) $(LIB_FLAGS)
+
+libctdb/libctdb.a: $(CTDB_LIB_OBJ)
+	@echo Linking $@
+	-rm -f libctdb.a
+	@$(AR) $(ARFLAGS) libctdb/libctdb.a $(CTDB_LIB_OBJ)
+	@$(RANLIB) libctdb/libctdb.a
+
+bin/scsi_io: $(CTDB_CLIENT_OBJ) utils/scsi_io/scsi_io.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ utils/scsi_io/scsi_io.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+bin/ctdb: $(CTDB_CLIENT_OBJ) tools/ctdb.o tools/ctdb_vacuum.o libctdb/libctdb.a
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tools/ctdb.o tools/ctdb_vacuum.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS) libctdb/libctdb.a
+
+bin/ltdbtool: tools/ltdbtool.o @TDB_OBJ@
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ $+
+
+bin/smnotify: utils/smnotify/gen_xdr.o utils/smnotify/gen_smnotify.o utils/smnotify/smnotify.o $(POPT_OBJ)
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ utils/smnotify/smnotify.o utils/smnotify/gen_xdr.o utils/smnotify/gen_smnotify.o $(POPT_OBJ) $(LIB_FLAGS)
+
+utils/smnotify/smnotify.o: utils/smnotify/smnotify.c utils/smnotify/smnotify.h
+
+utils/smnotify/smnotify.h:  utils/smnotify/smnotify.x
+	@echo Generating $@
+	rpcgen -h utils/smnotify/smnotify.x > utils/smnotify/smnotify.h
+
+utils/smnotify/gen_xdr.c: utils/smnotify/smnotify.x utils/smnotify/smnotify.h
+	@echo Generating $@
+	rpcgen -c utils/smnotify/smnotify.x > utils/smnotify/gen_xdr.c 
+
+utils/smnotify/gen_smnotify.c: utils/smnotify/smnotify.x utils/smnotify/smnotify.h
+	@echo Generating $@
+	rpcgen -l utils/smnotify/smnotify.x > utils/smnotify/gen_smnotify.c 
+
+bin/ping_pong: utils/ping_pong/ping_pong.o
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ utils/ping_pong/ping_pong.o
+
+bin/pmdactdb: $(CTDB_CLIENT_OBJ) utils/pmda/pmda_ctdb.o
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ utils/pmda/pmda_ctdb.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS) $(PMDA_LIBS)
+
+tests/bin/rb_test: $(CTDB_CLIENT_OBJ) tests/src/rb_test.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/rb_test.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_bench: $(CTDB_CLIENT_OBJ) tests/src/ctdb_bench.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_bench.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_fetch: $(CTDB_CLIENT_OBJ) tests/src/ctdb_fetch.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_fetch.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_fetch_one: $(CTDB_CLIENT_OBJ) tests/src/ctdb_fetch_one.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_fetch_one.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_fetch_lock_once: libctdb/libctdb.a tests/src/ctdb_fetch_lock_once.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_fetch_lock_once.o @TDB_OBJ@ @POPT_OBJ@ libctdb/libctdb.a $(LIB_FLAGS)
+
+tests/bin/ctdb_fetch_readonly_once: libctdb/libctdb.a tests/src/ctdb_fetch_readonly_once.o
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_fetch_readonly_once.o @TDB_OBJ@ @POPT_OBJ@ libctdb/libctdb.a $(LIB_FLAGS)
+
+tests/bin/ctdb_fetch_readonly_loop: $(CTDB_CLIENT_OBJ) tests/src/ctdb_fetch_readonly_loop.o
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_fetch_readonly_loop.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_trackingdb_test: $(CTDB_CLIENT_OBJ) tests/src/ctdb_trackingdb_test.o
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_trackingdb_test.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_update_record: $(CTDB_CLIENT_OBJ) tests/src/ctdb_update_record.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_update_record.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_store: $(CTDB_CLIENT_OBJ) tests/src/ctdb_store.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_store.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_traverse: $(CTDB_CLIENT_OBJ) tests/src/ctdb_traverse.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_traverse.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_randrec: $(CTDB_CLIENT_OBJ) tests/src/ctdb_randrec.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_randrec.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_persistent: $(CTDB_CLIENT_OBJ) tests/src/ctdb_persistent.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_persistent.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+tests/bin/ctdb_transaction: $(CTDB_CLIENT_OBJ) tests/src/ctdb_transaction.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_transaction.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+CTDB_TAKEOVER_OBJ = $(CTDB_SERVER_OBJ:server/ctdbd.o=)
+
+tests/bin/ctdb_takeover_tests: $(CTDB_TAKEOVER_OBJ) tests/src/ctdb_takeover_tests.o
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/src/ctdb_takeover_tests.o $(CTDB_TAKEOVER_OBJ) $(LIB_FLAGS)
+
+tests/bin/ibwrapper_test: $(CTDB_CLIENT_OBJ) ib/ibwrapper_test.o
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ ib/ibwrapper_test.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
+.1.xml.1:
+	-test -z "$(XSLTPROC)" || $(XSLTPROC) -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+
+.1.xml.1.html:
+	-test -z "$(XSLTPROC)" || $(XSLTPROC) -o $@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl $<
+
+doc: doc/ctdb.1 doc/ctdb.1.html \
+	doc/ctdbd.1 doc/ctdbd.1.html \
+	doc/onnode.1 doc/onnode.1.html \
+	doc/ltdbtool.1 doc/ltdbtool.1.html \
+	doc/ping_pong.1 doc/ping_pong.1.html
+
+clean:
+	rm -f *.o */*.o */*.a */*/*.o */*~
+	rm -f utils/smnotify/gen_xdr.c
+	rm -f $(BINS) $(SBINS) $(TEST_BINS)
+
+distclean: clean
+	rm -f *~ */*~
+	rm -rf bin
+	rm -f config.log config.status config.cache config.h
+	rm -f Makefile
+
+install: all $(PMDA_INSTALL)
+	mkdir -p $(DESTDIR)$(libdir)/pkgconfig
+	mkdir -p $(DESTDIR)$(bindir)
+	mkdir -p $(DESTDIR)$(sbindir)
+	mkdir -p $(DESTDIR)$(includedir)
+	mkdir -p $(DESTDIR)$(etcdir)/ctdb
+	mkdir -p $(DESTDIR)$(etcdir)/ctdb/events.d
+	mkdir -p $(DESTDIR)$(docdir)/ctdb
+	${INSTALLCMD} -m 644 ctdb.pc $(DESTDIR)$(libdir)/pkgconfig
+	${INSTALLCMD} -m 755 bin/ctdb $(DESTDIR)$(bindir)
+	${INSTALLCMD} -m 755 bin/ctdbd $(DESTDIR)$(sbindir)
+	${INSTALLCMD} -m 755 bin/smnotify $(DESTDIR)$(bindir)
+	$(INSTALLCMD) -m 755 bin/ping_pong $(DESTDIR)$(bindir)
+	$(INSTALLCMD) -m 755 bin/ltdbtool $(DESTDIR)$(bindir)
+	$(INSTALLCMD) -m 755 libctdb/libctdb.a $(DESTDIR)$(libdir)
+	${INSTALLCMD} -m 644 include/ctdb.h $(DESTDIR)$(includedir)
+	${INSTALLCMD} -m 644 include/ctdb_client.h $(DESTDIR)$(includedir)
+	${INSTALLCMD} -m 644 include/ctdb_protocol.h $(DESTDIR)$(includedir)
+	${INSTALLCMD} -m 644 include/ctdb_private.h $(DESTDIR)$(includedir) # for samba3
+	${INSTALLCMD} -m 644 include/ctdb_typesafe_cb.h $(DESTDIR)$(includedir)
+	${INSTALLCMD} -m 644 config/functions $(DESTDIR)$(etcdir)/ctdb
+	${INSTALLCMD} -m 755 config/statd-callout $(DESTDIR)$(etcdir)/ctdb
+	${INSTALLCMD} -m 755 config/interface_modify.sh $(DESTDIR)$(etcdir)/ctdb
+	${INSTALLCMD} -m 644 config/events.d/README $(DESTDIR)$(docdir)/ctdb/README.eventscripts
+	${INSTALLCMD} -m 644 doc/recovery-process.txt $(DESTDIR)$(docdir)/ctdb/recovery-process.txt
+	${INSTALLCMD} -m 755 config/events.d/00.ctdb $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/01.reclock $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/10.interface $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/11.natgw $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/11.routing $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/13.per_ip_routing $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 644 config/events.d/20.multipathd $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 644 config/events.d/31.clamd $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/40.vsftpd $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 644 config/events.d/40.fs_use $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/41.httpd $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/50.samba $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/60.nfs $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 644 config/events.d/60.ganesha $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/62.cnfs $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/70.iscsi $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 config/events.d/91.lvs $(DESTDIR)$(etcdir)/ctdb/events.d
+	${INSTALLCMD} -m 755 tools/ctdb_diagnostics $(DESTDIR)$(bindir)
+	${INSTALLCMD} -m 755 tools/onnode $(DESTDIR)$(bindir)
+	if [ -f doc/ctdb.1 ];then ${INSTALLCMD} -d $(DESTDIR)$(mandir)/man1; fi
+	if [ -f doc/ctdb.1 ];then ${INSTALLCMD} -m 644 doc/ctdb.1 $(DESTDIR)$(mandir)/man1; fi
+	if [ -f doc/ctdbd.1 ];then ${INSTALLCMD} -m 644 doc/ctdbd.1 $(DESTDIR)$(mandir)/man1; fi
+	if [ -f doc/onnode.1 ];then ${INSTALLCMD} -m 644 doc/onnode.1 $(DESTDIR)$(mandir)/man1; fi
+	if [ -f doc/ltdbtool.1 ]; then ${INSTALLCMD} -m 644 doc/ltdbtool.1 $(DESTDIR)$(mandir)/man1; fi
+	if [ -f doc/ping_pong.1 ];then ${INSTALLCMD} -m 644 doc/ping_pong.1 $(DESTDIR)$(mandir)/man1; fi
+	if [ ! -f $(DESTDIR)$(etcdir)/ctdb/notify.sh ];then ${INSTALLCMD} -m 755 config/notify.sh $(DESTDIR)$(etcdir)/ctdb; fi
+	if [ ! -f $(DESTDIR)$(etcdir)/ctdb/ctdb-crash-cleanup.sh ];then ${INSTALLCMD} -m 755 config/ctdb-crash-cleanup.sh $(DESTDIR)$(etcdir)/ctdb; fi
+
+install_pmda:
+	$(INSTALLCMD) -m 755 -d $(PMDA_DEST_DIR)
+	$(INSTALLCMD) -m 755 pmda/Install pmda/Remove $(PMDA_DEST_DIR)
+	$(INSTALLCMD) -m 644 pmda/pmns pmda/domain.h pmda/help pmda/README $(PMDA_DEST_DIR)
+	$(INSTALLCMD) -m 755 bin/pmdactdb $(PMDA_DEST_DIR)
+
+test: all
+	tests/run_tests.sh
+
+valgrindtest: all
+	VALGRIND="valgrind -q --trace-children=yes" tests/run_tests.sh
+
+
+realdistclean: distclean
+	rm -f configure config.h.in ctdb.pc


Property changes on: branches/ctdb/squeeze-backports/Makefile.in
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/README.Coding
===================================================================
--- branches/ctdb/squeeze-backports/README.Coding	                        (rev 0)
+++ branches/ctdb/squeeze-backports/README.Coding	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,236 @@
+##
+## Coding conventions in the Samba 3.0 tree
+##
+
+===========
+Quick Start
+===========
+
+Coding style guidelines are about reducing the number of unnecessary
+reformatting patches and making things easier developers to work together.
+You don't have to like them or even agree with them, but once put in place
+we all have to abide by them (or vote to change them).  However, coding
+style should never outweigh coding itself and so the the guidelines
+described here are hopefully easier enough to follow as they are very
+common and supported by tools and editors.
+
+The basic style, also mentioned in the SAMBA_4_0/prog_guide.txt is the
+Linux kernel coding style (See Documentation/CodingStyle in the kernel
+source tree).  The closely matches what most Samba developers use already
+anyways.
+
+But to save you the trouble of reading the Linux kernel style guide, here
+are the highlights.
+
+
+* Maximum Line Width is 80 Characters
+  The reason is not for people with low-res screens but rather sticking
+  to 80 columns prevents you from easily nesting more than one level of
+  if statements or other code blocks.  Use source/script/count_80_col.pl
+  to check your changes.
+
+* Use 8 Space Tabs to Indent
+  No whitespace filler.
+
+* No Trailing Whitespace
+  Use source/script/strip_trail_ws.pl to clean you files before committing.
+
+* Follow the K&R guidelines.  We won't go throw them all here.  You have
+  a copy of "The C Programming Language" anyways right?  You can also use
+  the format_indent.sh script found in source/script/ if all else fails.
+
+
+
+============
+Editor Hints
+============
+
+Emacs
+-----
+Add the follow to your $HOME/.emacs file:
+
+  (add-hook 'c-mode-hook
+	(lambda ()
+		(c-set-style "linux")
+		(c-toggle-auto-state)))
+
+
+Vi
+--
+(Thanks to SATOH Fumiyasu <fumiyas at osstech.jp> for these hints):
+
+For the basic vi editor including with all variants of *nix, add the 
+following to $HOME/.exrc:
+
+  set tabstop=8
+  set shiftwidth=8
+
+For Vim, the following settings in $HOME/.vimrc will also deal with 
+displaying trailing whitespace:
+
+  if has("syntax") && (&t_Co > 2 || has("gui_running"))
+	syntax on
+	function! ActivateInvisibleCharIndicator()
+		syntax match TrailingSpace "[ \t]\+$" display containedin=ALL
+		highlight TrailingSpace ctermbg=Red
+	endf
+	autocmd BufNewFile,BufRead * call ActivateInvisibleCharIndicator()
+  endif
+  " Show tabs, trailing whitespace, and continued lines visually
+  set list listchars=tab:»·,trail:·,extends:…
+
+  " highlight overly long lines same as TODOs.
+  set textwidth=80
+  autocmd BufNewFile,BufRead *.c,*.h exec 'match Todo /\%>' . &textwidth . 'v.\+/'
+
+
+=========================
+FAQ & Statement Reference
+=========================
+
+Comments
+--------
+
+Comments should always use the standard C syntax.  I.e. /* ... */.  C++ 
+style comments are not currently allowed.
+
+
+Indention & Whitespace & 80 columns
+-----------------------------------
+
+To avoid confusion, indentations are to be 8 character with tab (not 
+8 ' ' characters.  When wrapping parameters for function calls, 
+alignment parameter list with the first parameter on the previous line.
+Use tabs to get as close as possible and then fill in the final 7 
+characters or less with whitespace.  For example,
+
+	var1 = foo(arg1, arg2,
+		   arg3);
+
+The previous example is intended to illustrate alignment of function 
+parameters across lines and not as encourage for gratuitous line 
+splitting.  Never split a line before columns 70 - 79 unless you
+have a really good reason.  Be smart about formatting.
+
+
+If, switch, & Code blocks
+-------------------------
+
+Always follow an 'if' keyword with a space but don't include additional
+spaces following or preceding the parentheses in the conditional.
+This is good:
+
+	if (x == 1)
+
+This is bad:
+
+	if ( x == 1 )
+
+Yes we have a lot of code that uses the second form and we are trying 
+to clean it up without being overly intrusive.
+
+Note that this is a rule about parentheses following keywords and not
+functions.  Don't insert a space between the name and left parentheses when 
+invoking functions.
+
+Braces for code blocks used by for, if, switch, while, do..while, etc...
+should begin on the same line as the statement keyword and end on a line 
+of their own.  NOTE: Functions are different and the beginning left brace
+should begin on a line of its own.
+
+If the beginning statement has to be broken across lines due to length,
+the beginning brace should be on a line of its own.
+
+The exception to the ending rule is when the closing brace is followed by 
+another language keyword such as else or the closing while in a do..while 
+loop.
+
+Good examples:
+
+	if (x == 1) {
+		printf("good\n");
+	}
+
+	for (x=1;
+	     x<10;
+	     x++)
+	{
+		print("%d\n", x);
+	}
+
+	do {
+		printf("also good\n");
+	} while (1);
+
+Bad examples:
+
+	while (1)
+	{
+		print("I'm in a loop!\n"); }
+	
+
+Goto
+----
+
+While many people have been academically taught that goto's are fundamentally
+evil, then can greatly enhance readability and reduce memory leaks when used
+as the single exit point from a function.  But in no Samba world what so ever 
+is a goto outside of a function or block of code a good idea.
+
+Good Examples:
+
+int function foo(int y)
+{
+	int *z = NULL;
+	int ret = 0;
+
+	if ( y < 10 ) {
+		z = malloc(sizeof(int)*y);
+		if (!z) {
+			ret = 1;
+			goto done;
+		}
+	}
+
+	print("Allocated %d elements.\n", y);
+
+ done: 
+	if (z)
+		free(z);
+
+	return ret;
+}
+
+
+Checking Pointer Values
+-----------------------
+
+When invoking functions that return pointer values, either of the following 
+are acceptable.  Use you best judgement and choose the more readable option.
+Remember that many other people will review it.
+
+	if ((x = malloc(sizeof(short)*10)) == NULL ) {
+		fprintf(stderr, "Unable to alloc memory!\n");
+	}
+
+or
+
+	x = malloc(sizeof(short)*10);
+	if (!x) {
+		fprintf(stderr, "Unable to alloc memory!\n");
+	}
+
+
+Primitive Data Types
+--------------------
+
+Samba has large amounts of historical code which makes use of data types 
+commonly supported by the C99 standard. However, at the time such types 
+as boolean and exact width integers did not exist and Samba developers 
+were forced to provide their own.  Now that these types are guaranteed to 
+be available either as part of the compiler C99 support or from lib/replace/, 
+new code should adhere to the following conventions:
+
+  * Booleans are of type "bool" (not BOOL)
+  * Boolean values are "true" and "false" (not True or False)
+  * Exact width integers are of type [u]int[8|16|32|64]_t

Added: branches/ctdb/squeeze-backports/aclocal.m4
===================================================================
--- branches/ctdb/squeeze-backports/aclocal.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/aclocal.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+m4_include(libreplace.m4)

Added: branches/ctdb/squeeze-backports/autogen.sh
===================================================================
--- branches/ctdb/squeeze-backports/autogen.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/autogen.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in ctdb.pc
+
+IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace"
+IPATHS="$IPATHS -I lib/talloc -I talloc -I ../talloc"
+IPATHS="$IPATHS -I lib/tdb -I tdb -I ../tdb"
+IPATHS="$IPATHS -I lib/popt -I popt -I ../popt"
+IPATHS="$IPATHS -I lib/tevent"
+
+autoheader $IPATHS || exit 1
+autoconf $IPATHS || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/autogen.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/client/ctdb_client.c
===================================================================
--- branches/ctdb/squeeze-backports/client/ctdb_client.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/client/ctdb_client.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,4615 @@
+/* 
+   ctdb daemon code
+
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Ronnie Sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "db_wrap.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/util/dlinklist.h"
+#include "lib/tevent/tevent.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#include <stdlib.h>
+#include "../include/ctdb_private.h"
+#include "lib/util/dlinklist.h"
+
+pid_t ctdbd_pid;
+
+/*
+  allocate a packet for use in client<->daemon communication
+ */
+struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb,
+					    TALLOC_CTX *mem_ctx, 
+					    enum ctdb_operation operation, 
+					    size_t length, size_t slength,
+					    const char *type)
+{
+	int size;
+	struct ctdb_req_header *hdr;
+
+	length = MAX(length, slength);
+	size = (length+(CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1);
+
+	hdr = (struct ctdb_req_header *)talloc_size(mem_ctx, size);
+	if (hdr == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to allocate packet for operation %u of length %u\n",
+			 operation, (unsigned)length));
+		return NULL;
+	}
+	talloc_set_name_const(hdr, type);
+	memset(hdr, 0, slength);
+	hdr->length       = length;
+	hdr->operation    = operation;
+	hdr->ctdb_magic   = CTDB_MAGIC;
+	hdr->ctdb_version = CTDB_VERSION;
+	hdr->srcnode      = ctdb->pnn;
+	if (ctdb->vnn_map) {
+		hdr->generation = ctdb->vnn_map->generation;
+	}
+
+	return hdr;
+}
+
+/*
+  local version of ctdb_call
+*/
+int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call,
+		    struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx,
+		    TDB_DATA *data, bool updatetdb)
+{
+	struct ctdb_call_info *c;
+	struct ctdb_registered_call *fn;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	
+	c = talloc(ctdb, struct ctdb_call_info);
+	CTDB_NO_MEMORY(ctdb, c);
+
+	c->key = call->key;
+	c->call_data = &call->call_data;
+	c->record_data.dptr = talloc_memdup(c, data->dptr, data->dsize);
+	c->record_data.dsize = data->dsize;
+	CTDB_NO_MEMORY(ctdb, c->record_data.dptr);
+	c->new_data = NULL;
+	c->reply_data = NULL;
+	c->status = 0;
+	c->header = header;
+
+	for (fn=ctdb_db->calls;fn;fn=fn->next) {
+		if (fn->id == call->call_id) break;
+	}
+	if (fn == NULL) {
+		ctdb_set_error(ctdb, "Unknown call id %u\n", call->call_id);
+		talloc_free(c);
+		return -1;
+	}
+
+	if (fn->fn(c) != 0) {
+		ctdb_set_error(ctdb, "ctdb_call %u failed\n", call->call_id);
+		talloc_free(c);
+		return -1;
+	}
+
+	/* we need to force the record to be written out if this was a remote access */
+	if (c->new_data == NULL) {
+		c->new_data = &c->record_data;
+	}
+
+	if (c->new_data && updatetdb) {
+		/* XXX check that we always have the lock here? */
+		if (ctdb_ltdb_store(ctdb_db, call->key, header, *c->new_data) != 0) {
+			ctdb_set_error(ctdb, "ctdb_call tdb_store failed\n");
+			talloc_free(c);
+			return -1;
+		}
+	}
+
+	if (c->reply_data) {
+		call->reply_data = *c->reply_data;
+
+		talloc_steal(call, call->reply_data.dptr);
+		talloc_set_name_const(call->reply_data.dptr, __location__);
+	} else {
+		call->reply_data.dptr = NULL;
+		call->reply_data.dsize = 0;
+	}
+	call->status = c->status;
+
+	talloc_free(c);
+
+	return 0;
+}
+
+
+/*
+  queue a packet for sending from client to daemon
+*/
+static int ctdb_client_queue_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	return ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)hdr, hdr->length);
+}
+
+
+/*
+  called when a CTDB_REPLY_CALL packet comes in in the client
+
+  This packet comes in response to a CTDB_REQ_CALL request packet. It
+  contains any reply data from the call
+*/
+static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;
+	struct ctdb_client_call_state *state;
+
+	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_call_state);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
+		return;
+	}
+
+	if (hdr->reqid != state->reqid) {
+		/* we found a record  but it was the wrong one */
+		DEBUG(DEBUG_ERR, ("Dropped client call reply with reqid:%u\n",hdr->reqid));
+		return;
+	}
+
+	state->call->reply_data.dptr = c->data;
+	state->call->reply_data.dsize = c->datalen;
+	state->call->status = c->status;
+
+	talloc_steal(state, c);
+
+	state->state = CTDB_CALL_DONE;
+
+	if (state->async.fn) {
+		state->async.fn(state);
+	}
+}
+
+static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+
+/*
+  this is called in the client, when data comes in from the daemon
+ */
+void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args)
+{
+	struct ctdb_context *ctdb = talloc_get_type(args, struct ctdb_context);
+	struct ctdb_req_header *hdr = (struct ctdb_req_header *)data;
+	TALLOC_CTX *tmp_ctx;
+
+	/* place the packet as a child of a tmp_ctx. We then use
+	   talloc_free() below to free it. If any of the calls want
+	   to keep it, then they will steal it somewhere else, and the
+	   talloc_free() will be a no-op */
+	tmp_ctx = talloc_new(ctdb);
+	talloc_steal(tmp_ctx, hdr);
+
+	if (cnt == 0) {
+		DEBUG(DEBUG_INFO,("Daemon has exited - shutting down client\n"));
+		exit(0);
+	}
+
+	if (cnt < sizeof(*hdr)) {
+		DEBUG(DEBUG_CRIT,("Bad packet length %u in client\n", (unsigned)cnt));
+		goto done;
+	}
+	if (cnt != hdr->length) {
+		ctdb_set_error(ctdb, "Bad header length %u expected %u in client\n", 
+			       (unsigned)hdr->length, (unsigned)cnt);
+		goto done;
+	}
+
+	if (hdr->ctdb_magic != CTDB_MAGIC) {
+		ctdb_set_error(ctdb, "Non CTDB packet rejected in client\n");
+		goto done;
+	}
+
+	if (hdr->ctdb_version != CTDB_VERSION) {
+		ctdb_set_error(ctdb, "Bad CTDB version 0x%x rejected in client\n", hdr->ctdb_version);
+		goto done;
+	}
+
+	switch (hdr->operation) {
+	case CTDB_REPLY_CALL:
+		ctdb_client_reply_call(ctdb, hdr);
+		break;
+
+	case CTDB_REQ_MESSAGE:
+		ctdb_request_message(ctdb, hdr);
+		break;
+
+	case CTDB_REPLY_CONTROL:
+		ctdb_client_reply_control(ctdb, hdr);
+		break;
+
+	default:
+		DEBUG(DEBUG_CRIT,("bogus operation code:%u\n",hdr->operation));
+	}
+
+done:
+	talloc_free(tmp_ctx);
+}
+
+/*
+  connect with exponential backoff, thanks Stevens
+*/
+#define CONNECT_MAXSLEEP 64
+static int ctdb_connect_retry(struct ctdb_context *ctdb)
+{
+	struct sockaddr_un addr;
+	int secs;
+	int ret = 0;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path));
+
+	for (secs = 1; secs <= CONNECT_MAXSLEEP; secs *= 2) {
+		ret = connect(ctdb->daemon.sd, (struct sockaddr *)&addr,
+			      sizeof(addr));
+		if ((ret == 0) || (errno != EAGAIN)) {
+			break;
+		}
+
+		if (secs <= (CONNECT_MAXSLEEP / 2)) {
+			DEBUG(DEBUG_ERR,("connect failed: %s, retry in %d second(s)\n",
+					 strerror(errno), secs));
+			sleep(secs);
+		}
+	}
+
+	return ret;
+}
+
+/*
+  connect to a unix domain socket
+*/
+int ctdb_socket_connect(struct ctdb_context *ctdb)
+{
+	ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (ctdb->daemon.sd == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to open client socket. Errno:%s(%d)\n", strerror(errno), errno));
+		return -1;
+	}
+
+	set_nonblocking(ctdb->daemon.sd);
+	set_close_on_exec(ctdb->daemon.sd);
+
+	if (ctdb_connect_retry(ctdb) == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to connect client socket to daemon. Errno:%s(%d)\n", strerror(errno), errno));
+		close(ctdb->daemon.sd);
+		ctdb->daemon.sd = -1;
+		return -1;
+	}
+
+	ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd, 
+					      CTDB_DS_ALIGNMENT, 
+					      ctdb_client_read_cb, ctdb, "to-ctdbd");
+	return 0;
+}
+
+
+struct ctdb_record_handle {
+	struct ctdb_db_context *ctdb_db;
+	TDB_DATA key;
+	TDB_DATA *data;
+	struct ctdb_ltdb_header header;
+};
+
+
+/*
+  make a recv call to the local ctdb daemon - called from client context
+
+  This is called when the program wants to wait for a ctdb_call to complete and get the 
+  results. This call will block unless the call has already completed.
+*/
+int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call)
+{
+	if (state == NULL) {
+		return -1;
+	}
+
+	while (state->state < CTDB_CALL_DONE) {
+		event_loop_once(state->ctdb_db->ctdb->ev);
+	}
+	if (state->state != CTDB_CALL_DONE) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_call_recv failed\n"));
+		talloc_free(state);
+		return -1;
+	}
+
+	if (state->call->reply_data.dsize) {
+		call->reply_data.dptr = talloc_memdup(state->ctdb_db,
+						      state->call->reply_data.dptr,
+						      state->call->reply_data.dsize);
+		call->reply_data.dsize = state->call->reply_data.dsize;
+	} else {
+		call->reply_data.dptr = NULL;
+		call->reply_data.dsize = 0;
+	}
+	call->status = state->call->status;
+	talloc_free(state);
+
+	return call->status;
+}
+
+
+
+
+/*
+  destroy a ctdb_call in client
+*/
+static int ctdb_client_call_destructor(struct ctdb_client_call_state *state)	
+{
+	ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);
+	return 0;
+}
+
+/*
+  construct an event driven local ctdb_call
+
+  this is used so that locally processed ctdb_call requests are processed
+  in an event driven manner
+*/
+static struct ctdb_client_call_state *ctdb_client_call_local_send(struct ctdb_db_context *ctdb_db, 
+								  struct ctdb_call *call,
+								  struct ctdb_ltdb_header *header,
+								  TDB_DATA *data)
+{
+	struct ctdb_client_call_state *state;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	int ret;
+
+	state = talloc_zero(ctdb_db, struct ctdb_client_call_state);
+	CTDB_NO_MEMORY_NULL(ctdb, state);
+	state->call = talloc_zero(state, struct ctdb_call);
+	CTDB_NO_MEMORY_NULL(ctdb, state->call);
+
+	talloc_steal(state, data->dptr);
+
+	state->state   = CTDB_CALL_DONE;
+	*(state->call) = *call;
+	state->ctdb_db = ctdb_db;
+
+	ret = ctdb_call_local(ctdb_db, state->call, header, state, data, true);
+
+	return state;
+}
+
+/*
+  make a ctdb call to the local daemon - async send. Called from client context.
+
+  This constructs a ctdb_call request and queues it for processing. 
+  This call never blocks.
+*/
+struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, 
+					      struct ctdb_call *call)
+{
+	struct ctdb_client_call_state *state;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	struct ctdb_ltdb_header header;
+	TDB_DATA data;
+	int ret;
+	size_t len;
+	struct ctdb_req_call *c;
+
+	/* if the domain socket is not yet open, open it */
+	if (ctdb->daemon.sd==-1) {
+		ctdb_socket_connect(ctdb);
+	}
+
+	ret = ctdb_ltdb_lock(ctdb_db, call->key);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get chainlock\n"));
+		return NULL;
+	}
+
+	ret = ctdb_ltdb_fetch(ctdb_db, call->key, &header, ctdb_db, &data);
+
+	if ((call->flags & CTDB_IMMEDIATE_MIGRATION) && (header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) {
+		ret = -1;
+	}
+
+	if (ret == 0 && header.dmaster == ctdb->pnn) {
+		state = ctdb_client_call_local_send(ctdb_db, call, &header, &data);
+		talloc_free(data.dptr);
+		ctdb_ltdb_unlock(ctdb_db, call->key);
+		return state;
+	}
+
+	ctdb_ltdb_unlock(ctdb_db, call->key);
+	talloc_free(data.dptr);
+
+	state = talloc_zero(ctdb_db, struct ctdb_client_call_state);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to allocate state\n"));
+		return NULL;
+	}
+	state->call = talloc_zero(state, struct ctdb_call);
+	if (state->call == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to allocate state->call\n"));
+		return NULL;
+	}
+
+	len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;
+	c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call);
+	if (c == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to allocate packet\n"));
+		return NULL;
+	}
+
+	state->reqid     = ctdb_reqid_new(ctdb, state);
+	state->ctdb_db = ctdb_db;
+	talloc_set_destructor(state, ctdb_client_call_destructor);
+
+	c->hdr.reqid     = state->reqid;
+	c->flags         = call->flags;
+	c->db_id         = ctdb_db->db_id;
+	c->callid        = call->call_id;
+	c->hopcount      = 0;
+	c->keylen        = call->key.dsize;
+	c->calldatalen   = call->call_data.dsize;
+	memcpy(&c->data[0], call->key.dptr, call->key.dsize);
+	memcpy(&c->data[call->key.dsize], 
+	       call->call_data.dptr, call->call_data.dsize);
+	*(state->call)              = *call;
+	state->call->call_data.dptr = &c->data[call->key.dsize];
+	state->call->key.dptr       = &c->data[0];
+
+	state->state  = CTDB_CALL_WAIT;
+
+
+	ctdb_client_queue_pkt(ctdb, &c->hdr);
+
+	return state;
+}
+
+
+/*
+  full ctdb_call. Equivalent to a ctdb_call_send() followed by a ctdb_call_recv()
+*/
+int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call)
+{
+	struct ctdb_client_call_state *state;
+
+	state = ctdb_call_send(ctdb_db, call);
+	return ctdb_call_recv(state, call);
+}
+
+
+/*
+  tell the daemon what messaging srvid we will use, and register the message
+  handler function in the client
+*/
+int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     ctdb_msg_fn_t handler,
+			     void *private_data)
+				    
+{
+	int res;
+	int32_t status;
+	
+	res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_REGISTER_SRVID, 0, 
+			   tdb_null, NULL, NULL, &status, NULL, NULL);
+	if (res != 0 || status != 0) {
+		DEBUG(DEBUG_ERR,("Failed to register srvid %llu\n", (unsigned long long)srvid));
+		return -1;
+	}
+
+	/* also need to register the handler with our own ctdb structure */
+	return ctdb_register_message_handler(ctdb, ctdb, srvid, handler, private_data);
+}
+
+/*
+  tell the daemon we no longer want a srvid
+*/
+int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data)
+{
+	int res;
+	int32_t status;
+	
+	res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_DEREGISTER_SRVID, 0, 
+			   tdb_null, NULL, NULL, &status, NULL, NULL);
+	if (res != 0 || status != 0) {
+		DEBUG(DEBUG_ERR,("Failed to deregister srvid %llu\n", (unsigned long long)srvid));
+		return -1;
+	}
+
+	/* also need to register the handler with our own ctdb structure */
+	ctdb_deregister_message_handler(ctdb, srvid, private_data);
+	return 0;
+}
+
+
+/*
+  send a message - from client context
+ */
+int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t pnn,
+		      uint64_t srvid, TDB_DATA data)
+{
+	struct ctdb_req_message *r;
+	int len, res;
+
+	len = offsetof(struct ctdb_req_message, data) + data.dsize;
+	r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE, 
+			       len, struct ctdb_req_message);
+	CTDB_NO_MEMORY(ctdb, r);
+
+	r->hdr.destnode  = pnn;
+	r->srvid         = srvid;
+	r->datalen       = data.dsize;
+	memcpy(&r->data[0], data.dptr, data.dsize);
+	
+	res = ctdb_client_queue_pkt(ctdb, &r->hdr);
+	if (res != 0) {
+		return res;
+	}
+
+	talloc_free(r);
+	return 0;
+}
+
+
+/*
+  cancel a ctdb_fetch_lock operation, releasing the lock
+ */
+static int fetch_lock_destructor(struct ctdb_record_handle *h)
+{
+	ctdb_ltdb_unlock(h->ctdb_db, h->key);
+	return 0;
+}
+
+/*
+  force the migration of a record to this node
+ */
+static int ctdb_client_force_migration(struct ctdb_db_context *ctdb_db, TDB_DATA key)
+{
+	struct ctdb_call call;
+	ZERO_STRUCT(call);
+	call.call_id = CTDB_NULL_FUNC;
+	call.key = key;
+	call.flags = CTDB_IMMEDIATE_MIGRATION;
+	return ctdb_call(ctdb_db, &call);
+}
+
+/*
+  try to fetch a readonly copy of a record
+ */
+static int
+ctdb_client_fetch_readonly(struct ctdb_db_context *ctdb_db, TDB_DATA key, TALLOC_CTX *mem_ctx, struct ctdb_ltdb_header **hdr, TDB_DATA *data)
+{
+	int ret;
+
+	struct ctdb_call call;
+	ZERO_STRUCT(call);
+
+	call.call_id = CTDB_FETCH_WITH_HEADER_FUNC;
+	call.call_data.dptr = NULL;
+	call.call_data.dsize = 0;
+	call.key = key;
+	call.flags = CTDB_WANT_READONLY;
+	ret = ctdb_call(ctdb_db, &call);
+
+	if (ret != 0) {
+		return -1;
+	}
+	if (call.reply_data.dsize < sizeof(struct ctdb_ltdb_header)) {
+		return -1;
+	}
+
+	*hdr = talloc_memdup(mem_ctx, &call.reply_data.dptr[0], sizeof(struct ctdb_ltdb_header));
+	if (*hdr == NULL) {
+		talloc_free(call.reply_data.dptr);
+		return -1;
+	}
+
+	data->dsize = call.reply_data.dsize - sizeof(struct ctdb_ltdb_header);
+	data->dptr  = talloc_memdup(mem_ctx, &call.reply_data.dptr[sizeof(struct ctdb_ltdb_header)], data->dsize);
+	if (data->dptr == NULL) {
+		talloc_free(call.reply_data.dptr);
+		talloc_free(hdr);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  get a lock on a record, and return the records data. Blocks until it gets the lock
+ */
+struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, 
+					   TDB_DATA key, TDB_DATA *data)
+{
+	int ret;
+	struct ctdb_record_handle *h;
+
+	/*
+	  procedure is as follows:
+
+	  1) get the chain lock. 
+	  2) check if we are dmaster
+	  3) if we are the dmaster then return handle 
+	  4) if not dmaster then ask ctdb daemon to make us dmaster, and wait for
+	     reply from ctdbd
+	  5) when we get the reply, goto (1)
+	 */
+
+	h = talloc_zero(mem_ctx, struct ctdb_record_handle);
+	if (h == NULL) {
+		return NULL;
+	}
+
+	h->ctdb_db = ctdb_db;
+	h->key     = key;
+	h->key.dptr = talloc_memdup(h, key.dptr, key.dsize);
+	if (h->key.dptr == NULL) {
+		talloc_free(h);
+		return NULL;
+	}
+	h->data    = data;
+
+	DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: key=%*.*s\n", (int)key.dsize, (int)key.dsize, 
+		 (const char *)key.dptr));
+
+again:
+	/* step 1 - get the chain lock */
+	ret = ctdb_ltdb_lock(ctdb_db, key);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to lock ltdb record\n"));
+		talloc_free(h);
+		return NULL;
+	}
+
+	DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: got chain lock\n"));
+
+	talloc_set_destructor(h, fetch_lock_destructor);
+
+	ret = ctdb_ltdb_fetch(ctdb_db, key, &h->header, h, data);
+
+	/* when torturing, ensure we test the remote path */
+	if ((ctdb_db->ctdb->flags & CTDB_FLAG_TORTURE) &&
+	    random() % 5 == 0) {
+		h->header.dmaster = (uint32_t)-1;
+	}
+
+
+	DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: done local fetch\n"));
+
+	if (ret != 0 || h->header.dmaster != ctdb_db->ctdb->pnn) {
+		ctdb_ltdb_unlock(ctdb_db, key);
+		ret = ctdb_client_force_migration(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: force_migration failed\n"));
+			talloc_free(h);
+			return NULL;
+		}
+		goto again;
+	}
+
+	DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: we are dmaster - done\n"));
+	return h;
+}
+
+/*
+  get a readonly lock on a record, and return the records data. Blocks until it gets the lock
+ */
+struct ctdb_record_handle *
+ctdb_fetch_readonly_lock(
+	struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, 
+	TDB_DATA key, TDB_DATA *data,
+	int read_only)
+{
+	int ret;
+	struct ctdb_record_handle *h;
+	struct ctdb_ltdb_header *roheader = NULL;
+
+	h = talloc_zero(mem_ctx, struct ctdb_record_handle);
+	if (h == NULL) {
+		return NULL;
+	}
+
+	h->ctdb_db = ctdb_db;
+	h->key     = key;
+	h->key.dptr = talloc_memdup(h, key.dptr, key.dsize);
+	if (h->key.dptr == NULL) {
+		talloc_free(h);
+		return NULL;
+	}
+	h->data    = data;
+
+	data->dptr = NULL;
+	data->dsize = 0;
+
+
+again:
+	talloc_free(roheader);
+	roheader = NULL;
+
+	talloc_free(data->dptr);
+	data->dptr = NULL;
+	data->dsize = 0;
+
+	/* Lock the record/chain */
+	ret = ctdb_ltdb_lock(ctdb_db, key);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to lock ltdb record\n"));
+		talloc_free(h);
+		return NULL;
+	}
+
+	talloc_set_destructor(h, fetch_lock_destructor);
+
+	/* Check if record exists yet in the TDB */
+	ret = ctdb_ltdb_fetch_with_header(ctdb_db, key, &h->header, h, data);
+	if (ret != 0) {
+		ctdb_ltdb_unlock(ctdb_db, key);
+		ret = ctdb_client_force_migration(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n"));
+			talloc_free(h);
+			return NULL;
+		}
+		goto again;
+	}
+
+	/* if this is a request for read/write and we have delegations
+	   we have to revoke all delegations first
+	*/
+	if ((read_only == 0) 
+	&&  (h->header.dmaster == ctdb_db->ctdb->pnn)
+	&&  (h->header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) {
+		ctdb_ltdb_unlock(ctdb_db, key);
+		ret = ctdb_client_force_migration(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n"));
+			talloc_free(h);
+			return NULL;
+		}
+		goto again;
+	}
+
+	/* if we are dmaster, just return the handle */
+	if (h->header.dmaster == ctdb_db->ctdb->pnn) {
+		return h;
+	}
+
+	if (read_only != 0) {
+		TDB_DATA rodata = {NULL, 0};
+
+		if ((h->header.flags & CTDB_REC_RO_HAVE_READONLY)
+		||  (h->header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) {
+			return h;
+		}
+
+		ctdb_ltdb_unlock(ctdb_db, key);
+		ret = ctdb_client_fetch_readonly(ctdb_db, key, h, &roheader, &rodata);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("ctdb_fetch_readonly_lock:  failed. force migration and try again\n"));
+			ret = ctdb_client_force_migration(ctdb_db, key);
+			if (ret != 0) {
+				DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n"));
+				talloc_free(h);
+				return NULL;
+			}
+
+			goto again;
+		}
+
+		if (!(roheader->flags&CTDB_REC_RO_HAVE_READONLY)) {
+			ret = ctdb_client_force_migration(ctdb_db, key);
+			if (ret != 0) {
+				DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n"));
+				talloc_free(h);
+				return NULL;
+			}
+
+			goto again;
+		}
+
+		ret = ctdb_ltdb_lock(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " failed to lock ltdb record\n"));
+			talloc_free(h);
+			return NULL;
+		}
+
+		ret = ctdb_ltdb_fetch_with_header(ctdb_db, key, &h->header, h, data);
+		if (ret != 0) {
+			ctdb_ltdb_unlock(ctdb_db, key);
+
+			ret = ctdb_client_force_migration(ctdb_db, key);
+			if (ret != 0) {
+				DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n"));
+				talloc_free(h);
+				return NULL;
+			}
+
+			goto again;
+		}
+
+		return h;
+	}
+
+	/* we are not dmaster and this was not a request for a readonly lock
+	 * so unlock the record, migrate it and try again
+	 */
+	ctdb_ltdb_unlock(ctdb_db, key);
+	ret = ctdb_client_force_migration(ctdb_db, key);
+	if (ret != 0) {
+		DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: force_migration failed\n"));
+		talloc_free(h);
+		return NULL;
+	}
+	goto again;
+}
+
+/*
+  store some data to the record that was locked with ctdb_fetch_lock()
+*/
+int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data)
+{
+	if (h->ctdb_db->persistent) {
+		DEBUG(DEBUG_ERR, (__location__ " ctdb_record_store prohibited for persistent dbs\n"));
+		return -1;
+	}
+
+	return ctdb_ltdb_store(h->ctdb_db, h->key, &h->header, data);
+}
+
+/*
+  non-locking fetch of a record
+ */
+int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, 
+	       TDB_DATA key, TDB_DATA *data)
+{
+	struct ctdb_call call;
+	int ret;
+
+	call.call_id = CTDB_FETCH_FUNC;
+	call.call_data.dptr = NULL;
+	call.call_data.dsize = 0;
+	call.key = key;
+
+	ret = ctdb_call(ctdb_db, &call);
+
+	if (ret == 0) {
+		*data = call.reply_data;
+		talloc_steal(mem_ctx, data->dptr);
+	}
+
+	return ret;
+}
+
+
+
+/*
+   called when a control completes or timesout to invoke the callback
+   function the user provided
+*/
+static void invoke_control_callback(struct event_context *ev, struct timed_event *te, 
+	struct timeval t, void *private_data)
+{
+	struct ctdb_client_control_state *state;
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	int ret;
+
+	state = talloc_get_type(private_data, struct ctdb_client_control_state);
+	talloc_steal(tmp_ctx, state);
+
+	ret = ctdb_control_recv(state->ctdb, state, state,
+			NULL, 
+			NULL, 
+			NULL);
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  called when a CTDB_REPLY_CONTROL packet comes in in the client
+
+  This packet comes in response to a CTDB_REQ_CONTROL request packet. It
+  contains any reply data from the control
+*/
+static void ctdb_client_reply_control(struct ctdb_context *ctdb, 
+				      struct ctdb_req_header *hdr)
+{
+	struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_control_state);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
+		return;
+	}
+
+	if (hdr->reqid != state->reqid) {
+		/* we found a record  but it was the wrong one */
+		DEBUG(DEBUG_ERR, ("Dropped orphaned reply control with reqid:%u\n",hdr->reqid));
+		return;
+	}
+
+	state->outdata.dptr = c->data;
+	state->outdata.dsize = c->datalen;
+	state->status = c->status;
+	if (c->errorlen) {
+		state->errormsg = talloc_strndup(state, 
+						 (char *)&c->data[c->datalen], 
+						 c->errorlen);
+	}
+
+	/* state->outdata now uses resources from c so we dont want c
+	   to just dissappear from under us while state is still alive
+	*/
+	talloc_steal(state, c);
+
+	state->state = CTDB_CONTROL_DONE;
+
+	/* if we had a callback registered for this control, pull the response
+	   and call the callback.
+	*/
+	if (state->async.fn) {
+		event_add_timed(ctdb->ev, state, timeval_zero(), invoke_control_callback, state);
+	}
+}
+
+
+/*
+  destroy a ctdb_control in client
+*/
+static int ctdb_control_destructor(struct ctdb_client_control_state *state)	
+{
+	ctdb_reqid_remove(state->ctdb, state->reqid);
+	return 0;
+}
+
+
+/* time out handler for ctdb_control */
+static void control_timeout_func(struct event_context *ev, struct timed_event *te, 
+	struct timeval t, void *private_data)
+{
+	struct ctdb_client_control_state *state = talloc_get_type(private_data, struct ctdb_client_control_state);
+
+	DEBUG(DEBUG_ERR,(__location__ " control timed out. reqid:%u opcode:%u "
+			 "dstnode:%u\n", state->reqid, state->c->opcode,
+			 state->c->hdr.destnode));
+
+	state->state = CTDB_CONTROL_TIMEOUT;
+
+	/* if we had a callback registered for this control, pull the response
+	   and call the callback.
+	*/
+	if (state->async.fn) {
+		event_add_timed(state->ctdb->ev, state, timeval_zero(), invoke_control_callback, state);
+	}
+}
+
+/* async version of send control request */
+struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb, 
+		uint32_t destnode, uint64_t srvid, 
+		uint32_t opcode, uint32_t flags, TDB_DATA data, 
+		TALLOC_CTX *mem_ctx,
+		struct timeval *timeout,
+		char **errormsg)
+{
+	struct ctdb_client_control_state *state;
+	size_t len;
+	struct ctdb_req_control *c;
+	int ret;
+
+	if (errormsg) {
+		*errormsg = NULL;
+	}
+
+	/* if the domain socket is not yet open, open it */
+	if (ctdb->daemon.sd==-1) {
+		ctdb_socket_connect(ctdb);
+	}
+
+	state = talloc_zero(mem_ctx, struct ctdb_client_control_state);
+	CTDB_NO_MEMORY_NULL(ctdb, state);
+
+	state->ctdb       = ctdb;
+	state->reqid      = ctdb_reqid_new(ctdb, state);
+	state->state      = CTDB_CONTROL_WAIT;
+	state->errormsg   = NULL;
+
+	talloc_set_destructor(state, ctdb_control_destructor);
+
+	len = offsetof(struct ctdb_req_control, data) + data.dsize;
+	c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CONTROL, 
+			       len, struct ctdb_req_control);
+	state->c            = c;	
+	CTDB_NO_MEMORY_NULL(ctdb, c);
+	c->hdr.reqid        = state->reqid;
+	c->hdr.destnode     = destnode;
+	c->opcode           = opcode;
+	c->client_id        = 0;
+	c->flags            = flags;
+	c->srvid            = srvid;
+	c->datalen          = data.dsize;
+	if (data.dsize) {
+		memcpy(&c->data[0], data.dptr, data.dsize);
+	}
+
+	/* timeout */
+	if (timeout && !timeval_is_zero(timeout)) {
+		event_add_timed(ctdb->ev, state, *timeout, control_timeout_func, state);
+	}
+
+	ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
+	if (ret != 0) {
+		talloc_free(state);
+		return NULL;
+	}
+
+	if (flags & CTDB_CTRL_FLAG_NOREPLY) {
+		talloc_free(state);
+		return NULL;
+	}
+
+	return state;
+}
+
+
+/* async version of receive control reply */
+int ctdb_control_recv(struct ctdb_context *ctdb, 
+		struct ctdb_client_control_state *state, 
+		TALLOC_CTX *mem_ctx,
+		TDB_DATA *outdata, int32_t *status, char **errormsg)
+{
+	TALLOC_CTX *tmp_ctx;
+
+	if (status != NULL) {
+		*status = -1;
+	}
+	if (errormsg != NULL) {
+		*errormsg = NULL;
+	}
+
+	if (state == NULL) {
+		return -1;
+	}
+
+	/* prevent double free of state */
+	tmp_ctx = talloc_new(ctdb);
+	talloc_steal(tmp_ctx, state);
+
+	/* loop one event at a time until we either timeout or the control
+	   completes.
+	*/
+	while (state->state == CTDB_CONTROL_WAIT) {
+		event_loop_once(ctdb->ev);
+	}
+
+	if (state->state != CTDB_CONTROL_DONE) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control_recv failed\n"));
+		if (state->async.fn) {
+			state->async.fn(state);
+		}
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (state->errormsg) {
+		DEBUG(DEBUG_ERR,("ctdb_control error: '%s'\n", state->errormsg));
+		if (errormsg) {
+			(*errormsg) = talloc_move(mem_ctx, &state->errormsg);
+		}
+		if (state->async.fn) {
+			state->async.fn(state);
+		}
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (outdata) {
+		*outdata = state->outdata;
+		outdata->dptr = talloc_memdup(mem_ctx, outdata->dptr, outdata->dsize);
+	}
+
+	if (status) {
+		*status = state->status;
+	}
+
+	if (state->async.fn) {
+		state->async.fn(state);
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+
+
+/*
+  send a ctdb control message
+  timeout specifies how long we should wait for a reply.
+  if timeout is NULL we wait indefinitely
+ */
+int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, 
+		 uint32_t opcode, uint32_t flags, TDB_DATA data, 
+		 TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
+		 struct timeval *timeout,
+		 char **errormsg)
+{
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_control_send(ctdb, destnode, srvid, opcode, 
+			flags, data, mem_ctx,
+			timeout, errormsg);
+	return ctdb_control_recv(ctdb, state, mem_ctx, outdata, status, 
+			errormsg);
+}
+
+
+
+
+/*
+  a process exists call. Returns 0 if process exists, -1 otherwise
+ */
+int ctdb_ctrl_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t status;
+
+	data.dptr = (uint8_t*)&pid;
+	data.dsize = sizeof(pid);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_PROCESS_EXISTS, 0, data, 
+			   NULL, NULL, &status, NULL, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for process_exists failed\n"));
+		return -1;
+	}
+
+	return status;
+}
+
+/*
+  get remote statistics
+ */
+int ctdb_ctrl_statistics(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_statistics *status)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_STATISTICS, 0, tdb_null, 
+			   ctdb, &data, &res, NULL, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for statistics failed\n"));
+		return -1;
+	}
+
+	if (data.dsize != sizeof(struct ctdb_statistics)) {
+		DEBUG(DEBUG_ERR,(__location__ " Wrong statistics size %u - expected %u\n",
+			 (unsigned)data.dsize, (unsigned)sizeof(struct ctdb_statistics)));
+		      return -1;
+	}
+
+	*status = *(struct ctdb_statistics *)data.dptr;
+	talloc_free(data.dptr);
+			
+	return 0;
+}
+
+/*
+  shutdown a remote ctdb node
+ */
+int ctdb_ctrl_shutdown(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_control_send(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SHUTDOWN, 0, tdb_null, 
+			   NULL, &timeout, NULL);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for shutdown failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  get vnn map from a remote node
+ */
+int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_vnn_map **vnnmap)
+{
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+	struct ctdb_vnn_map_wire *map;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GETVNNMAP, 0, tdb_null, 
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getvnnmap failed\n"));
+		return -1;
+	}
+	
+	map = (struct ctdb_vnn_map_wire *)outdata.dptr;
+	if (outdata.dsize < offsetof(struct ctdb_vnn_map_wire, map) ||
+	    outdata.dsize != map->size*sizeof(uint32_t) + offsetof(struct ctdb_vnn_map_wire, map)) {
+		DEBUG(DEBUG_ERR,("Bad vnn map size received in ctdb_ctrl_getvnnmap\n"));
+		return -1;
+	}
+
+	(*vnnmap) = talloc(mem_ctx, struct ctdb_vnn_map);
+	CTDB_NO_MEMORY(ctdb, *vnnmap);
+	(*vnnmap)->generation = map->generation;
+	(*vnnmap)->size       = map->size;
+	(*vnnmap)->map        = talloc_array(*vnnmap, uint32_t, map->size);
+
+	CTDB_NO_MEMORY(ctdb, (*vnnmap)->map);
+	memcpy((*vnnmap)->map, map->map, sizeof(uint32_t)*map->size);
+	talloc_free(outdata.dptr);
+		    
+	return 0;
+}
+
+
+/*
+  get the recovery mode of a remote node
+ */
+struct ctdb_client_control_state *
+ctdb_ctrl_getrecmode_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode)
+{
+	return ctdb_control_send(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_RECMODE, 0, tdb_null, 
+			   mem_ctx, &timeout, NULL);
+}
+
+int ctdb_ctrl_getrecmode_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmode)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control_recv(ctdb, state, mem_ctx, NULL, &res, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_getrecmode_recv failed\n"));
+		return -1;
+	}
+
+	if (recmode) {
+		*recmode = (uint32_t)res;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmode)
+{
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_ctrl_getrecmode_send(ctdb, mem_ctx, timeout, destnode);
+	return ctdb_ctrl_getrecmode_recv(ctdb, mem_ctx, state, recmode);
+}
+
+
+
+
+/*
+  set the recovery mode of a remote node
+ */
+int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmode)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	data.dsize = sizeof(uint32_t);
+	data.dptr = (unsigned char *)&recmode;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_RECMODE, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setrecmode failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+
+/*
+  get the recovery master of a remote node
+ */
+struct ctdb_client_control_state *
+ctdb_ctrl_getrecmaster_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, 
+			struct timeval timeout, uint32_t destnode)
+{
+	return ctdb_control_send(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_RECMASTER, 0, tdb_null, 
+			   mem_ctx, &timeout, NULL);
+}
+
+int ctdb_ctrl_getrecmaster_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmaster)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control_recv(ctdb, state, mem_ctx, NULL, &res, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_getrecmaster_recv failed\n"));
+		return -1;
+	}
+
+	if (recmaster) {
+		*recmaster = (uint32_t)res;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_getrecmaster(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmaster)
+{
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_ctrl_getrecmaster_send(ctdb, mem_ctx, timeout, destnode);
+	return ctdb_ctrl_getrecmaster_recv(ctdb, mem_ctx, state, recmaster);
+}
+
+
+/*
+  set the recovery master of a remote node
+ */
+int ctdb_ctrl_setrecmaster(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmaster)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	ZERO_STRUCT(data);
+	data.dsize = sizeof(uint32_t);
+	data.dptr = (unsigned char *)&recmaster;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_RECMASTER, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setrecmaster failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+  get a list of databases off a remote node
+ */
+int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, 
+		       TALLOC_CTX *mem_ctx, struct ctdb_dbid_map **dbmap)
+{
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_DBMAP, 0, tdb_null, 
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getdbmap failed ret:%d res:%d\n", ret, res));
+		return -1;
+	}
+
+	*dbmap = (struct ctdb_dbid_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	talloc_free(outdata.dptr);
+		    
+	return 0;
+}
+
+/*
+  get a list of nodes (vnn and flags ) from a remote node
+ */
+int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb, 
+		struct timeval timeout, uint32_t destnode, 
+		TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap)
+{
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_NODEMAP, 0, tdb_null, 
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret == 0 && res == -1 && outdata.dsize == 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodes failed, falling back to ipv4-only control\n"));
+		return ctdb_ctrl_getnodemapv4(ctdb, timeout, destnode, mem_ctx, nodemap);
+	}
+	if (ret != 0 || res != 0 || outdata.dsize == 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodes failed ret:%d res:%d\n", ret, res));
+		return -1;
+	}
+
+	*nodemap = (struct ctdb_node_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	talloc_free(outdata.dptr);
+		    
+	return 0;
+}
+
+/*
+  old style ipv4-only get a list of nodes (vnn and flags ) from a remote node
+ */
+int ctdb_ctrl_getnodemapv4(struct ctdb_context *ctdb, 
+		struct timeval timeout, uint32_t destnode, 
+		TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap)
+{
+	int ret, i, len;
+	TDB_DATA outdata;
+	struct ctdb_node_mapv4 *nodemapv4;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_NODEMAPv4, 0, tdb_null, 
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0 || outdata.dsize == 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodesv4 failed ret:%d res:%d\n", ret, res));
+		return -1;
+	}
+
+	nodemapv4 = (struct ctdb_node_mapv4 *)outdata.dptr;
+
+	len = offsetof(struct ctdb_node_map, nodes) + nodemapv4->num*sizeof(struct ctdb_node_and_flags);
+	(*nodemap) = talloc_zero_size(mem_ctx, len);
+	CTDB_NO_MEMORY(ctdb, (*nodemap));
+
+	(*nodemap)->num = nodemapv4->num;
+	for (i=0; i<nodemapv4->num; i++) {
+		(*nodemap)->nodes[i].pnn     = nodemapv4->nodes[i].pnn;
+		(*nodemap)->nodes[i].flags   = nodemapv4->nodes[i].flags;
+		(*nodemap)->nodes[i].addr.ip = nodemapv4->nodes[i].sin;
+		(*nodemap)->nodes[i].addr.sa.sa_family = AF_INET;
+	}
+		
+	talloc_free(outdata.dptr);
+		    
+	return 0;
+}
+
+/*
+  drop the transport, reload the nodes file and restart the transport
+ */
+int ctdb_ctrl_reload_nodes_file(struct ctdb_context *ctdb, 
+		    struct timeval timeout, uint32_t destnode)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_RELOAD_NODES_FILE, 0, tdb_null, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for reloadnodesfile failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+  set vnn map on a node
+ */
+int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, 
+			TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *vnnmap)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+	struct ctdb_vnn_map_wire *map;
+	size_t len;
+
+	len = offsetof(struct ctdb_vnn_map_wire, map) + sizeof(uint32_t)*vnnmap->size;
+	map = talloc_size(mem_ctx, len);
+	CTDB_NO_MEMORY(ctdb, map);
+
+	map->generation = vnnmap->generation;
+	map->size = vnnmap->size;
+	memcpy(map->map, vnnmap->map, sizeof(uint32_t)*map->size);
+	
+	data.dsize = len;
+	data.dptr  = (uint8_t *)map;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SETVNNMAP, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setvnnmap failed\n"));
+		return -1;
+	}
+
+	talloc_free(map);
+
+	return 0;
+}
+
+
+/*
+  async send for pull database
+ */
+struct ctdb_client_control_state *ctdb_ctrl_pulldb_send(
+	struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
+	uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout)
+{
+	TDB_DATA indata;
+	struct ctdb_control_pulldb *pull;
+	struct ctdb_client_control_state *state;
+
+	pull = talloc(mem_ctx, struct ctdb_control_pulldb);
+	CTDB_NO_MEMORY_NULL(ctdb, pull);
+
+	pull->db_id   = dbid;
+	pull->lmaster = lmaster;
+
+	indata.dsize = sizeof(struct ctdb_control_pulldb);
+	indata.dptr  = (unsigned char *)pull;
+
+	state = ctdb_control_send(ctdb, destnode, 0, 
+				  CTDB_CONTROL_PULL_DB, 0, indata, 
+				  mem_ctx, &timeout, NULL);
+	talloc_free(pull);
+
+	return state;
+}
+
+/*
+  async recv for pull database
+ */
+int ctdb_ctrl_pulldb_recv(
+	struct ctdb_context *ctdb, 
+	TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, 
+	TDB_DATA *outdata)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control_recv(ctdb, state, mem_ctx, outdata, &res, NULL);
+	if ( (ret != 0) || (res != 0) ){
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_pulldb_recv failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  pull all keys and records for a specific database on a node
+ */
+int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode, 
+		uint32_t dbid, uint32_t lmaster, 
+		TALLOC_CTX *mem_ctx, struct timeval timeout,
+		TDB_DATA *outdata)
+{
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_ctrl_pulldb_send(ctdb, destnode, dbid, lmaster, mem_ctx,
+				      timeout);
+	
+	return ctdb_ctrl_pulldb_recv(ctdb, mem_ctx, state, outdata);
+}
+
+
+/*
+  change dmaster for all keys in the database to the new value
+ */
+int ctdb_ctrl_setdmaster(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, 
+			 TALLOC_CTX *mem_ctx, uint32_t dbid, uint32_t dmaster)
+{
+	int ret;
+	TDB_DATA indata;
+	int32_t res;
+
+	indata.dsize = 2*sizeof(uint32_t);
+	indata.dptr = (unsigned char *)talloc_array(mem_ctx, uint32_t, 2);
+
+	((uint32_t *)(&indata.dptr[0]))[0] = dbid;
+	((uint32_t *)(&indata.dptr[0]))[1] = dmaster;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_DMASTER, 0, indata, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setdmaster failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  ping a node, return number of clients connected
+ */
+int ctdb_ctrl_ping(struct ctdb_context *ctdb, uint32_t destnode)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_PING, 0, 
+			   tdb_null, NULL, NULL, &res, NULL, NULL);
+	if (ret != 0) {
+		return -1;
+	}
+	return res;
+}
+
+/*
+  find the real path to a ltdb 
+ */
+int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, 
+		   const char **path)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+
+	data.dptr = (uint8_t *)&dbid;
+	data.dsize = sizeof(dbid);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GETDBPATH, 0, data, 
+			   mem_ctx, &data, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		return -1;
+	}
+
+	(*path) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize);
+	if ((*path) == NULL) {
+		return -1;
+	}
+
+	talloc_free(data.dptr);
+
+	return 0;
+}
+
+/*
+  find the name of a db 
+ */
+int ctdb_ctrl_getdbname(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, 
+		   const char **name)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+
+	data.dptr = (uint8_t *)&dbid;
+	data.dsize = sizeof(dbid);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_DBNAME, 0, data, 
+			   mem_ctx, &data, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		return -1;
+	}
+
+	(*name) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize);
+	if ((*name) == NULL) {
+		return -1;
+	}
+
+	talloc_free(data.dptr);
+
+	return 0;
+}
+
+/*
+  get the health status of a db
+ */
+int ctdb_ctrl_getdbhealth(struct ctdb_context *ctdb,
+			  struct timeval timeout,
+			  uint32_t destnode,
+			  uint32_t dbid, TALLOC_CTX *mem_ctx,
+			  const char **reason)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+
+	data.dptr = (uint8_t *)&dbid;
+	data.dsize = sizeof(dbid);
+
+	ret = ctdb_control(ctdb, destnode, 0,
+			   CTDB_CONTROL_DB_GET_HEALTH, 0, data,
+			   mem_ctx, &data, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		return -1;
+	}
+
+	if (data.dsize == 0) {
+		(*reason) = NULL;
+		return 0;
+	}
+
+	(*reason) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize);
+	if ((*reason) == NULL) {
+		return -1;
+	}
+
+	talloc_free(data.dptr);
+
+	return 0;
+}
+
+/*
+  create a database
+ */
+int ctdb_ctrl_createdb(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, 
+		       TALLOC_CTX *mem_ctx, const char *name, bool persistent)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+
+	data.dptr = discard_const(name);
+	data.dsize = strlen(name)+1;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   persistent?CTDB_CONTROL_DB_ATTACH_PERSISTENT:CTDB_CONTROL_DB_ATTACH, 
+			   0, data, 
+			   mem_ctx, &data, &res, &timeout, NULL);
+
+	if (ret != 0 || res != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  get debug level on a node
+ */
+int ctdb_ctrl_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t *level)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DEBUG, 0, tdb_null, 
+			   ctdb, &data, &res, NULL, NULL);
+	if (ret != 0 || res != 0) {
+		return -1;
+	}
+	if (data.dsize != sizeof(int32_t)) {
+		DEBUG(DEBUG_ERR,("Bad control reply size in ctdb_get_debuglevel (got %u)\n",
+			 (unsigned)data.dsize));
+		return -1;
+	}
+	*level = *(int32_t *)data.dptr;
+	talloc_free(data.dptr);
+	return 0;
+}
+
+/*
+  set debug level on a node
+ */
+int ctdb_ctrl_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t level)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+
+	data.dptr = (uint8_t *)&level;
+	data.dsize = sizeof(level);
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_DEBUG, 0, data, 
+			   NULL, NULL, &res, NULL, NULL);
+	if (ret != 0 || res != 0) {
+		return -1;
+	}
+	return 0;
+}
+
+
+/*
+  get a list of connected nodes
+ */
+uint32_t *ctdb_get_connected_nodes(struct ctdb_context *ctdb, 
+				struct timeval timeout,
+				TALLOC_CTX *mem_ctx,
+				uint32_t *num_nodes)
+{
+	struct ctdb_node_map *map=NULL;
+	int ret, i;
+	uint32_t *nodes;
+
+	*num_nodes = 0;
+
+	ret = ctdb_ctrl_getnodemap(ctdb, timeout, CTDB_CURRENT_NODE, mem_ctx, &map);
+	if (ret != 0) {
+		return NULL;
+	}
+
+	nodes = talloc_array(mem_ctx, uint32_t, map->num);
+	if (nodes == NULL) {
+		return NULL;
+	}
+
+	for (i=0;i<map->num;i++) {
+		if (!(map->nodes[i].flags & NODE_FLAGS_DISCONNECTED)) {
+			nodes[*num_nodes] = map->nodes[i].pnn;
+			(*num_nodes)++;
+		}
+	}
+
+	return nodes;
+}
+
+
+/*
+  reset remote status
+ */
+int ctdb_statistics_reset(struct ctdb_context *ctdb, uint32_t destnode)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_STATISTICS_RESET, 0, tdb_null, 
+			   NULL, NULL, &res, NULL, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for reset statistics failed\n"));
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  this is the dummy null procedure that all databases support
+*/
+static int ctdb_null_func(struct ctdb_call_info *call)
+{
+	return 0;
+}
+
+/*
+  this is a plain fetch procedure that all databases support
+*/
+static int ctdb_fetch_func(struct ctdb_call_info *call)
+{
+	call->reply_data = &call->record_data;
+	return 0;
+}
+
+/*
+  this is a plain fetch procedure that all databases support
+  this returns the full record including the ltdb header
+*/
+static int ctdb_fetch_with_header_func(struct ctdb_call_info *call)
+{
+	call->reply_data = talloc(call, TDB_DATA);
+	if (call->reply_data == NULL) {
+		return -1;
+	}
+	call->reply_data->dsize = sizeof(struct ctdb_ltdb_header) + call->record_data.dsize;
+	call->reply_data->dptr  = talloc_size(call->reply_data, call->reply_data->dsize);
+	if (call->reply_data->dptr == NULL) {
+		return -1;
+	}
+	memcpy(call->reply_data->dptr, call->header, sizeof(struct ctdb_ltdb_header));
+	memcpy(&call->reply_data->dptr[sizeof(struct ctdb_ltdb_header)], call->record_data.dptr, call->record_data.dsize);
+
+	return 0;
+}
+
+/*
+  attach to a specific database - client call
+*/
+struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb,
+				    struct timeval timeout,
+				    const char *name,
+				    bool persistent,
+				    uint32_t tdb_flags)
+{
+	struct ctdb_db_context *ctdb_db;
+	TDB_DATA data;
+	int ret;
+	int32_t res;
+
+	ctdb_db = ctdb_db_handle(ctdb, name);
+	if (ctdb_db) {
+		return ctdb_db;
+	}
+
+	ctdb_db = talloc_zero(ctdb, struct ctdb_db_context);
+	CTDB_NO_MEMORY_NULL(ctdb, ctdb_db);
+
+	ctdb_db->ctdb = ctdb;
+	ctdb_db->db_name = talloc_strdup(ctdb_db, name);
+	CTDB_NO_MEMORY_NULL(ctdb, ctdb_db->db_name);
+
+	data.dptr = discard_const(name);
+	data.dsize = strlen(name)+1;
+
+	/* tell ctdb daemon to attach */
+	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, tdb_flags, 
+			   persistent?CTDB_CONTROL_DB_ATTACH_PERSISTENT:CTDB_CONTROL_DB_ATTACH,
+			   0, data, ctdb_db, &data, &res, NULL, NULL);
+	if (ret != 0 || res != 0 || data.dsize != sizeof(uint32_t)) {
+		DEBUG(DEBUG_ERR,("Failed to attach to database '%s'\n", name));
+		talloc_free(ctdb_db);
+		return NULL;
+	}
+	
+	ctdb_db->db_id = *(uint32_t *)data.dptr;
+	talloc_free(data.dptr);
+
+	ret = ctdb_ctrl_getdbpath(ctdb, timeout, CTDB_CURRENT_NODE, ctdb_db->db_id, ctdb_db, &ctdb_db->db_path);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to get dbpath for database '%s'\n", name));
+		talloc_free(ctdb_db);
+		return NULL;
+	}
+
+	tdb_flags = persistent?TDB_DEFAULT:TDB_NOSYNC;
+	if (ctdb->valgrinding) {
+		tdb_flags |= TDB_NOMMAP;
+	}
+	tdb_flags |= TDB_DISALLOW_NESTING;
+
+	ctdb_db->ltdb = tdb_wrap_open(ctdb, ctdb_db->db_path, 0, tdb_flags, O_RDWR, 0);
+	if (ctdb_db->ltdb == NULL) {
+		ctdb_set_error(ctdb, "Failed to open tdb '%s'\n", ctdb_db->db_path);
+		talloc_free(ctdb_db);
+		return NULL;
+	}
+
+	ctdb_db->persistent = persistent;
+
+	DLIST_ADD(ctdb->db_list, ctdb_db);
+
+	/* add well known functions */
+	ctdb_set_call(ctdb_db, ctdb_null_func, CTDB_NULL_FUNC);
+	ctdb_set_call(ctdb_db, ctdb_fetch_func, CTDB_FETCH_FUNC);
+	ctdb_set_call(ctdb_db, ctdb_fetch_with_header_func, CTDB_FETCH_WITH_HEADER_FUNC);
+
+	return ctdb_db;
+}
+
+
+/*
+  setup a call for a database
+ */
+int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id)
+{
+	struct ctdb_registered_call *call;
+
+#if 0
+	TDB_DATA data;
+	int32_t status;
+	struct ctdb_control_set_call c;
+	int ret;
+
+	/* this is no longer valid with the separate daemon architecture */
+	c.db_id = ctdb_db->db_id;
+	c.fn    = fn;
+	c.id    = id;
+
+	data.dptr = (uint8_t *)&c;
+	data.dsize = sizeof(c);
+
+	ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_SET_CALL, 0,
+			   data, NULL, NULL, &status, NULL, NULL);
+	if (ret != 0 || status != 0) {
+		DEBUG(DEBUG_ERR,("ctdb_set_call failed for call %u\n", id));
+		return -1;
+	}
+#endif
+
+	/* also register locally */
+	call = talloc(ctdb_db, struct ctdb_registered_call);
+	call->fn = fn;
+	call->id = id;
+
+	DLIST_ADD(ctdb_db->calls, call);	
+	return 0;
+}
+
+
+struct traverse_state {
+	bool done;
+	uint32_t count;
+	ctdb_traverse_func fn;
+	void *private_data;
+};
+
+/*
+  called on each key during a ctdb_traverse
+ */
+static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *p)
+{
+	struct traverse_state *state = (struct traverse_state *)p;
+	struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr;
+	TDB_DATA key;
+
+	if (data.dsize < sizeof(uint32_t) ||
+	    d->length != data.dsize) {
+		DEBUG(DEBUG_ERR,("Bad data size %u in traverse_handler\n", (unsigned)data.dsize));
+		state->done = True;
+		return;
+	}
+
+	key.dsize = d->keylen;
+	key.dptr  = &d->data[0];
+	data.dsize = d->datalen;
+	data.dptr = &d->data[d->keylen];
+
+	if (key.dsize == 0 && data.dsize == 0) {
+		/* end of traverse */
+		state->done = True;
+		return;
+	}
+
+	if (data.dsize == sizeof(struct ctdb_ltdb_header)) {
+		/* empty records are deleted records in ctdb */
+		return;
+	}
+
+	if (state->fn(ctdb, key, data, state->private_data) != 0) {
+		state->done = True;
+	}
+
+	state->count++;
+}
+
+
+/*
+  start a cluster wide traverse, calling the supplied fn on each record
+  return the number of records traversed, or -1 on error
+ */
+int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *private_data)
+{
+	TDB_DATA data;
+	struct ctdb_traverse_start t;
+	int32_t status;
+	int ret;
+	uint64_t srvid = (getpid() | 0xFLL<<60);
+	struct traverse_state state;
+
+	state.done = False;
+	state.count = 0;
+	state.private_data = private_data;
+	state.fn = fn;
+
+	ret = ctdb_client_set_message_handler(ctdb_db->ctdb, srvid, traverse_handler, &state);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to setup traverse handler\n"));
+		return -1;
+	}
+
+	t.db_id = ctdb_db->db_id;
+	t.srvid = srvid;
+	t.reqid = 0;
+
+	data.dptr = (uint8_t *)&t;
+	data.dsize = sizeof(t);
+
+	ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_TRAVERSE_START, 0,
+			   data, NULL, NULL, &status, NULL, NULL);
+	if (ret != 0 || status != 0) {
+		DEBUG(DEBUG_ERR,("ctdb_traverse_all failed\n"));
+		ctdb_client_remove_message_handler(ctdb_db->ctdb, srvid, &state);
+		return -1;
+	}
+
+	while (!state.done) {
+		event_loop_once(ctdb_db->ctdb->ev);
+	}
+
+	ret = ctdb_client_remove_message_handler(ctdb_db->ctdb, srvid, &state);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to remove ctdb_traverse handler\n"));
+		return -1;
+	}
+
+	return state.count;
+}
+
+#define ISASCII(x) (isprint(x) && !strchr("\"\\", (x)))
+/*
+  called on each key during a catdb
+ */
+int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p)
+{
+	int i;
+	FILE *f = (FILE *)p;
+	struct ctdb_ltdb_header *h = (struct ctdb_ltdb_header *)data.dptr;
+
+	fprintf(f, "key(%u) = \"", (unsigned)key.dsize);
+	for (i=0;i<key.dsize;i++) {
+		if (ISASCII(key.dptr[i])) {
+			fprintf(f, "%c", key.dptr[i]);
+		} else {
+			fprintf(f, "\\%02X", key.dptr[i]);
+		}
+	}
+	fprintf(f, "\"\n");
+
+	fprintf(f, "dmaster: %u\n", h->dmaster);
+	fprintf(f, "rsn: %llu\n", (unsigned long long)h->rsn);
+	fprintf(f, "flags: 0x%08x", h->flags);
+	if (h->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) printf(" MIGRATED_WITH_DATA");
+	if (h->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) printf(" VACUUM_MIGRATED");
+	if (h->flags & CTDB_REC_FLAG_AUTOMATIC) printf(" AUTOMATIC");
+	if (h->flags & CTDB_REC_RO_HAVE_DELEGATIONS) printf(" RO_HAVE_DELEGATIONS");
+	if (h->flags & CTDB_REC_RO_HAVE_READONLY) printf(" RO_HAVE_READONLY");
+	if (h->flags & CTDB_REC_RO_REVOKING_READONLY) printf(" RO_REVOKING_READONLY");
+	if (h->flags & CTDB_REC_RO_REVOKE_COMPLETE) printf(" RO_REVOKE_COMPLETE");
+	fprintf(f, "\n");
+
+	fprintf(f, "data(%u) = \"", (unsigned)(data.dsize - sizeof(*h)));
+	for (i=sizeof(*h);i<data.dsize;i++) {
+		if (ISASCII(data.dptr[i])) {
+			fprintf(f, "%c", data.dptr[i]);
+		} else {
+			fprintf(f, "\\%02X", data.dptr[i]);
+		}
+	}
+	fprintf(f, "\"\n");
+
+	fprintf(f, "\n");
+
+	return 0;
+}
+
+/*
+  convenience function to list all keys to stdout
+ */
+int ctdb_dump_db(struct ctdb_db_context *ctdb_db, FILE *f)
+{
+	return ctdb_traverse(ctdb_db, ctdb_dumpdb_record, f);
+}
+
+/*
+  get the pid of a ctdb daemon
+ */
+int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *pid)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_PID, 0, tdb_null, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpid failed\n"));
+		return -1;
+	}
+
+	*pid = res;
+
+	return 0;
+}
+
+
+/*
+  async freeze send control
+ */
+struct ctdb_client_control_state *
+ctdb_ctrl_freeze_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t priority)
+{
+	return ctdb_control_send(ctdb, destnode, priority, 
+			   CTDB_CONTROL_FREEZE, 0, tdb_null, 
+			   mem_ctx, &timeout, NULL);
+}
+
+/* 
+   async freeze recv control
+*/
+int ctdb_ctrl_freeze_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control_recv(ctdb, state, mem_ctx, NULL, &res, NULL);
+	if ( (ret != 0) || (res != 0) ){
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_freeze_recv failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  freeze databases of a certain priority
+ */
+int ctdb_ctrl_freeze_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t priority)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_client_control_state *state;
+	int ret;
+
+	state = ctdb_ctrl_freeze_send(ctdb, tmp_ctx, timeout, destnode, priority);
+	ret = ctdb_ctrl_freeze_recv(ctdb, tmp_ctx, state);
+	talloc_free(tmp_ctx);
+
+	return ret;
+}
+
+/* Freeze all databases */
+int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	int i;
+
+	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb_ctrl_freeze_priority(ctdb, timeout, destnode, i) != 0) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+  thaw databases of a certain priority
+ */
+int ctdb_ctrl_thaw_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t priority)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, priority, 
+			   CTDB_CONTROL_THAW, 0, tdb_null, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control thaw failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* thaw all databases */
+int ctdb_ctrl_thaw(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	return ctdb_ctrl_thaw_priority(ctdb, timeout, destnode, 0);
+}
+
+/*
+  get pnn of a node, or -1
+ */
+int ctdb_ctrl_getpnn(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_PNN, 0, tdb_null, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpnn failed\n"));
+		return -1;
+	}
+
+	return res;
+}
+
+/*
+  get the monitoring mode of a remote node
+ */
+int ctdb_ctrl_getmonmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *monmode)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_MONMODE, 0, tdb_null, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getmonmode failed\n"));
+		return -1;
+	}
+
+	*monmode = res;
+
+	return 0;
+}
+
+
+/*
+ set the monitoring mode of a remote node to active
+ */
+int ctdb_ctrl_enable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	int ret;
+	
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_ENABLE_MONITOR, 0, tdb_null, 
+			   NULL, NULL,NULL, &timeout, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for enable_monitor failed\n"));
+		return -1;
+	}
+
+	
+
+	return 0;
+}
+
+/*
+  set the monitoring mode of a remote node to disable
+ */
+int ctdb_ctrl_disable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	int ret;
+	
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_DISABLE_MONITOR, 0, tdb_null, 
+			   NULL, NULL, NULL, &timeout, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for disable_monitor failed\n"));
+		return -1;
+	}
+
+	
+
+	return 0;
+}
+
+
+
+/* 
+  sent to a node to make it take over an ip address
+*/
+int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout, 
+			  uint32_t destnode, struct ctdb_public_ip *ip)
+{
+	TDB_DATA data;
+	struct ctdb_public_ipv4 ipv4;
+	int ret;
+	int32_t res;
+
+	if (ip->addr.sa.sa_family == AF_INET) {
+		ipv4.pnn = ip->pnn;
+		ipv4.sin = ip->addr.ip;
+
+		data.dsize = sizeof(ipv4);
+		data.dptr  = (uint8_t *)&ipv4;
+
+		ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_TAKEOVER_IPv4, 0, data, NULL,
+			   NULL, &res, &timeout, NULL);
+	} else {
+		data.dsize = sizeof(*ip);
+		data.dptr  = (uint8_t *)ip;
+
+		ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_TAKEOVER_IP, 0, data, NULL,
+			   NULL, &res, &timeout, NULL);
+	}
+
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for takeover_ip failed\n"));
+		return -1;
+	}
+
+	return 0;	
+}
+
+
+/* 
+  sent to a node to make it release an ip address
+*/
+int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout, 
+			 uint32_t destnode, struct ctdb_public_ip *ip)
+{
+	TDB_DATA data;
+	struct ctdb_public_ipv4 ipv4;
+	int ret;
+	int32_t res;
+
+	if (ip->addr.sa.sa_family == AF_INET) {
+		ipv4.pnn = ip->pnn;
+		ipv4.sin = ip->addr.ip;
+
+		data.dsize = sizeof(ipv4);
+		data.dptr  = (uint8_t *)&ipv4;
+
+		ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELEASE_IPv4, 0, data, NULL,
+				   NULL, &res, &timeout, NULL);
+	} else {
+		data.dsize = sizeof(*ip);
+		data.dptr  = (uint8_t *)ip;
+
+		ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELEASE_IP, 0, data, NULL,
+				   NULL, &res, &timeout, NULL);
+	}
+
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for release_ip failed\n"));
+		return -1;
+	}
+
+	return 0;	
+}
+
+
+/*
+  get a tunable
+ */
+int ctdb_ctrl_get_tunable(struct ctdb_context *ctdb, 
+			  struct timeval timeout, 
+			  uint32_t destnode,
+			  const char *name, uint32_t *value)
+{
+	struct ctdb_control_get_tunable *t;
+	TDB_DATA data, outdata;
+	int32_t res;
+	int ret;
+
+	data.dsize = offsetof(struct ctdb_control_get_tunable, name) + strlen(name) + 1;
+	data.dptr  = talloc_size(ctdb, data.dsize);
+	CTDB_NO_MEMORY(ctdb, data.dptr);
+
+	t = (struct ctdb_control_get_tunable *)data.dptr;
+	t->length = strlen(name)+1;
+	memcpy(t->name, name, t->length);
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_TUNABLE, 0, data, ctdb,
+			   &outdata, &res, &timeout, NULL);
+	talloc_free(data.dptr);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get_tunable failed\n"));
+		return -1;
+	}
+
+	if (outdata.dsize != sizeof(uint32_t)) {
+		DEBUG(DEBUG_ERR,("Invalid return data in get_tunable\n"));
+		talloc_free(outdata.dptr);
+		return -1;
+	}
+	
+	*value = *(uint32_t *)outdata.dptr;
+	talloc_free(outdata.dptr);
+
+	return 0;
+}
+
+/*
+  set a tunable
+ */
+int ctdb_ctrl_set_tunable(struct ctdb_context *ctdb, 
+			  struct timeval timeout, 
+			  uint32_t destnode,
+			  const char *name, uint32_t value)
+{
+	struct ctdb_control_set_tunable *t;
+	TDB_DATA data;
+	int32_t res;
+	int ret;
+
+	data.dsize = offsetof(struct ctdb_control_set_tunable, name) + strlen(name) + 1;
+	data.dptr  = talloc_size(ctdb, data.dsize);
+	CTDB_NO_MEMORY(ctdb, data.dptr);
+
+	t = (struct ctdb_control_set_tunable *)data.dptr;
+	t->length = strlen(name)+1;
+	memcpy(t->name, name, t->length);
+	t->value = value;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_TUNABLE, 0, data, NULL,
+			   NULL, &res, &timeout, NULL);
+	talloc_free(data.dptr);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set_tunable failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  list tunables
+ */
+int ctdb_ctrl_list_tunables(struct ctdb_context *ctdb, 
+			    struct timeval timeout, 
+			    uint32_t destnode,
+			    TALLOC_CTX *mem_ctx,
+			    const char ***list, uint32_t *count)
+{
+	TDB_DATA outdata;
+	int32_t res;
+	int ret;
+	struct ctdb_control_list_tunable *t;
+	char *p, *s, *ptr;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_LIST_TUNABLES, 0, tdb_null, 
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for list_tunables failed\n"));
+		return -1;
+	}
+
+	t = (struct ctdb_control_list_tunable *)outdata.dptr;
+	if (outdata.dsize < offsetof(struct ctdb_control_list_tunable, data) ||
+	    t->length > outdata.dsize-offsetof(struct ctdb_control_list_tunable, data)) {
+		DEBUG(DEBUG_ERR,("Invalid data in list_tunables reply\n"));
+		talloc_free(outdata.dptr);
+		return -1;		
+	}
+	
+	p = talloc_strndup(mem_ctx, (char *)t->data, t->length);
+	CTDB_NO_MEMORY(ctdb, p);
+
+	talloc_free(outdata.dptr);
+	
+	(*list) = NULL;
+	(*count) = 0;
+
+	for (s=strtok_r(p, ":", &ptr); s; s=strtok_r(NULL, ":", &ptr)) {
+		(*list) = talloc_realloc(mem_ctx, *list, const char *, 1+(*count));
+		CTDB_NO_MEMORY(ctdb, *list);
+		(*list)[*count] = talloc_strdup(*list, s);
+		CTDB_NO_MEMORY(ctdb, (*list)[*count]);
+		(*count)++;
+	}
+
+	talloc_free(p);
+
+	return 0;
+}
+
+
+int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
+				   struct timeval timeout, uint32_t destnode,
+				   TALLOC_CTX *mem_ctx,
+				   uint32_t flags,
+				   struct ctdb_all_public_ips **ips)
+{
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_PUBLIC_IPS, flags, tdb_null,
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret == 0 && res == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control to get public ips failed, falling back to ipv4-only version\n"));
+		return ctdb_ctrl_get_public_ipsv4(ctdb, timeout, destnode, mem_ctx, ips);
+	}
+	if (ret != 0 || res != 0) {
+	  DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpublicips failed ret:%d res:%d\n", ret, res));
+		return -1;
+	}
+
+	*ips = (struct ctdb_all_public_ips *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	talloc_free(outdata.dptr);
+		    
+	return 0;
+}
+
+int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode,
+			     TALLOC_CTX *mem_ctx,
+			     struct ctdb_all_public_ips **ips)
+{
+	return ctdb_ctrl_get_public_ips_flags(ctdb, timeout,
+					      destnode, mem_ctx,
+					      0, ips);
+}
+
+int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb, 
+			struct timeval timeout, uint32_t destnode, 
+			TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips)
+{
+	int ret, i, len;
+	TDB_DATA outdata;
+	int32_t res;
+	struct ctdb_all_public_ipsv4 *ipsv4;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_PUBLIC_IPSv4, 0, tdb_null, 
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpublicips failed\n"));
+		return -1;
+	}
+
+	ipsv4 = (struct ctdb_all_public_ipsv4 *)outdata.dptr;
+	len = offsetof(struct ctdb_all_public_ips, ips) +
+		ipsv4->num*sizeof(struct ctdb_public_ip);
+	*ips = talloc_zero_size(mem_ctx, len);
+	CTDB_NO_MEMORY(ctdb, *ips);
+	(*ips)->num = ipsv4->num;
+	for (i=0; i<ipsv4->num; i++) {
+		(*ips)->ips[i].pnn     = ipsv4->ips[i].pnn;
+		(*ips)->ips[i].addr.ip = ipsv4->ips[i].sin;
+	}
+
+	talloc_free(outdata.dptr);
+		    
+	return 0;
+}
+
+int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
+				 struct timeval timeout, uint32_t destnode,
+				 TALLOC_CTX *mem_ctx,
+				 const ctdb_sock_addr *addr,
+				 struct ctdb_control_public_ip_info **_info)
+{
+	int ret;
+	TDB_DATA indata;
+	TDB_DATA outdata;
+	int32_t res;
+	struct ctdb_control_public_ip_info *info;
+	uint32_t len;
+	uint32_t i;
+
+	indata.dptr = discard_const_p(uint8_t, addr);
+	indata.dsize = sizeof(*addr);
+
+	ret = ctdb_control(ctdb, destnode, 0,
+			   CTDB_CONTROL_GET_PUBLIC_IP_INFO, 0, indata,
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
+				"failed ret:%d res:%d\n",
+				ret, res));
+		return -1;
+	}
+
+	len = offsetof(struct ctdb_control_public_ip_info, ifaces);
+	if (len > outdata.dsize) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
+				"returned invalid data with size %u > %u\n",
+				(unsigned int)outdata.dsize,
+				(unsigned int)len));
+		dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
+		return -1;
+	}
+
+	info = (struct ctdb_control_public_ip_info *)outdata.dptr;
+	len += info->num*sizeof(struct ctdb_control_iface_info);
+
+	if (len > outdata.dsize) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
+				"returned invalid data with size %u > %u\n",
+				(unsigned int)outdata.dsize,
+				(unsigned int)len));
+		dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
+		return -1;
+	}
+
+	/* make sure we null terminate the returned strings */
+	for (i=0; i < info->num; i++) {
+		info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
+	}
+
+	*_info = (struct ctdb_control_public_ip_info *)talloc_memdup(mem_ctx,
+								outdata.dptr,
+								outdata.dsize);
+	talloc_free(outdata.dptr);
+	if (*_info == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
+				"talloc_memdup size %u failed\n",
+				(unsigned int)outdata.dsize));
+		return -1;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
+			 struct timeval timeout, uint32_t destnode,
+			 TALLOC_CTX *mem_ctx,
+			 struct ctdb_control_get_ifaces **_ifaces)
+{
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+	struct ctdb_control_get_ifaces *ifaces;
+	uint32_t len;
+	uint32_t i;
+
+	ret = ctdb_control(ctdb, destnode, 0,
+			   CTDB_CONTROL_GET_IFACES, 0, tdb_null,
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
+				"failed ret:%d res:%d\n",
+				ret, res));
+		return -1;
+	}
+
+	len = offsetof(struct ctdb_control_get_ifaces, ifaces);
+	if (len > outdata.dsize) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
+				"returned invalid data with size %u > %u\n",
+				(unsigned int)outdata.dsize,
+				(unsigned int)len));
+		dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
+		return -1;
+	}
+
+	ifaces = (struct ctdb_control_get_ifaces *)outdata.dptr;
+	len += ifaces->num*sizeof(struct ctdb_control_iface_info);
+
+	if (len > outdata.dsize) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
+				"returned invalid data with size %u > %u\n",
+				(unsigned int)outdata.dsize,
+				(unsigned int)len));
+		dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
+		return -1;
+	}
+
+	/* make sure we null terminate the returned strings */
+	for (i=0; i < ifaces->num; i++) {
+		ifaces->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
+	}
+
+	*_ifaces = (struct ctdb_control_get_ifaces *)talloc_memdup(mem_ctx,
+								  outdata.dptr,
+								  outdata.dsize);
+	talloc_free(outdata.dptr);
+	if (*_ifaces == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
+				"talloc_memdup size %u failed\n",
+				(unsigned int)outdata.dsize));
+		return -1;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode,
+			     TALLOC_CTX *mem_ctx,
+			     const struct ctdb_control_iface_info *info)
+{
+	int ret;
+	TDB_DATA indata;
+	int32_t res;
+
+	indata.dptr = discard_const_p(uint8_t, info);
+	indata.dsize = sizeof(*info);
+
+	ret = ctdb_control(ctdb, destnode, 0,
+			   CTDB_CONTROL_SET_IFACE_LINK_STATE, 0, indata,
+			   mem_ctx, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set iface link "
+				"failed ret:%d res:%d\n",
+				ret, res));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  set/clear the permanent disabled bit on a remote node
+ */
+int ctdb_ctrl_modflags(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, 
+		       uint32_t set, uint32_t clear)
+{
+	int ret;
+	TDB_DATA data;
+	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_flag_change c;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	uint32_t recmaster;
+	uint32_t *nodes;
+
+
+	/* find the recovery master */
+	ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, timeout, CTDB_CURRENT_NODE, &recmaster);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get recmaster from local node\n"));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+
+	/* read the node flags from the recmaster */
+	ret = ctdb_ctrl_getnodemap(ctdb, timeout, recmaster, tmp_ctx, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from node %u\n", destnode));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	if (destnode >= nodemap->num) {
+		DEBUG(DEBUG_ERR,(__location__ " Nodemap from recmaster does not contain node %d\n", destnode));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	c.pnn       = destnode;
+	c.old_flags = nodemap->nodes[destnode].flags;
+	c.new_flags = c.old_flags;
+	c.new_flags |= set;
+	c.new_flags &= ~clear;
+
+	data.dsize = sizeof(c);
+	data.dptr = (unsigned char *)&c;
+
+	/* send the flags update to all connected nodes */
+	nodes = list_of_connected_nodes(ctdb, nodemap, tmp_ctx, true);
+
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_MODIFY_FLAGS,
+					nodes, 0,
+					timeout, false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to update nodeflags on remote nodes\n"));
+
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+
+/*
+  get all tunables
+ */
+int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb, 
+			       struct timeval timeout, 
+			       uint32_t destnode,
+			       struct ctdb_tunable *tunables)
+{
+	TDB_DATA outdata;
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_ALL_TUNABLES, 0, tdb_null, ctdb,
+			   &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get all tunables failed\n"));
+		return -1;
+	}
+
+	if (outdata.dsize != sizeof(*tunables)) {
+		DEBUG(DEBUG_ERR,(__location__ " bad data size %u in ctdb_ctrl_get_all_tunables should be %u\n",
+			 (unsigned)outdata.dsize, (unsigned)sizeof(*tunables)));
+		return -1;		
+	}
+
+	*tunables = *(struct ctdb_tunable *)outdata.dptr;
+	talloc_free(outdata.dptr);
+	return 0;
+}
+
+/*
+  add a public address to a node
+ */
+int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      struct ctdb_control_ip_iface *pub)
+{
+	TDB_DATA data;
+	int32_t res;
+	int ret;
+
+	data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len;
+	data.dptr  = (unsigned char *)pub;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_ADD_PUBLIC_IP, 0, data, NULL,
+			   NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for add_public_ip failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  delete a public address from a node
+ */
+int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      struct ctdb_control_ip_iface *pub)
+{
+	TDB_DATA data;
+	int32_t res;
+	int ret;
+
+	data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len;
+	data.dptr  = (unsigned char *)pub;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_DEL_PUBLIC_IP, 0, data, NULL,
+			   NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for del_public_ip failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  kill a tcp connection
+ */
+int ctdb_ctrl_killtcp(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      struct ctdb_control_killtcp *killtcp)
+{
+	TDB_DATA data;
+	int32_t res;
+	int ret;
+
+	data.dsize = sizeof(struct ctdb_control_killtcp);
+	data.dptr  = (unsigned char *)killtcp;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_KILL_TCP, 0, data, NULL,
+			   NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for killtcp failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  send a gratious arp
+ */
+int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      ctdb_sock_addr *addr,
+		      const char *ifname)
+{
+	TDB_DATA data;
+	int32_t res;
+	int ret, len;
+	struct ctdb_control_gratious_arp *gratious_arp;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+
+	len = strlen(ifname)+1;
+	gratious_arp = talloc_size(tmp_ctx, 
+		offsetof(struct ctdb_control_gratious_arp, iface) + len);
+	CTDB_NO_MEMORY(ctdb, gratious_arp);
+
+	gratious_arp->addr = *addr;
+	gratious_arp->len = len;
+	memcpy(&gratious_arp->iface[0], ifname, len);
+
+
+	data.dsize = offsetof(struct ctdb_control_gratious_arp, iface) + len;
+	data.dptr  = (unsigned char *)gratious_arp;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SEND_GRATIOUS_ARP, 0, data, NULL,
+			   NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for gratious_arp failed\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  get a list of all tcp tickles that a node knows about for a particular vnn
+ */
+int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb, 
+			      struct timeval timeout, uint32_t destnode, 
+			      TALLOC_CTX *mem_ctx, 
+			      ctdb_sock_addr *addr,
+			      struct ctdb_control_tcp_tickle_list **list)
+{
+	int ret;
+	TDB_DATA data, outdata;
+	int32_t status;
+
+	data.dptr = (uint8_t*)addr;
+	data.dsize = sizeof(ctdb_sock_addr);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_TCP_TICKLE_LIST, 0, data, 
+			   mem_ctx, &outdata, &status, NULL, NULL);
+	if (ret != 0 || status != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get tcp tickles failed\n"));
+		return -1;
+	}
+
+	*list = (struct ctdb_control_tcp_tickle_list *)outdata.dptr;
+
+	return status;
+}
+
+/*
+  register a server id
+ */
+int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      struct ctdb_server_id *id)
+{
+	TDB_DATA data;
+	int32_t res;
+	int ret;
+
+	data.dsize = sizeof(struct ctdb_server_id);
+	data.dptr  = (unsigned char *)id;
+
+	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, 
+			CTDB_CONTROL_REGISTER_SERVER_ID, 
+			0, data, NULL,
+			NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for register server id failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  unregister a server id
+ */
+int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      struct ctdb_server_id *id)
+{
+	TDB_DATA data;
+	int32_t res;
+	int ret;
+
+	data.dsize = sizeof(struct ctdb_server_id);
+	data.dptr  = (unsigned char *)id;
+
+	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, 
+			CTDB_CONTROL_UNREGISTER_SERVER_ID, 
+			0, data, NULL,
+			NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for unregister server id failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+  check if a server id exists
+
+  if a server id does exist, return *status == 1, otherwise *status == 0
+ */
+int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      struct ctdb_server_id *id,
+		      uint32_t *status)
+{
+	TDB_DATA data;
+	int32_t res;
+	int ret;
+
+	data.dsize = sizeof(struct ctdb_server_id);
+	data.dptr  = (unsigned char *)id;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_CHECK_SERVER_ID, 
+			0, data, NULL,
+			NULL, &res, &timeout, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for check server id failed\n"));
+		return -1;
+	}
+
+	if (res) {
+		*status = 1;
+	} else {
+		*status = 0;
+	}
+
+	return 0;
+}
+
+/*
+   get the list of server ids that are registered on a node
+*/
+int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb,
+		TALLOC_CTX *mem_ctx,
+		struct timeval timeout, uint32_t destnode, 
+		struct ctdb_server_id_list **svid_list)
+{
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_SERVER_ID_LIST, 0, tdb_null, 
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get_server_id_list failed\n"));
+		return -1;
+	}
+
+	*svid_list = (struct ctdb_server_id_list *)talloc_steal(mem_ctx, outdata.dptr);
+		    
+	return 0;
+}
+
+/*
+  initialise the ctdb daemon for client applications
+
+  NOTE: In current code the daemon does not fork. This is for testing purposes only
+  and to simplify the code.
+*/
+struct ctdb_context *ctdb_init(struct event_context *ev)
+{
+	int ret;
+	struct ctdb_context *ctdb;
+
+	ctdb = talloc_zero(ev, struct ctdb_context);
+	if (ctdb == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " talloc_zero failed.\n"));
+		return NULL;
+	}
+	ctdb->ev  = ev;
+	ctdb->idr = idr_init(ctdb);
+	/* Wrap early to exercise code. */
+	ctdb->lastid = INT_MAX-200;
+	CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr);
+
+	ret = ctdb_set_socketname(ctdb, CTDB_PATH);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_set_socketname failed.\n"));
+		talloc_free(ctdb);
+		return NULL;
+	}
+
+	ctdb->statistics.statistics_start_time = timeval_current();
+
+	return ctdb;
+}
+
+
+/*
+  set some ctdb flags
+*/
+void ctdb_set_flags(struct ctdb_context *ctdb, unsigned flags)
+{
+	ctdb->flags |= flags;
+}
+
+/*
+  setup the local socket name
+*/
+int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname)
+{
+	ctdb->daemon.name = talloc_strdup(ctdb, socketname);
+	CTDB_NO_MEMORY(ctdb, ctdb->daemon.name);
+
+	return 0;
+}
+
+const char *ctdb_get_socketname(struct ctdb_context *ctdb)
+{
+	return ctdb->daemon.name;
+}
+
+/*
+  return the pnn of this node
+*/
+uint32_t ctdb_get_pnn(struct ctdb_context *ctdb)
+{
+	return ctdb->pnn;
+}
+
+
+/*
+  get the uptime of a remote node
+ */
+struct ctdb_client_control_state *
+ctdb_ctrl_uptime_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode)
+{
+	return ctdb_control_send(ctdb, destnode, 0, 
+			   CTDB_CONTROL_UPTIME, 0, tdb_null, 
+			   mem_ctx, &timeout, NULL);
+}
+
+int ctdb_ctrl_uptime_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, struct ctdb_uptime **uptime)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA outdata;
+
+	ret = ctdb_control_recv(ctdb, state, mem_ctx, &outdata, &res, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_uptime_recv failed\n"));
+		return -1;
+	}
+
+	*uptime = (struct ctdb_uptime *)talloc_steal(mem_ctx, outdata.dptr);
+
+	return 0;
+}
+
+int ctdb_ctrl_uptime(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_uptime **uptime)
+{
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_ctrl_uptime_send(ctdb, mem_ctx, timeout, destnode);
+	return ctdb_ctrl_uptime_recv(ctdb, mem_ctx, state, uptime);
+}
+
+/*
+  send a control to execute the "recovered" event script on a node
+ */
+int ctdb_ctrl_end_recovery(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	int ret;
+	int32_t status;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_END_RECOVERY, 0, tdb_null, 
+			   NULL, NULL, &status, &timeout, NULL);
+	if (ret != 0 || status != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for end_recovery failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* 
+  callback for the async helpers used when sending the same control
+  to multiple nodes in parallell.
+*/
+static void async_callback(struct ctdb_client_control_state *state)
+{
+	struct client_async_data *data = talloc_get_type(state->async.private_data, struct client_async_data);
+	struct ctdb_context *ctdb = talloc_get_type(state->ctdb, struct ctdb_context);
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+	uint32_t destnode = state->c->hdr.destnode;
+
+	/* one more node has responded with recmode data */
+	data->count--;
+
+	/* if we failed to push the db, then return an error and let
+	   the main loop try again.
+	*/
+	if (state->state != CTDB_CONTROL_DONE) {
+		if ( !data->dont_log_errors) {
+			DEBUG(DEBUG_ERR,("Async operation failed with state %d, opcode:%u\n", state->state, data->opcode));
+		}
+		data->fail_count++;
+		if (data->fail_callback) {
+			data->fail_callback(ctdb, destnode, res, outdata,
+					data->callback_data);
+		}
+		return;
+	}
+	
+	state->async.fn = NULL;
+
+	ret = ctdb_control_recv(ctdb, state, data, &outdata, &res, NULL);
+	if ((ret != 0) || (res != 0)) {
+		if ( !data->dont_log_errors) {
+			DEBUG(DEBUG_ERR,("Async operation failed with ret=%d res=%d opcode=%u\n", ret, (int)res, data->opcode));
+		}
+		data->fail_count++;
+		if (data->fail_callback) {
+			data->fail_callback(ctdb, destnode, res, outdata,
+					data->callback_data);
+		}
+	}
+	if ((ret == 0) && (data->callback != NULL)) {
+		data->callback(ctdb, destnode, res, outdata,
+					data->callback_data);
+	}
+}
+
+
+void ctdb_client_async_add(struct client_async_data *data, struct ctdb_client_control_state *state)
+{
+	/* set up the callback functions */
+	state->async.fn = async_callback;
+	state->async.private_data = data;
+	
+	/* one more control to wait for to complete */
+	data->count++;
+}
+
+
+/* wait for up to the maximum number of seconds allowed
+   or until all nodes we expect a response from has replied
+*/
+int ctdb_client_async_wait(struct ctdb_context *ctdb, struct client_async_data *data)
+{
+	while (data->count > 0) {
+		event_loop_once(ctdb->ev);
+	}
+	if (data->fail_count != 0) {
+		if (!data->dont_log_errors) {
+			DEBUG(DEBUG_ERR,("Async wait failed - fail_count=%u\n", 
+				 data->fail_count));
+		}
+		return -1;
+	}
+	return 0;
+}
+
+
+/* 
+   perform a simple control on the listed nodes
+   The control cannot return data
+ */
+int ctdb_client_async_control(struct ctdb_context *ctdb,
+				enum ctdb_controls opcode,
+				uint32_t *nodes,
+				uint64_t srvid,
+				struct timeval timeout,
+				bool dont_log_errors,
+				TDB_DATA data,
+				client_async_callback client_callback,
+			        client_async_callback fail_callback,
+				void *callback_data)
+{
+	struct client_async_data *async_data;
+	struct ctdb_client_control_state *state;
+	int j, num_nodes;
+
+	async_data = talloc_zero(ctdb, struct client_async_data);
+	CTDB_NO_MEMORY_FATAL(ctdb, async_data);
+	async_data->dont_log_errors = dont_log_errors;
+	async_data->callback = client_callback;
+	async_data->fail_callback = fail_callback;
+	async_data->callback_data = callback_data;
+	async_data->opcode        = opcode;
+
+	num_nodes = talloc_get_size(nodes) / sizeof(uint32_t);
+
+	/* loop over all nodes and send an async control to each of them */
+	for (j=0; j<num_nodes; j++) {
+		uint32_t pnn = nodes[j];
+
+		state = ctdb_control_send(ctdb, pnn, srvid, opcode, 
+					  0, data, async_data, &timeout, NULL);
+		if (state == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to call async control %u\n", (unsigned)opcode));
+			talloc_free(async_data);
+			return -1;
+		}
+		
+		ctdb_client_async_add(async_data, state);
+	}
+
+	if (ctdb_client_async_wait(ctdb, async_data) != 0) {
+		talloc_free(async_data);
+		return -1;
+	}
+
+	talloc_free(async_data);
+	return 0;
+}
+
+uint32_t *list_of_vnnmap_nodes(struct ctdb_context *ctdb,
+				struct ctdb_vnn_map *vnn_map,
+				TALLOC_CTX *mem_ctx,
+				bool include_self)
+{
+	int i, j, num_nodes;
+	uint32_t *nodes;
+
+	for (i=num_nodes=0;i<vnn_map->size;i++) {
+		if (vnn_map->map[i] == ctdb->pnn && !include_self) {
+			continue;
+		}
+		num_nodes++;
+	} 
+
+	nodes = talloc_array(mem_ctx, uint32_t, num_nodes);
+	CTDB_NO_MEMORY_FATAL(ctdb, nodes);
+
+	for (i=j=0;i<vnn_map->size;i++) {
+		if (vnn_map->map[i] == ctdb->pnn && !include_self) {
+			continue;
+		}
+		nodes[j++] = vnn_map->map[i];
+	} 
+
+	return nodes;
+}
+
+uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
+				struct ctdb_node_map *node_map,
+				TALLOC_CTX *mem_ctx,
+				bool include_self)
+{
+	int i, j, num_nodes;
+	uint32_t *nodes;
+
+	for (i=num_nodes=0;i<node_map->num;i++) {
+		if (node_map->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (node_map->nodes[i].pnn == ctdb->pnn && !include_self) {
+			continue;
+		}
+		num_nodes++;
+	} 
+
+	nodes = talloc_array(mem_ctx, uint32_t, num_nodes);
+	CTDB_NO_MEMORY_FATAL(ctdb, nodes);
+
+	for (i=j=0;i<node_map->num;i++) {
+		if (node_map->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (node_map->nodes[i].pnn == ctdb->pnn && !include_self) {
+			continue;
+		}
+		nodes[j++] = node_map->nodes[i].pnn;
+	} 
+
+	return nodes;
+}
+
+uint32_t *list_of_active_nodes_except_pnn(struct ctdb_context *ctdb,
+				struct ctdb_node_map *node_map,
+				TALLOC_CTX *mem_ctx,
+				uint32_t pnn)
+{
+	int i, j, num_nodes;
+	uint32_t *nodes;
+
+	for (i=num_nodes=0;i<node_map->num;i++) {
+		if (node_map->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (node_map->nodes[i].pnn == pnn) {
+			continue;
+		}
+		num_nodes++;
+	} 
+
+	nodes = talloc_array(mem_ctx, uint32_t, num_nodes);
+	CTDB_NO_MEMORY_FATAL(ctdb, nodes);
+
+	for (i=j=0;i<node_map->num;i++) {
+		if (node_map->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (node_map->nodes[i].pnn == pnn) {
+			continue;
+		}
+		nodes[j++] = node_map->nodes[i].pnn;
+	} 
+
+	return nodes;
+}
+
+uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb,
+				struct ctdb_node_map *node_map,
+				TALLOC_CTX *mem_ctx,
+				bool include_self)
+{
+	int i, j, num_nodes;
+	uint32_t *nodes;
+
+	for (i=num_nodes=0;i<node_map->num;i++) {
+		if (node_map->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+		if (node_map->nodes[i].pnn == ctdb->pnn && !include_self) {
+			continue;
+		}
+		num_nodes++;
+	} 
+
+	nodes = talloc_array(mem_ctx, uint32_t, num_nodes);
+	CTDB_NO_MEMORY_FATAL(ctdb, nodes);
+
+	for (i=j=0;i<node_map->num;i++) {
+		if (node_map->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+		if (node_map->nodes[i].pnn == ctdb->pnn && !include_self) {
+			continue;
+		}
+		nodes[j++] = node_map->nodes[i].pnn;
+	} 
+
+	return nodes;
+}
+
+/* 
+  this is used to test if a pnn lock exists and if it exists will return
+  the number of connections that pnn has reported or -1 if that recovery
+  daemon is not running.
+*/
+int
+ctdb_read_pnn_lock(int fd, int32_t pnn)
+{
+	struct flock lock;
+	char c;
+
+	lock.l_type = F_WRLCK;
+	lock.l_whence = SEEK_SET;
+	lock.l_start = pnn;
+	lock.l_len = 1;
+	lock.l_pid = 0;
+
+	if (fcntl(fd, F_GETLK, &lock) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " F_GETLK failed with %s\n", strerror(errno)));
+		return -1;
+	}
+
+	if (lock.l_type == F_UNLCK) {
+		return -1;
+	}
+
+	if (pread(fd, &c, 1, pnn) == -1) {
+		DEBUG(DEBUG_CRIT,(__location__ " failed read pnn count - %s\n", strerror(errno)));
+		return -1;
+	}
+
+	return c;
+}
+
+/*
+  get capabilities of a remote node
+ */
+struct ctdb_client_control_state *
+ctdb_ctrl_getcapabilities_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode)
+{
+	return ctdb_control_send(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_CAPABILITIES, 0, tdb_null, 
+			   mem_ctx, &timeout, NULL);
+}
+
+int ctdb_ctrl_getcapabilities_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *capabilities)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA outdata;
+
+	ret = ctdb_control_recv(ctdb, state, mem_ctx, &outdata, &res, NULL);
+	if ( (ret != 0) || (res != 0) ) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_getcapabilities_recv failed\n"));
+		return -1;
+	}
+
+	if (capabilities) {
+		*capabilities = *((uint32_t *)outdata.dptr);
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_getcapabilities(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *capabilities)
+{
+	struct ctdb_client_control_state *state;
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	int ret;
+
+	state = ctdb_ctrl_getcapabilities_send(ctdb, tmp_ctx, timeout, destnode);
+	ret = ctdb_ctrl_getcapabilities_recv(ctdb, tmp_ctx, state, capabilities);
+	talloc_free(tmp_ctx);
+	return ret;
+}
+
+/**
+ * check whether a transaction is active on a given db on a given node
+ */
+int32_t ctdb_ctrl_transaction_active(struct ctdb_context *ctdb,
+				     uint32_t destnode,
+				     uint32_t db_id)
+{
+	int32_t status;
+	int ret;
+	TDB_DATA indata;
+
+	indata.dptr = (uint8_t *)&db_id;
+	indata.dsize = sizeof(db_id);
+
+	ret = ctdb_control(ctdb, destnode, 0,
+			   CTDB_CONTROL_TRANS2_ACTIVE,
+			   0, indata, NULL, NULL, &status,
+			   NULL, NULL);
+
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " ctdb control for transaction_active failed\n"));
+		return -1;
+	}
+
+	return status;
+}
+
+
+struct ctdb_transaction_handle {
+	struct ctdb_db_context *ctdb_db;
+	bool in_replay;
+	/*
+	 * we store the reads and writes done under a transaction:
+	 * - one list stores both reads and writes (m_all),
+	 * - the other just writes (m_write)
+	 */
+	struct ctdb_marshall_buffer *m_all;
+	struct ctdb_marshall_buffer *m_write;
+};
+
+/* start a transaction on a database */
+static int ctdb_transaction_destructor(struct ctdb_transaction_handle *h)
+{
+	tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
+	return 0;
+}
+
+/* start a transaction on a database */
+static int ctdb_transaction_fetch_start(struct ctdb_transaction_handle *h)
+{
+	struct ctdb_record_handle *rh;
+	TDB_DATA key;
+	TDB_DATA data;
+	struct ctdb_ltdb_header header;
+	TALLOC_CTX *tmp_ctx;
+	const char *keyname = CTDB_TRANSACTION_LOCK_KEY;
+	int ret;
+	struct ctdb_db_context *ctdb_db = h->ctdb_db;
+	pid_t pid;
+	int32_t status;
+
+	key.dptr = discard_const(keyname);
+	key.dsize = strlen(keyname);
+
+	if (!ctdb_db->persistent) {
+		DEBUG(DEBUG_ERR,(__location__ " Attempted transaction on non-persistent database\n"));
+		return -1;
+	}
+
+again:
+	tmp_ctx = talloc_new(h);
+
+	rh = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, NULL);
+	if (rh == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to fetch_lock database\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	status = ctdb_ctrl_transaction_active(ctdb_db->ctdb,
+					      CTDB_CURRENT_NODE,
+					      ctdb_db->db_id);
+	if (status == 1) {
+		unsigned long int usec = (1000 + random()) % 100000;
+		DEBUG(DEBUG_DEBUG, (__location__ " transaction is active "
+				    "on db_id[0x%08x]. waiting for %lu "
+				    "microseconds\n",
+				    ctdb_db->db_id, usec));
+		talloc_free(tmp_ctx);
+		usleep(usec);
+		goto again;
+	}
+
+	/*
+	 * store the pid in the database:
+	 * it is not enough that the node is dmaster...
+	 */
+	pid = getpid();
+	data.dptr = (unsigned char *)&pid;
+	data.dsize = sizeof(pid_t);
+	rh->header.rsn++;
+	rh->header.dmaster = ctdb_db->ctdb->pnn;
+	ret = ctdb_ltdb_store(ctdb_db, key, &(rh->header), data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to store pid in "
+				  "transaction record\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(rh);
+
+	ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to start tdb transaction\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ret = ctdb_ltdb_fetch(ctdb_db, key, &header, tmp_ctx, &data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to re-fetch transaction "
+				 "lock record inside transaction\n"));
+		tdb_transaction_cancel(ctdb_db->ltdb->tdb);
+		talloc_free(tmp_ctx);
+		goto again;
+	}
+
+	if (header.dmaster != ctdb_db->ctdb->pnn) {
+		DEBUG(DEBUG_DEBUG,(__location__ " not dmaster any more on "
+				   "transaction lock record\n"));
+		tdb_transaction_cancel(ctdb_db->ltdb->tdb);
+		talloc_free(tmp_ctx);
+		goto again;
+	}
+
+	if ((data.dsize != sizeof(pid_t)) || (*(pid_t *)(data.dptr) != pid)) {
+		DEBUG(DEBUG_DEBUG, (__location__ " my pid is not stored in "
+				    "the transaction lock record\n"));
+		tdb_transaction_cancel(ctdb_db->ltdb->tdb);
+		talloc_free(tmp_ctx);
+		goto again;
+	}
+
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+
+/* start a transaction on a database */
+struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *ctdb_db,
+						       TALLOC_CTX *mem_ctx)
+{
+	struct ctdb_transaction_handle *h;
+	int ret;
+
+	h = talloc_zero(mem_ctx, struct ctdb_transaction_handle);
+	if (h == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " oom for transaction handle\n"));		
+		return NULL;
+	}
+
+	h->ctdb_db = ctdb_db;
+
+	ret = ctdb_transaction_fetch_start(h);
+	if (ret != 0) {
+		talloc_free(h);
+		return NULL;
+	}
+
+	talloc_set_destructor(h, ctdb_transaction_destructor);
+
+	return h;
+}
+
+
+
+/*
+  fetch a record inside a transaction
+ */
+int ctdb_transaction_fetch(struct ctdb_transaction_handle *h, 
+			   TALLOC_CTX *mem_ctx, 
+			   TDB_DATA key, TDB_DATA *data)
+{
+	struct ctdb_ltdb_header header;
+	int ret;
+
+	ZERO_STRUCT(header);
+
+	ret = ctdb_ltdb_fetch(h->ctdb_db, key, &header, mem_ctx, data);
+	if (ret == -1 && header.dmaster == (uint32_t)-1) {
+		/* record doesn't exist yet */
+		*data = tdb_null;
+		ret = 0;
+	}
+	
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (!h->in_replay) {
+		h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 1, key, NULL, *data);
+		if (h->m_all == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+  stores a record inside a transaction
+ */
+int ctdb_transaction_store(struct ctdb_transaction_handle *h, 
+			   TDB_DATA key, TDB_DATA data)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(h);
+	struct ctdb_ltdb_header header;
+	TDB_DATA olddata;
+	int ret;
+
+	ZERO_STRUCT(header);
+
+	/* we need the header so we can update the RSN */
+	ret = ctdb_ltdb_fetch(h->ctdb_db, key, &header, tmp_ctx, &olddata);
+	if (ret == -1 && header.dmaster == (uint32_t)-1) {
+		/* the record doesn't exist - create one with us as dmaster.
+		   This is only safe because we are in a transaction and this
+		   is a persistent database */
+		ZERO_STRUCT(header);
+	} else if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to fetch record\n"));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	if (data.dsize == olddata.dsize &&
+	    memcmp(data.dptr, olddata.dptr, data.dsize) == 0) {
+		/* save writing the same data */
+		talloc_free(tmp_ctx);
+		return 0;
+	}
+
+	header.dmaster = h->ctdb_db->ctdb->pnn;
+	header.rsn++;
+
+	if (!h->in_replay) {
+		h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 0, key, NULL, data);
+		if (h->m_all == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+	}		
+
+	h->m_write = ctdb_marshall_add(h, h->m_write, h->ctdb_db->db_id, 0, key, &header, data);
+	if (h->m_write == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	
+	ret = ctdb_ltdb_store(h->ctdb_db, key, &header, data);
+
+	talloc_free(tmp_ctx);
+	
+	return ret;
+}
+
+/*
+  replay a transaction
+ */
+static int ctdb_replay_transaction(struct ctdb_transaction_handle *h)
+{
+	int ret, i;
+	struct ctdb_rec_data *rec = NULL;
+
+	h->in_replay = true;
+	talloc_free(h->m_write);
+	h->m_write = NULL;
+
+	ret = ctdb_transaction_fetch_start(h);
+	if (ret != 0) {
+		return ret;
+	}
+
+	for (i=0;i<h->m_all->count;i++) {
+		TDB_DATA key, data;
+
+		rec = ctdb_marshall_loop_next(h->m_all, rec, NULL, NULL, &key, &data);
+		if (rec == NULL) {
+			DEBUG(DEBUG_ERR, (__location__ " Out of records in ctdb_replay_transaction?\n"));
+			goto failed;
+		}
+
+		if (rec->reqid == 0) {
+			/* its a store */
+			if (ctdb_transaction_store(h, key, data) != 0) {
+				goto failed;
+			}
+		} else {
+			TDB_DATA data2;
+			TALLOC_CTX *tmp_ctx = talloc_new(h);
+
+			if (ctdb_transaction_fetch(h, tmp_ctx, key, &data2) != 0) {
+				talloc_free(tmp_ctx);
+				goto failed;
+			}
+			if (data2.dsize != data.dsize ||
+			    memcmp(data2.dptr, data.dptr, data.dsize) != 0) {
+				/* the record has changed on us - we have to give up */
+				talloc_free(tmp_ctx);
+				goto failed;
+			}
+			talloc_free(tmp_ctx);
+		}
+	}
+	
+	return 0;
+
+failed:
+	tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
+	return -1;
+}
+
+
+/*
+  commit a transaction
+ */
+int ctdb_transaction_commit(struct ctdb_transaction_handle *h)
+{
+	int ret, retries=0;
+	int32_t status;
+	struct ctdb_context *ctdb = h->ctdb_db->ctdb;
+	struct timeval timeout;
+	enum ctdb_controls failure_control = CTDB_CONTROL_TRANS2_ERROR;
+
+	talloc_set_destructor(h, NULL);
+
+	/* our commit strategy is quite complex.
+
+	   - we first try to commit the changes to all other nodes
+
+	   - if that works, then we commit locally and we are done
+
+	   - if a commit on another node fails, then we need to cancel
+	     the transaction, then restart the transaction (thus
+	     opening a window of time for a pending recovery to
+	     complete), then replay the transaction, checking all the
+	     reads and writes (checking that reads give the same data,
+	     and writes succeed). Then we retry the transaction to the
+	     other nodes
+	*/
+
+again:
+	if (h->m_write == NULL) {
+		/* no changes were made */
+		tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
+		talloc_free(h);
+		return 0;
+	}
+
+	/* tell ctdbd to commit to the other nodes */
+	timeout = timeval_current_ofs(1, 0);
+	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, 
+			   retries==0?CTDB_CONTROL_TRANS2_COMMIT:CTDB_CONTROL_TRANS2_COMMIT_RETRY, 0, 
+			   ctdb_marshall_finish(h->m_write), NULL, NULL, &status, 
+			   &timeout, NULL);
+	if (ret != 0 || status != 0) {
+		tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
+		DEBUG(DEBUG_NOTICE, (__location__ " transaction commit%s failed"
+				     ", retrying after 1 second...\n",
+				     (retries==0)?"":"retry "));
+		sleep(1);
+
+		if (ret != 0) {
+			failure_control = CTDB_CONTROL_TRANS2_ERROR;
+		} else {
+			/* work out what error code we will give if we 
+			   have to fail the operation */
+			switch ((enum ctdb_trans2_commit_error)status) {
+			case CTDB_TRANS2_COMMIT_SUCCESS:
+			case CTDB_TRANS2_COMMIT_SOMEFAIL:
+			case CTDB_TRANS2_COMMIT_TIMEOUT:
+				failure_control = CTDB_CONTROL_TRANS2_ERROR;
+				break;
+			case CTDB_TRANS2_COMMIT_ALLFAIL:
+				failure_control = CTDB_CONTROL_TRANS2_FINISHED;
+				break;
+			}
+		}
+
+		if (++retries == 100) {
+			DEBUG(DEBUG_ERR,(__location__ " Giving up transaction on db 0x%08x after %d retries failure_control=%u\n", 
+					 h->ctdb_db->db_id, retries, (unsigned)failure_control));
+			ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, 
+				     failure_control, CTDB_CTRL_FLAG_NOREPLY, 
+				     tdb_null, NULL, NULL, NULL, NULL, NULL);		
+			talloc_free(h);
+			return -1;
+		}		
+
+		if (ctdb_replay_transaction(h) != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Failed to replay "
+					  "transaction on db 0x%08x, "
+					  "failure control =%u\n",
+					  h->ctdb_db->db_id,
+					  (unsigned)failure_control));
+			ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, 
+				     failure_control, CTDB_CTRL_FLAG_NOREPLY, 
+				     tdb_null, NULL, NULL, NULL, NULL, NULL);		
+			talloc_free(h);
+			return -1;
+		}
+		goto again;
+	} else {
+		failure_control = CTDB_CONTROL_TRANS2_ERROR;
+	}
+
+	/* do the real commit locally */
+	ret = tdb_transaction_commit(h->ctdb_db->ltdb->tdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to commit transaction "
+				  "on db id 0x%08x locally, "
+				  "failure_control=%u\n",
+				  h->ctdb_db->db_id,
+				  (unsigned)failure_control));
+		ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, 
+			     failure_control, CTDB_CTRL_FLAG_NOREPLY, 
+			     tdb_null, NULL, NULL, NULL, NULL, NULL);		
+		talloc_free(h);
+		return ret;
+	}
+
+	/* tell ctdbd that we are finished with our local commit */
+	ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, 
+		     CTDB_CONTROL_TRANS2_FINISHED, CTDB_CTRL_FLAG_NOREPLY, 
+		     tdb_null, NULL, NULL, NULL, NULL, NULL);
+	talloc_free(h);
+	return 0;
+}
+
+/*
+  recovery daemon ping to main daemon
+ */
+int ctdb_ctrl_recd_ping(struct ctdb_context *ctdb)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_RECD_PING, 0, tdb_null, 
+			   ctdb, NULL, &res, NULL, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send recd ping\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* when forking the main daemon and the child process needs to connect back
+ * to the daemon as a client process, this function can be used to change
+ * the ctdb context from daemon into client mode
+ */
+int switch_from_server_to_client(struct ctdb_context *ctdb, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	/* Add extra information so we can identify this in the logs */
+	va_start(ap, fmt);
+	debug_extra = talloc_strdup_append(talloc_vasprintf(NULL, fmt, ap), ":");
+	va_end(ap);
+
+	/* shutdown the transport */
+	if (ctdb->methods) {
+		ctdb->methods->shutdown(ctdb);
+	}
+
+	/* get a new event context */
+	talloc_free(ctdb->ev);
+	ctdb->ev = event_context_init(ctdb);
+	tevent_loop_allow_nesting(ctdb->ev);
+
+	close(ctdb->daemon.sd);
+	ctdb->daemon.sd = -1;
+
+	/* the client does not need to be realtime */
+	if (ctdb->do_setsched) {
+		ctdb_restore_scheduler(ctdb);
+	}
+
+	/* initialise ctdb */
+	ret = ctdb_socket_connect(ctdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ALERT, (__location__ " Failed to init ctdb client\n"));
+		return -1;
+	}
+
+	 return 0;
+}
+
+/*
+  get the status of running the monitor eventscripts: NULL means never run.
+ */
+int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb, 
+		struct timeval timeout, uint32_t destnode, 
+		TALLOC_CTX *mem_ctx, enum ctdb_eventscript_call type,
+		struct ctdb_scripts_wire **script_status)
+{
+	int ret;
+	TDB_DATA outdata, indata;
+	int32_t res;
+	uint32_t uinttype = type;
+
+	indata.dptr = (uint8_t *)&uinttype;
+	indata.dsize = sizeof(uinttype);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS, 0, indata,
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getscriptstatus failed ret:%d res:%d\n", ret, res));
+		return -1;
+	}
+
+	if (outdata.dsize == 0) {
+		*script_status = NULL;
+	} else {
+		*script_status = (struct ctdb_scripts_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+		talloc_free(outdata.dptr);
+	}
+		    
+	return 0;
+}
+
+/*
+  tell the main daemon how long it took to lock the reclock file
+ */
+int ctdb_ctrl_report_recd_lock_latency(struct ctdb_context *ctdb, struct timeval timeout, double latency)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+
+	data.dptr = (uint8_t *)&latency;
+	data.dsize = sizeof(latency);
+
+	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_RECD_RECLOCK_LATENCY, 0, data, 
+			   ctdb, NULL, &res, NULL, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send recd reclock latency\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  get the name of the reclock file
+ */
+int ctdb_ctrl_getreclock(struct ctdb_context *ctdb, struct timeval timeout,
+			 uint32_t destnode, TALLOC_CTX *mem_ctx,
+			 const char **name)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_RECLOCK_FILE, 0, tdb_null, 
+			   mem_ctx, &data, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		return -1;
+	}
+
+	if (data.dsize == 0) {
+		*name = NULL;
+	} else {
+		*name = talloc_strdup(mem_ctx, discard_const(data.dptr));
+	}
+	talloc_free(data.dptr);
+
+	return 0;
+}
+
+/*
+  set the reclock filename for a node
+ */
+int ctdb_ctrl_setreclock(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *reclock)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	if (reclock == NULL) {
+	        data.dsize = 0;
+		data.dptr  = NULL;
+	} else {
+	        data.dsize = strlen(reclock) + 1;
+		data.dptr  = discard_const(reclock);
+	}
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_RECLOCK_FILE, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setreclock failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  stop a node
+ */
+int ctdb_ctrl_stop_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_STOP_NODE, 0, tdb_null, 
+			   ctdb, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,("Failed to stop node\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  continue a node
+ */
+int ctdb_ctrl_continue_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
+{
+	int ret;
+
+	ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_CONTINUE_NODE, 0, tdb_null, 
+			   ctdb, NULL, NULL, &timeout, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to continue node\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  set the natgw state for a node
+ */
+int ctdb_ctrl_setnatgwstate(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t natgwstate)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	data.dsize = sizeof(natgwstate);
+	data.dptr  = (uint8_t *)&natgwstate;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_NATGWSTATE, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setnatgwstate failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  set the lmaster role for a node
+ */
+int ctdb_ctrl_setlmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t lmasterrole)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	data.dsize = sizeof(lmasterrole);
+	data.dptr  = (uint8_t *)&lmasterrole;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_LMASTERROLE, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setlmasterrole failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  set the recmaster role for a node
+ */
+int ctdb_ctrl_setrecmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmasterrole)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	data.dsize = sizeof(recmasterrole);
+	data.dptr  = (uint8_t *)&recmasterrole;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_RECMASTERROLE, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setrecmasterrole failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* enable an eventscript
+ */
+int ctdb_ctrl_enablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	data.dsize = strlen(script) + 1;
+	data.dptr  = discard_const(script);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_ENABLE_SCRIPT, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for enablescript failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* disable an eventscript
+ */
+int ctdb_ctrl_disablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	data.dsize = strlen(script) + 1;
+	data.dptr  = discard_const(script);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_DISABLE_SCRIPT, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for disablescript failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_ban_time *bantime)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+
+	data.dsize = sizeof(*bantime);
+	data.dptr  = (uint8_t *)bantime;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_BAN_STATE, 0, data, 
+			   NULL, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set ban state failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_ban_time **bantime)
+{
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_BAN_STATE, 0, tdb_null,
+			   tmp_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set ban state failed\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	*bantime = (struct ctdb_ban_time *)talloc_steal(mem_ctx, outdata.dptr);
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+
+int ctdb_ctrl_set_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_db_priority *db_prio)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+	data.dptr = (uint8_t*)db_prio;
+	data.dsize = sizeof(*db_prio);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_DB_PRIORITY, 0, data,
+			   tmp_ctx, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set_db_priority failed\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t db_id, uint32_t *priority)
+{
+	int ret;
+	int32_t res;
+	TDB_DATA data;
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+	data.dptr = (uint8_t*)&db_id;
+	data.dsize = sizeof(db_id);
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_DB_PRIORITY, 0, data,
+			   tmp_ctx, NULL, &res, &timeout, NULL);
+	if (ret != 0 || res < 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set_db_priority failed\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (priority) {
+		*priority = res;
+	}
+
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_statistics_wire **stats)
+{
+	int ret;
+	TDB_DATA outdata;
+	int32_t res;
+
+	ret = ctdb_control(ctdb, destnode, 0, 
+			   CTDB_CONTROL_GET_STAT_HISTORY, 0, tdb_null, 
+			   mem_ctx, &outdata, &res, &timeout, NULL);
+	if (ret != 0 || res != 0 || outdata.dsize == 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getstathistory failed ret:%d res:%d\n", ret, res));
+		return -1;
+	}
+
+	*stats = (struct ctdb_statistics_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
+	talloc_free(outdata.dptr);
+		    
+	return 0;
+}
+
+struct ctdb_ltdb_header *ctdb_header_from_record_handle(struct ctdb_record_handle *h)
+{
+	if (h == NULL) {
+		return NULL;
+	}
+
+	return &h->header;
+}
+
+
+struct ctdb_client_control_state *
+ctdb_ctrl_updaterecord_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data)
+{
+	struct ctdb_client_control_state *handle;
+	struct ctdb_marshall_buffer *m;
+	struct ctdb_rec_data *rec;
+	TDB_DATA outdata;
+
+	m = talloc_zero(mem_ctx, struct ctdb_marshall_buffer);
+	if (m == NULL) {
+		DEBUG(DEBUG_ERR, ("Failed to allocate marshall buffer for update record\n"));
+		return NULL;
+	}
+
+	m->db_id = ctdb_db->db_id;
+
+	rec = ctdb_marshall_record(m, 0, key, header, data);
+	if (rec == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to marshall record for update record\n"));
+		talloc_free(m);
+		return NULL;
+	}
+	m = talloc_realloc_size(mem_ctx, m, rec->length + offsetof(struct ctdb_marshall_buffer, data));
+	if (m == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to expand recdata\n"));
+		talloc_free(m);
+		return NULL;
+	}
+	m->count++;
+	memcpy((uint8_t *)m + offsetof(struct ctdb_marshall_buffer, data), rec, rec->length);
+
+
+	outdata.dptr = (uint8_t *)m;
+	outdata.dsize = talloc_get_size(m);
+
+	handle = ctdb_control_send(ctdb, destnode, 0, 
+			   CTDB_CONTROL_UPDATE_RECORD, 0, outdata,
+			   mem_ctx, &timeout, NULL);
+	talloc_free(m);
+	return handle;
+}
+
+int ctdb_ctrl_updaterecord_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control_recv(ctdb, state, state, NULL, &res, NULL);
+	if ( (ret != 0) || (res != 0) ){
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_update_record_recv failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data)
+{
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_ctrl_updaterecord_send(ctdb, mem_ctx, timeout, destnode, ctdb_db, key, header, data);
+	return ctdb_ctrl_updaterecord_recv(ctdb, state);
+}
+
+
+
+
+
+
+/*
+  set a database to be readonly
+ */
+struct ctdb_client_control_state *
+ctdb_ctrl_set_db_readonly_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid)
+{
+	TDB_DATA data;
+
+	data.dptr = (uint8_t *)&dbid;
+	data.dsize = sizeof(dbid);
+
+	return ctdb_control_send(ctdb, destnode, 0, 
+			   CTDB_CONTROL_SET_DB_READONLY, 0, data, 
+			   ctdb, NULL, NULL);
+}
+
+int ctdb_ctrl_set_db_readonly_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state)
+{
+	int ret;
+	int32_t res;
+
+	ret = ctdb_control_recv(ctdb, state, ctdb, NULL, &res, NULL);
+	if (ret != 0 || res != 0) {
+	  DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_set_db_readonly_recv failed  ret:%d res:%d\n", ret, res));
+		return -1;
+	}
+
+	return 0;
+}
+
+int ctdb_ctrl_set_db_readonly(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid)
+{
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_ctrl_set_db_readonly_send(ctdb, destnode, dbid);
+	return ctdb_ctrl_set_db_readonly_recv(ctdb, state);
+}

Added: branches/ctdb/squeeze-backports/common/cmdline.c
===================================================================
--- branches/ctdb/squeeze-backports/common/cmdline.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/cmdline.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,164 @@
+/* 
+   common commandline code to ctdb test tools
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "../include/ctdb_client.h"
+#include "../include/ctdb_private.h"
+#include "../common/rb_tree.h"
+#include <ctype.h>
+
+/* Handle common command line options for ctdb test progs
+ */
+
+static struct {
+	const char *socketname;
+	const char *debuglevel;
+	int torture;
+	const char *events;
+} ctdb_cmdline = {
+	.torture = 0,
+	.debuglevel = "ERR",
+};
+
+enum {OPT_EVENTSYSTEM=1};
+
+static void ctdb_cmdline_callback(poptContext con, 
+				  enum poptCallbackReason reason,
+				  const struct poptOption *opt,
+				  const char *arg, const void *data)
+{
+	switch (opt->val) {
+	case OPT_EVENTSYSTEM:
+		event_set_default_backend(arg);
+		break;
+	}
+}
+
+
+struct poptOption popt_ctdb_cmdline[] = {
+	{ NULL, 0, POPT_ARG_CALLBACK, (void *)ctdb_cmdline_callback },	
+	{ "socket", 0, POPT_ARG_STRING, &ctdb_cmdline.socketname, 0, "local socket name", "filename" },
+	{ "debug", 'd', POPT_ARG_STRING, &ctdb_cmdline.debuglevel, 0, "debug level"},
+	{ "torture", 0, POPT_ARG_NONE, &ctdb_cmdline.torture, 0, "enable nastiness in library", NULL },
+	{ "events", 0, POPT_ARG_STRING, NULL, OPT_EVENTSYSTEM, "event system", NULL },
+	{ NULL }
+};
+
+
+/*
+  startup daemon side of ctdb according to command line options
+ */
+struct ctdb_context *ctdb_cmdline_init(struct event_context *ev)
+{
+	struct ctdb_context *ctdb;
+	int ret;
+
+	/* initialise ctdb */
+	ctdb = ctdb_init(ev);
+	if (ctdb == NULL) {
+		printf("Failed to init ctdb\n");
+		exit(1);
+	}
+
+	if (ctdb_cmdline.torture) {
+		ctdb_set_flags(ctdb, CTDB_FLAG_TORTURE);
+	}
+
+	/* command line specified a socket name */
+	if (ctdb_cmdline.socketname != NULL) {
+		setenv("CTDB_SOCKET", ctdb_cmdline.socketname, 1);
+		ret = ctdb_set_socketname(ctdb, ctdb_cmdline.socketname);
+		if (ret == -1) {
+			printf("ctdb_set_socketname failed - %s\n",
+						    ctdb_errstr(ctdb));
+			exit(1);
+		}
+	}
+
+	/* Set the debug level */
+	if (isalpha(ctdb_cmdline.debuglevel[0]) || ctdb_cmdline.debuglevel[0] == '-') { 
+		LogLevel = get_debug_by_desc(ctdb_cmdline.debuglevel);
+	} else {
+		LogLevel = strtol(ctdb_cmdline.debuglevel, NULL, 0);
+	}
+
+	/* set up the tree to store server ids */
+	ctdb->server_ids = trbt_create(ctdb, 0);
+
+	return ctdb;
+}
+
+
+/*
+  startup a client only ctdb context
+ */
+struct ctdb_context *ctdb_cmdline_client(struct tevent_context *ev,
+					 struct timeval req_timeout)
+{
+	struct ctdb_context *ctdb;
+	char *socket_name;
+	int ret;
+
+	/* initialise ctdb */
+	ctdb = ctdb_init(ev);
+	if (ctdb == NULL) {
+		fprintf(stderr, "Failed to init ctdb\n");
+		exit(1);
+	}
+
+	/* tell ctdb the socket address */
+	socket_name = getenv("CTDB_SOCKET");
+	if (socket_name != NULL) {
+		ret = ctdb_set_socketname(ctdb, socket_name);
+		if (ret == -1) {
+			printf("ctdb_set_socketname failed - %s\n",
+						    ctdb_errstr(ctdb));
+			exit(1);
+		}
+	}
+
+	if (ctdb_cmdline.socketname != NULL) {
+		ret = ctdb_set_socketname(ctdb, ctdb_cmdline.socketname);
+		if (ret == -1) {
+			fprintf(stderr, "ctdb_set_socketname failed - %s\n",
+					ctdb_errstr(ctdb));
+			exit(1);
+		}
+	}
+
+	ret = ctdb_socket_connect(ctdb);
+	if (ret != 0) {
+		fprintf(stderr, __location__ " Failed to connect to daemon\n");
+		talloc_free(ctdb);
+		return NULL;
+	}
+
+	/* get our pnn */
+	ctdb->pnn = ctdb_ctrl_getpnn(ctdb, req_timeout, CTDB_CURRENT_NODE);
+	if (ctdb->pnn == (uint32_t)-1) {
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to get ctdb pnn\n"));
+		talloc_free(ctdb);
+		return NULL;
+	}
+
+	return ctdb;
+}

Added: branches/ctdb/squeeze-backports/common/ctdb_io.c
===================================================================
--- branches/ctdb/squeeze-backports/common/ctdb_io.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/ctdb_io.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,405 @@
+/* 
+   ctdb database library
+   Utility functions to read/write blobs of data from a file descriptor
+   and handle the case where we might need multiple read/writes to get all the
+   data.
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/tevent/tevent.h"
+#include "lib/util/dlinklist.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "../include/ctdb_private.h"
+#include "../include/ctdb_client.h"
+#include <stdarg.h>
+
+/* structures for packet queueing - see common/ctdb_io.c */
+struct ctdb_partial {
+	uint8_t *data;
+	uint32_t length;
+};
+
+struct ctdb_queue_pkt {
+	struct ctdb_queue_pkt *next, *prev;
+	uint8_t *data;
+	uint32_t length;
+	uint32_t full_length;
+};
+
+struct ctdb_queue {
+	struct ctdb_context *ctdb;
+	struct ctdb_partial partial; /* partial input packet */
+	struct ctdb_queue_pkt *out_queue, *out_queue_tail;
+	uint32_t out_queue_length;
+	struct fd_event *fde;
+	int fd;
+	size_t alignment;
+	void *private_data;
+	ctdb_queue_cb_fn_t callback;
+	bool *destroyed;
+	const char *name;
+};
+
+
+
+int ctdb_queue_length(struct ctdb_queue *queue)
+{
+	return queue->out_queue_length;
+}
+
+static void dump_packet(unsigned char *data, size_t len)
+{
+	size_t i;
+	char *p = talloc_array(NULL, char, len*3 + 1);
+	if (!p) {
+		DEBUG(DEBUG_CRIT,("Packet talloc fail"));
+		return;
+	}
+
+	for (i = 0; i < len; i++)
+		sprintf(p + i*3, " %02x", data[i]);
+	DEBUG(DEBUG_CRIT,("Contents: %s\n", p));
+	talloc_free(p);
+}
+
+/*
+  called when an incoming connection is readable
+  This function MUST be safe for reentry via the queue callback!
+*/
+static void queue_io_read(struct ctdb_queue *queue)
+{
+	int num_ready = 0;
+	uint32_t sz_bytes_req;
+	uint32_t pkt_size;
+	uint32_t pkt_bytes_remaining;
+	uint32_t to_read;
+	ssize_t nread;
+	uint8_t *data;
+
+	if (ioctl(queue->fd, FIONREAD, &num_ready) != 0) {
+		return;
+	}
+	if (num_ready == 0) {
+		/* the descriptor has been closed */
+		goto failed;
+	}
+
+	if (queue->partial.data == NULL) {
+		/* starting fresh, allocate buf for size bytes */
+		sz_bytes_req = sizeof(pkt_size);
+		queue->partial.data = talloc_size(queue, sz_bytes_req);
+		if (queue->partial.data == NULL) {
+			DEBUG(DEBUG_ERR,("read error alloc failed for %u\n",
+					 sz_bytes_req));
+			goto failed;
+		}
+	} else if (queue->partial.length < sizeof(pkt_size)) {
+		/* yet to find out the packet length */
+		sz_bytes_req = sizeof(pkt_size) - queue->partial.length;
+	} else {
+		/* partial packet, length known, full buf allocated */
+		sz_bytes_req = 0;
+	}
+	data = queue->partial.data;
+
+	if (sz_bytes_req > 0) {
+		to_read = MIN(sz_bytes_req, num_ready);
+		nread = read(queue->fd, data + queue->partial.length,
+			     to_read);
+		if (nread <= 0) {
+			DEBUG(DEBUG_ERR,("read error nread=%d\n", (int)nread));
+			goto failed;
+		}
+		queue->partial.length += nread;
+
+		if (nread < sz_bytes_req) {
+			/* not enough to know the length */
+			DEBUG(DEBUG_DEBUG,("Partial packet length read\n"));
+			return;
+		}
+		/* size now known, allocate buffer for the full packet */
+		queue->partial.data = talloc_realloc_size(queue, data,
+							  *(uint32_t *)data);
+		if (queue->partial.data == NULL) {
+			DEBUG(DEBUG_ERR,("read error alloc failed for %u\n",
+					 *(uint32_t *)data));
+			goto failed;
+		}
+		data = queue->partial.data;
+		num_ready -= nread;
+	}
+
+	pkt_size = *(uint32_t *)data;
+	if (pkt_size == 0) {
+		DEBUG(DEBUG_CRIT,("Invalid packet of length 0\n"));
+		goto failed;
+	}
+
+	pkt_bytes_remaining = pkt_size - queue->partial.length;
+	to_read = MIN(pkt_bytes_remaining, num_ready);
+	nread = read(queue->fd, data + queue->partial.length,
+		     to_read);
+	if (nread <= 0) {
+		DEBUG(DEBUG_ERR,("read error nread=%d\n",
+				 (int)nread));
+		goto failed;
+	}
+	queue->partial.length += nread;
+
+	if (queue->partial.length < pkt_size) {
+		DEBUG(DEBUG_DEBUG,("Partial packet data read\n"));
+		return;
+	}
+
+	queue->partial.data = NULL;
+	queue->partial.length = 0;
+	/* it is the responsibility of the callback to free 'data' */
+	queue->callback(data, pkt_size, queue->private_data);
+	return;
+
+failed:
+	queue->callback(NULL, 0, queue->private_data);
+}
+
+
+/* used when an event triggers a dead queue */
+static void queue_dead(struct event_context *ev, struct timed_event *te, 
+		       struct timeval t, void *private_data)
+{
+	struct ctdb_queue *queue = talloc_get_type(private_data, struct ctdb_queue);
+	queue->callback(NULL, 0, queue->private_data);
+}
+
+
+/*
+  called when an incoming connection is writeable
+*/
+static void queue_io_write(struct ctdb_queue *queue)
+{
+	while (queue->out_queue) {
+		struct ctdb_queue_pkt *pkt = queue->out_queue;
+		ssize_t n;
+		if (queue->ctdb->flags & CTDB_FLAG_TORTURE) {
+			n = write(queue->fd, pkt->data, 1);
+		} else {
+			n = write(queue->fd, pkt->data, pkt->length);
+		}
+
+		if (n == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
+			if (pkt->length != pkt->full_length) {
+				/* partial packet sent - we have to drop it */
+				DLIST_REMOVE(queue->out_queue, pkt);
+				queue->out_queue_length--;
+				talloc_free(pkt);
+			}
+			talloc_free(queue->fde);
+			queue->fde = NULL;
+			queue->fd = -1;
+			event_add_timed(queue->ctdb->ev, queue, timeval_zero(), 
+					queue_dead, queue);
+			return;
+		}
+		if (n <= 0) return;
+		
+		if (n != pkt->length) {
+			pkt->length -= n;
+			pkt->data += n;
+			return;
+		}
+
+		DLIST_REMOVE(queue->out_queue, pkt);
+		queue->out_queue_length--;
+		talloc_free(pkt);
+	}
+
+	EVENT_FD_NOT_WRITEABLE(queue->fde);
+}
+
+/*
+  called when an incoming connection is readable or writeable
+*/
+static void queue_io_handler(struct event_context *ev, struct fd_event *fde, 
+			     uint16_t flags, void *private_data)
+{
+	struct ctdb_queue *queue = talloc_get_type(private_data, struct ctdb_queue);
+
+	if (flags & EVENT_FD_READ) {
+		queue_io_read(queue);
+	} else {
+		queue_io_write(queue);
+	}
+}
+
+
+/*
+  queue a packet for sending
+*/
+int ctdb_queue_send(struct ctdb_queue *queue, uint8_t *data, uint32_t length)
+{
+	struct ctdb_queue_pkt *pkt;
+	uint32_t length2, full_length;
+
+	if (queue->alignment) {
+		/* enforce the length and alignment rules from the tcp packet allocator */
+		length2 = (length+(queue->alignment-1)) & ~(queue->alignment-1);
+		*(uint32_t *)data = length2;
+	} else {
+		length2 = length;
+	}
+
+	if (length2 != length) {
+		memset(data+length, 0, length2-length);
+	}
+
+	full_length = length2;
+	
+	/* if the queue is empty then try an immediate write, avoiding
+	   queue overhead. This relies on non-blocking sockets */
+	if (queue->out_queue == NULL && queue->fd != -1 &&
+	    !(queue->ctdb->flags & CTDB_FLAG_TORTURE)) {
+		ssize_t n = write(queue->fd, data, length2);
+		if (n == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
+			talloc_free(queue->fde);
+			queue->fde = NULL;
+			queue->fd = -1;
+			event_add_timed(queue->ctdb->ev, queue, timeval_zero(), 
+					queue_dead, queue);
+			/* yes, we report success, as the dead node is 
+			   handled via a separate event */
+			return 0;
+		}
+		if (n > 0) {
+			data += n;
+			length2 -= n;
+		}
+		if (length2 == 0) return 0;
+	}
+
+	pkt = talloc(queue, struct ctdb_queue_pkt);
+	CTDB_NO_MEMORY(queue->ctdb, pkt);
+
+	pkt->data = talloc_memdup(pkt, data, length2);
+	CTDB_NO_MEMORY(queue->ctdb, pkt->data);
+
+	pkt->length = length2;
+	pkt->full_length = full_length;
+
+	if (queue->out_queue == NULL && queue->fd != -1) {
+		EVENT_FD_WRITEABLE(queue->fde);
+	}
+
+	DLIST_ADD_END(queue->out_queue, pkt, NULL);
+
+	queue->out_queue_length++;
+
+	if (queue->ctdb->tunable.verbose_memory_names != 0) {
+		struct ctdb_req_header *hdr = (struct ctdb_req_header *)pkt->data;
+		switch (hdr->operation) {
+		case CTDB_REQ_CONTROL: {
+			struct ctdb_req_control *c = (struct ctdb_req_control *)hdr;
+			talloc_set_name(pkt, "ctdb_queue_pkt: %s control opcode=%u srvid=%llu datalen=%u",
+					queue->name, (unsigned)c->opcode, (unsigned long long)c->srvid, (unsigned)c->datalen);
+			break;
+		}
+		case CTDB_REQ_MESSAGE: {
+			struct ctdb_req_message *m = (struct ctdb_req_message *)hdr;
+			talloc_set_name(pkt, "ctdb_queue_pkt: %s message srvid=%llu datalen=%u",
+					queue->name, (unsigned long long)m->srvid, (unsigned)m->datalen);
+			break;
+		}
+		default:
+			talloc_set_name(pkt, "ctdb_queue_pkt: %s operation=%u length=%u src=%u dest=%u",
+					queue->name, (unsigned)hdr->operation, (unsigned)hdr->length,
+					(unsigned)hdr->srcnode, (unsigned)hdr->destnode);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+  setup the fd used by the queue
+ */
+int ctdb_queue_set_fd(struct ctdb_queue *queue, int fd)
+{
+	queue->fd = fd;
+	talloc_free(queue->fde);
+	queue->fde = NULL;
+
+	if (fd != -1) {
+		queue->fde = event_add_fd(queue->ctdb->ev, queue, fd, EVENT_FD_READ,
+					  queue_io_handler, queue);
+		if (queue->fde == NULL) {
+			return -1;
+		}
+		tevent_fd_set_auto_close(queue->fde);
+
+		if (queue->out_queue) {
+			EVENT_FD_WRITEABLE(queue->fde);		
+		}
+	}
+
+	return 0;
+}
+
+/* If someone sets up this pointer, they want to know if the queue is freed */
+static int queue_destructor(struct ctdb_queue *queue)
+{
+	if (queue->destroyed != NULL)
+		*queue->destroyed = true;
+	return 0;
+}
+
+/*
+  setup a packet queue on a socket
+ */
+struct ctdb_queue *ctdb_queue_setup(struct ctdb_context *ctdb,
+				    TALLOC_CTX *mem_ctx, int fd, int alignment,
+				    
+				    ctdb_queue_cb_fn_t callback,
+				    void *private_data, const char *fmt, ...)
+{
+	struct ctdb_queue *queue;
+	va_list ap;
+
+	queue = talloc_zero(mem_ctx, struct ctdb_queue);
+	CTDB_NO_MEMORY_NULL(ctdb, queue);
+	va_start(ap, fmt);
+	queue->name = talloc_vasprintf(mem_ctx, fmt, ap);
+	va_end(ap);
+	CTDB_NO_MEMORY_NULL(ctdb, queue->name);
+
+	queue->ctdb = ctdb;
+	queue->fd = fd;
+	queue->alignment = alignment;
+	queue->private_data = private_data;
+	queue->callback = callback;
+	if (fd != -1) {
+		if (ctdb_queue_set_fd(queue, fd) != 0) {
+			talloc_free(queue);
+			return NULL;
+		}
+	}
+	talloc_set_destructor(queue, queue_destructor);
+
+	return queue;
+}

Added: branches/ctdb/squeeze-backports/common/ctdb_logging.c
===================================================================
--- branches/ctdb/squeeze-backports/common/ctdb_logging.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/ctdb_logging.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,186 @@
+/* 
+   ctdb logging code
+
+   Copyright (C) Ronnie Sahlberg 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/time.h"
+#include "../include/ctdb_private.h"
+#include "../include/ctdb_client.h"
+
+int log_ringbuf_size;
+
+#define MAX_LOG_SIZE 128
+
+static int first_entry;
+static int last_entry;
+
+struct ctdb_log_entry {
+	int32_t level;
+	struct timeval t;
+	char message[MAX_LOG_SIZE];
+};
+
+
+static struct ctdb_log_entry *log_entries;
+
+/*
+ * this function logs all messages for all levels to a ringbuffer
+ */
+static void log_ringbuffer_v(const char *format, va_list ap)
+{
+	int ret;
+
+	if (log_entries == NULL && log_ringbuf_size != 0) {
+		/* Hope this works. We cant log anything if it doesnt anyway */
+		log_entries = malloc(sizeof(struct ctdb_log_entry) * log_ringbuf_size);
+	}
+	if (log_entries == NULL) {
+		return;
+	}
+
+	log_entries[last_entry].message[0] = '\0';
+
+	ret = vsnprintf(&log_entries[last_entry].message[0], MAX_LOG_SIZE, format, ap);
+	if (ret == -1) {
+		return;
+	}
+
+	log_entries[last_entry].level = this_log_level;
+	log_entries[last_entry].t = timeval_current();
+
+	last_entry++;
+	if (last_entry >= log_ringbuf_size) {
+		last_entry = 0;
+	}
+	if (first_entry == last_entry) {
+		first_entry++;
+	}
+	if (first_entry >= log_ringbuf_size) {
+		first_entry = 0;
+	}
+}
+
+void log_ringbuffer(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	log_ringbuffer_v(format, ap);
+	va_end(ap);
+}
+
+
+
+static void ctdb_collect_log(struct ctdb_context *ctdb, struct ctdb_get_log_addr *log_addr)
+{
+	TDB_DATA data;
+	FILE *f;
+	long fsize;
+	int tmp_entry;
+	int count = 0;
+	DEBUG(DEBUG_ERR,("Marshalling log entries  first:%d last:%d\n", first_entry, last_entry));
+
+	/* dump to a file, then send the file as a blob */
+	f = tmpfile();
+	if (f == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Unable to open tmpfile - %s\n", strerror(errno)));
+		return;
+	}
+
+	tmp_entry = first_entry;
+	while (tmp_entry != last_entry) {
+		struct tm *tm;
+		char tbuf[100];
+
+		if (log_entries == NULL) {
+			break;
+		}
+
+		if (log_entries[tmp_entry].level > log_addr->level) {
+			tmp_entry++;
+			if (tmp_entry >= log_ringbuf_size) {
+				tmp_entry = 0;
+			}
+		 	continue;
+		}
+
+		tm = localtime(&log_entries[tmp_entry].t.tv_sec);
+		strftime(tbuf, sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
+
+		if (log_entries[tmp_entry].message) {
+			count += fprintf(f, "%s:%s %s", tbuf, get_debug_by_level(log_entries[tmp_entry].level), log_entries[tmp_entry].message);
+		}
+
+		tmp_entry++;
+		if (tmp_entry >= log_ringbuf_size) {
+			tmp_entry = 0;
+		}
+	}
+
+	fsize = ftell(f);
+	rewind(f);
+	data.dptr = talloc_size(NULL, fsize);
+	CTDB_NO_MEMORY_VOID(ctdb, data.dptr);
+	data.dsize = fread(data.dptr, 1, fsize, f);
+	fclose(f);
+
+	DEBUG(DEBUG_ERR,("Marshalling log entries into a blob of %d bytes\n", (int)data.dsize));
+
+	DEBUG(DEBUG_ERR,("Send log to %d:%d\n", (int)log_addr->pnn, (int)log_addr->srvid));
+	ctdb_client_send_message(ctdb, log_addr->pnn, log_addr->srvid, data);
+
+	talloc_free(data.dptr);
+}
+
+int32_t ctdb_control_get_log(struct ctdb_context *ctdb, TDB_DATA addr)
+{
+	struct ctdb_get_log_addr *log_addr = (struct ctdb_get_log_addr *)addr.dptr;
+	pid_t child;
+
+	/* spawn a child process to marshall the huge log blob and send it back
+	   to the ctdb tool using a MESSAGE
+	*/
+	child = ctdb_fork(ctdb);
+	if (child == (pid_t)-1) {
+		DEBUG(DEBUG_ERR,("Failed to fork a log collector child\n"));
+		return -1;
+	}
+
+	if (child == 0) {
+		if (switch_from_server_to_client(ctdb, "log-collector") != 0) {
+			DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch log collector child into client mode.\n"));
+			_exit(1);
+		}
+		ctdb_collect_log(ctdb, log_addr);
+		_exit(0);
+	}
+
+	return 0;
+}
+
+
+int32_t ctdb_control_clear_log(struct ctdb_context *ctdb)
+{
+	first_entry = 0;
+	last_entry  = 0;
+
+	return 0;
+}
+

Added: branches/ctdb/squeeze-backports/common/ctdb_ltdb.c
===================================================================
--- branches/ctdb/squeeze-backports/common/ctdb_ltdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/ctdb_ltdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,298 @@
+/* 
+   ctdb ltdb code
+
+   Copyright (C) Andrew Tridgell  2006
+   Copyright (C) Ronnie sahlberg  2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "../include/ctdb_private.h"
+#include "db_wrap.h"
+#include "lib/util/dlinklist.h"
+
+/*
+  find an attached ctdb_db handle given a name
+ */
+struct ctdb_db_context *ctdb_db_handle(struct ctdb_context *ctdb, const char *name)
+{
+	struct ctdb_db_context *tmp_db;
+	for (tmp_db=ctdb->db_list;tmp_db;tmp_db=tmp_db->next) {
+		if (strcmp(name, tmp_db->db_name) == 0) {
+			return tmp_db;
+		}
+	}
+	return NULL;
+}
+
+
+/*
+  return the lmaster given a key
+*/
+uint32_t ctdb_lmaster(struct ctdb_context *ctdb, const TDB_DATA *key)
+{
+	uint32_t idx, lmaster;
+
+	idx = ctdb_hash(key) % ctdb->vnn_map->size;
+	lmaster = ctdb->vnn_map->map[idx];
+
+	return lmaster;
+}
+
+
+/*
+  construct an initial header for a record with no ltdb header yet
+*/
+static void ltdb_initial_header(struct ctdb_db_context *ctdb_db, 
+				TDB_DATA key,
+				struct ctdb_ltdb_header *header)
+{
+	ZERO_STRUCTP(header);
+	/* initial dmaster is the lmaster */
+	header->dmaster = ctdb_lmaster(ctdb_db->ctdb, &key);
+	header->flags = CTDB_REC_FLAG_AUTOMATIC;
+}
+
+
+/*
+  fetch a record from the ltdb, separating out the header information
+  and returning the body of the record. A valid (initial) header is
+  returned if the record is not present
+*/
+int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db, 
+		    TDB_DATA key, struct ctdb_ltdb_header *header, 
+		    TALLOC_CTX *mem_ctx, TDB_DATA *data)
+{
+	TDB_DATA rec;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+
+	rec = tdb_fetch(ctdb_db->ltdb->tdb, key);
+	if (rec.dsize < sizeof(*header)) {
+		TDB_DATA d2;
+		/* return an initial header */
+		if (rec.dptr) free(rec.dptr);
+		if (ctdb->vnn_map == NULL) {
+			/* called from the client */
+			ZERO_STRUCTP(data);
+			header->dmaster = (uint32_t)-1;
+			return -1;
+		}
+		ltdb_initial_header(ctdb_db, key, header);
+		ZERO_STRUCT(d2);
+		if (data) {
+			*data = d2;
+		}
+		ctdb_ltdb_store(ctdb_db, key, header, d2);
+		return 0;
+	}
+
+	*header = *(struct ctdb_ltdb_header *)rec.dptr;
+
+	if (data) {
+		data->dsize = rec.dsize - sizeof(struct ctdb_ltdb_header);
+		data->dptr = talloc_memdup(mem_ctx, 
+					   sizeof(struct ctdb_ltdb_header)+rec.dptr,
+					   data->dsize);
+	}
+
+	free(rec.dptr);
+	if (data) {
+		CTDB_NO_MEMORY(ctdb, data->dptr);
+	}
+
+	return 0;
+}
+
+/*
+  fetch a record from the ltdb, separating out the header information
+  and returning the body of the record.
+  if the record does not exist, *header will be NULL
+  and data = {0, NULL}
+*/
+int ctdb_ltdb_fetch_with_header(struct ctdb_db_context *ctdb_db, 
+		    TDB_DATA key, struct ctdb_ltdb_header *header, 
+		    TALLOC_CTX *mem_ctx, TDB_DATA *data)
+{
+	TDB_DATA rec;
+
+	rec = tdb_fetch(ctdb_db->ltdb->tdb, key);
+	if (rec.dsize < sizeof(*header)) {
+		free(rec.dptr);
+
+		data->dsize = 0;
+		data->dptr = NULL;
+		return -1;
+	}
+
+	*header = *(struct ctdb_ltdb_header *)rec.dptr;
+	if (data) {
+		data->dsize = rec.dsize - sizeof(struct ctdb_ltdb_header);
+		data->dptr = talloc_memdup(mem_ctx, 
+					   sizeof(struct ctdb_ltdb_header)+rec.dptr,
+					   data->dsize);
+	}
+
+	free(rec.dptr);
+
+	return 0;
+}
+
+
+/*
+  write a record to a normal database
+*/
+int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, 
+		    struct ctdb_ltdb_header *header, TDB_DATA data)
+{
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	TDB_DATA rec;
+	int ret;
+	bool seqnum_suppressed = false;
+
+	if (ctdb_db->ctdb_ltdb_store_fn) {
+		return ctdb_db->ctdb_ltdb_store_fn(ctdb_db, key, header, data);
+	}
+
+	if (ctdb->flags & CTDB_FLAG_TORTURE) {
+		struct ctdb_ltdb_header *h2;
+		rec = tdb_fetch(ctdb_db->ltdb->tdb, key);
+		h2 = (struct ctdb_ltdb_header *)rec.dptr;
+		if (rec.dptr && rec.dsize >= sizeof(h2) && h2->rsn > header->rsn) {
+			DEBUG(DEBUG_CRIT,("RSN regression! %llu %llu\n",
+				 (unsigned long long)h2->rsn, (unsigned long long)header->rsn));
+		}
+		if (rec.dptr) free(rec.dptr);
+	}
+
+	rec.dsize = sizeof(*header) + data.dsize;
+	rec.dptr = talloc_size(ctdb, rec.dsize);
+	CTDB_NO_MEMORY(ctdb, rec.dptr);
+
+	memcpy(rec.dptr, header, sizeof(*header));
+	memcpy(rec.dptr + sizeof(*header), data.dptr, data.dsize);
+
+	/* Databases with seqnum updates enabled only get their seqnum
+	   changes when/if we modify the data */
+	if (ctdb_db->seqnum_update != NULL) {
+		TDB_DATA old;
+		old = tdb_fetch(ctdb_db->ltdb->tdb, key);
+
+		if ( (old.dsize == rec.dsize)
+		&& !memcmp(old.dptr+sizeof(struct ctdb_ltdb_header),
+			  rec.dptr+sizeof(struct ctdb_ltdb_header),
+			  rec.dsize-sizeof(struct ctdb_ltdb_header)) ) {
+			tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_SEQNUM);
+			seqnum_suppressed = true;
+		}
+		if (old.dptr) free(old.dptr);
+	}
+	ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to store dynamic data\n"));
+	}
+	if (seqnum_suppressed) {
+		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_SEQNUM);
+	}
+
+	talloc_free(rec.dptr);
+
+	return ret;
+}
+
+/*
+  lock a record in the ltdb, given a key
+ */
+int ctdb_ltdb_lock(struct ctdb_db_context *ctdb_db, TDB_DATA key)
+{
+	return tdb_chainlock(ctdb_db->ltdb->tdb, key);
+}
+
+/*
+  unlock a record in the ltdb, given a key
+ */
+int ctdb_ltdb_unlock(struct ctdb_db_context *ctdb_db, TDB_DATA key)
+{
+	int ret = tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+	if (ret != 0) {
+ 		DEBUG(DEBUG_ERR,("tdb_chainunlock failed on db %s [%s]\n", ctdb_db->db_name, tdb_errorstr(ctdb_db->ltdb->tdb)));
+	}
+	return ret;
+}
+
+
+/*
+  delete a record from a normal database
+*/
+int ctdb_ltdb_delete(struct ctdb_db_context *ctdb_db, TDB_DATA key)
+{
+	if (ctdb_db->persistent != 0) {
+		DEBUG(DEBUG_ERR,("Trying to delete emty record in persistent database\n"));
+		return 0;
+	}
+	if (tdb_delete(ctdb_db->ltdb->tdb, key) != 0) {
+		DEBUG(DEBUG_ERR,("Failed to delete empty record."));
+		return -1;
+	}
+	return 0;
+}
+
+int ctdb_trackingdb_add_pnn(struct ctdb_context *ctdb, TDB_DATA *data, uint32_t pnn)
+{
+	int byte_pos = pnn / 8;
+	int bit_mask   = 1 << (pnn % 8);
+
+	if (byte_pos + 1 > data->dsize) {
+		char *buf;
+
+		buf = malloc(byte_pos + 1);
+		memset(buf, 0, byte_pos + 1);
+		if (buf == NULL) {
+			DEBUG(DEBUG_ERR, ("Out of memory when allocating buffer of %d bytes for trackingdb\n", byte_pos + 1));
+			return -1;
+		}
+		if (data->dptr != NULL) {
+			memcpy(buf, data->dptr, data->dsize);
+			free(data->dptr);
+		}
+		data->dptr  = (uint8_t *)buf;
+		data->dsize = byte_pos + 1;
+	}
+
+	data->dptr[byte_pos] |= bit_mask;
+	return 0;
+}
+
+void ctdb_trackingdb_traverse(struct ctdb_context *ctdb, TDB_DATA data, ctdb_trackingdb_cb cb, void *private_data)
+{
+	int i;
+
+	for(i = 0; i < data.dsize; i++) {
+		int j;
+
+		for (j=0; j<8; j++) {
+			int mask = 1<<j;
+
+			if (data.dptr[i] & mask) {
+				cb(ctdb, i * 8 + j, private_data);
+			}
+		}
+	}
+}
+
+

Added: branches/ctdb/squeeze-backports/common/ctdb_message.c
===================================================================
--- branches/ctdb/squeeze-backports/common/ctdb_message.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/ctdb_message.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,112 @@
+/* 
+   ctdb_message protocol code
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+  see http://wiki.samba.org/index.php/Samba_%26_Clustering for
+  protocol design and packet details
+*/
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "../include/ctdb_private.h"
+#include "lib/util/dlinklist.h"
+
+/*
+  this dispatches the messages to the registered ctdb message handler
+*/
+int ctdb_dispatch_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data)
+{
+	struct ctdb_message_list *ml;
+
+	for (ml=ctdb->message_list;ml;ml=ml->next) {
+		if (ml->srvid == srvid || ml->srvid == CTDB_SRVID_ALL) {
+			ml->message_handler(ctdb, srvid, data, ml->message_private);
+		}
+	}
+
+	return 0;
+}
+
+/*
+  called when a CTDB_REQ_MESSAGE packet comes in
+*/
+void ctdb_request_message(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_req_message *c = (struct ctdb_req_message *)hdr;
+	TDB_DATA data;
+
+	data.dsize = c->datalen;
+	data.dptr = talloc_memdup(c, &c->data[0], c->datalen);
+
+	ctdb_dispatch_message(ctdb, c->srvid, data);
+}
+
+
+/*
+  when a client goes away, we need to remove its srvid handler from the list
+ */
+static int message_handler_destructor(struct ctdb_message_list *m)
+{
+	DLIST_REMOVE(m->ctdb->message_list, m);
+	return 0;
+}
+
+/*
+  setup handler for receipt of ctdb messages from ctdb_send_message()
+*/
+int ctdb_register_message_handler(struct ctdb_context *ctdb, 
+				  TALLOC_CTX *mem_ctx,
+				  uint64_t srvid,
+				  ctdb_msg_fn_t handler,
+				  void *private_data)
+{
+	struct ctdb_message_list *m;
+
+	m = talloc(mem_ctx, struct ctdb_message_list);
+	CTDB_NO_MEMORY(ctdb, m);
+
+	m->ctdb            = ctdb;
+	m->srvid           = srvid;
+	m->message_handler = handler;
+	m->message_private = private_data;
+	
+	DLIST_ADD(ctdb->message_list, m);
+
+	talloc_set_destructor(m, message_handler_destructor);
+
+	return 0;
+}
+
+
+/*
+  setup handler for receipt of ctdb messages from ctdb_send_message()
+*/
+int ctdb_deregister_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data)
+{
+	struct ctdb_message_list *m;
+
+	for (m=ctdb->message_list;m;m=m->next) {
+		if (m->srvid == srvid && m->message_private == private_data) {
+			talloc_free(m);
+			return 0;
+		}
+	}
+	return -1;
+}

Added: branches/ctdb/squeeze-backports/common/ctdb_util.c
===================================================================
--- branches/ctdb/squeeze-backports/common/ctdb_util.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/ctdb_util.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,687 @@
+/* 
+   ctdb utility code
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "system/shmem.h"
+#include "../include/ctdb_private.h"
+
+int LogLevel = DEBUG_NOTICE;
+int this_log_level = 0;
+
+/*
+  return error string for last error
+*/
+const char *ctdb_errstr(struct ctdb_context *ctdb)
+{
+	return ctdb->err_msg;
+}
+
+
+/*
+  remember an error message
+*/
+void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...)
+{
+	va_list ap;
+	talloc_free(ctdb->err_msg);
+	va_start(ap, fmt);
+	ctdb->err_msg = talloc_vasprintf(ctdb, fmt, ap);
+	DEBUG(DEBUG_ERR,("ctdb error: %s\n", ctdb->err_msg));
+	va_end(ap);
+}
+
+/*
+  a fatal internal error occurred - no hope for recovery
+*/
+void ctdb_fatal(struct ctdb_context *ctdb, const char *msg)
+{
+	DEBUG(DEBUG_ALERT,("ctdb fatal error: %s\n", msg));
+	abort();
+}
+
+/*
+  parse a IP:port pair
+*/
+int ctdb_parse_address(struct ctdb_context *ctdb,
+		       TALLOC_CTX *mem_ctx, const char *str,
+		       struct ctdb_address *address)
+{
+	struct servent *se;
+
+	setservent(0);
+	se = getservbyname("ctdb", "tcp");
+	endservent();
+	
+	address->address = talloc_strdup(mem_ctx, str);
+	CTDB_NO_MEMORY(ctdb, address->address);
+
+	if (se == NULL) {
+		address->port = CTDB_PORT;
+	} else {
+		address->port = ntohs(se->s_port);
+	}
+	return 0;
+}
+
+
+/*
+  check if two addresses are the same
+*/
+bool ctdb_same_address(struct ctdb_address *a1, struct ctdb_address *a2)
+{
+	return strcmp(a1->address, a2->address) == 0 && a1->port == a2->port;
+}
+
+
+/*
+  hash function for mapping data to a VNN - taken from tdb
+*/
+uint32_t ctdb_hash(const TDB_DATA *key)
+{
+	return tdb_jenkins_hash(discard_const(key));
+}
+
+/*
+  a type checking varient of idr_find
+ */
+static void *_idr_find_type(struct idr_context *idp, int id, const char *type, const char *location)
+{
+	void *p = idr_find(idp, id);
+	if (p && talloc_check_name(p, type) == NULL) {
+		DEBUG(DEBUG_ERR,("%s idr_find_type expected type %s  but got %s\n",
+			 location, type, talloc_get_name(p)));
+		return NULL;
+	}
+	return p;
+}
+
+uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state)
+{
+	int id = idr_get_new_above(ctdb->idr, state, ctdb->lastid+1, INT_MAX);
+	if (id < 0) {
+		DEBUG(DEBUG_DEBUG, ("Reqid wrap!\n"));
+		id = idr_get_new(ctdb->idr, state, INT_MAX);
+	}
+	ctdb->lastid = id;
+	return id;
+}
+
+void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location)
+{
+	void *p;
+
+	p = _idr_find_type(ctdb->idr, reqid, type, location);
+	if (p == NULL) {
+		DEBUG(DEBUG_WARNING, ("Could not find idr:%u\n",reqid));
+	}
+
+	return p;
+}
+
+
+void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid)
+{
+	int ret;
+
+	ret = idr_remove(ctdb->idr, reqid);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Removing idr that does not exist\n"));
+	}
+}
+
+
+/*
+  form a ctdb_rec_data record from a key/data pair
+  
+  note that header may be NULL. If not NULL then it is included in the data portion
+  of the record
+ */
+struct ctdb_rec_data *ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid,	
+					   TDB_DATA key, 
+					   struct ctdb_ltdb_header *header,
+					   TDB_DATA data)
+{
+	size_t length;
+	struct ctdb_rec_data *d;
+
+	length = offsetof(struct ctdb_rec_data, data) + key.dsize + 
+		data.dsize + (header?sizeof(*header):0);
+	d = (struct ctdb_rec_data *)talloc_size(mem_ctx, length);
+	if (d == NULL) {
+		return NULL;
+	}
+	d->length = length;
+	d->reqid = reqid;
+	d->keylen = key.dsize;
+	memcpy(&d->data[0], key.dptr, key.dsize);
+	if (header) {
+		d->datalen = data.dsize + sizeof(*header);
+		memcpy(&d->data[key.dsize], header, sizeof(*header));
+		memcpy(&d->data[key.dsize+sizeof(*header)], data.dptr, data.dsize);
+	} else {
+		d->datalen = data.dsize;
+		memcpy(&d->data[key.dsize], data.dptr, data.dsize);
+	}
+	return d;
+}
+
+
+/* helper function for marshalling multiple records */
+struct ctdb_marshall_buffer *ctdb_marshall_add(TALLOC_CTX *mem_ctx, 
+					       struct ctdb_marshall_buffer *m,
+					       uint64_t db_id,
+					       uint32_t reqid,
+					       TDB_DATA key,
+					       struct ctdb_ltdb_header *header,
+					       TDB_DATA data)
+{
+	struct ctdb_rec_data *r;
+	size_t m_size, r_size;
+	struct ctdb_marshall_buffer *m2;
+
+	r = ctdb_marshall_record(mem_ctx, reqid, key, header, data);
+	if (r == NULL) {
+		talloc_free(m);
+		return NULL;
+	}
+
+	if (m == NULL) {
+		m = talloc_zero_size(mem_ctx, offsetof(struct ctdb_marshall_buffer, data));
+		if (m == NULL) {
+			return NULL;
+		}
+		m->db_id = db_id;
+	}
+
+	m_size = talloc_get_size(m);
+	r_size = talloc_get_size(r);
+
+	m2 = talloc_realloc_size(mem_ctx, m,  m_size + r_size);
+	if (m2 == NULL) {
+		talloc_free(m);
+		return NULL;
+	}
+
+	memcpy(m_size + (uint8_t *)m2, r, r_size);
+
+	talloc_free(r);
+
+	m2->count++;
+
+	return m2;
+}
+
+/* we've finished marshalling, return a data blob with the marshalled records */
+TDB_DATA ctdb_marshall_finish(struct ctdb_marshall_buffer *m)
+{
+	TDB_DATA data;
+	data.dptr = (uint8_t *)m;
+	data.dsize = talloc_get_size(m);
+	return data;
+}
+
+/* 
+   loop over a marshalling buffer 
+   
+     - pass r==NULL to start
+     - loop the number of times indicated by m->count
+*/
+struct ctdb_rec_data *ctdb_marshall_loop_next(struct ctdb_marshall_buffer *m, struct ctdb_rec_data *r,
+					      uint32_t *reqid,
+					      struct ctdb_ltdb_header *header,
+					      TDB_DATA *key, TDB_DATA *data)
+{
+	if (r == NULL) {
+		r = (struct ctdb_rec_data *)&m->data[0];
+	} else {
+		r = (struct ctdb_rec_data *)(r->length + (uint8_t *)r);
+	}
+
+	if (reqid != NULL) {
+		*reqid = r->reqid;
+	}
+	
+	if (key != NULL) {
+		key->dptr   = &r->data[0];
+		key->dsize  = r->keylen;
+	}
+	if (data != NULL) {
+		data->dptr  = &r->data[r->keylen];
+		data->dsize = r->datalen;
+		if (header != NULL) {
+			data->dptr += sizeof(*header);
+			data->dsize -= sizeof(*header);
+		}
+	}
+
+	if (header != NULL) {
+		if (r->datalen < sizeof(*header)) {
+			return NULL;
+		}
+		*header = *(struct ctdb_ltdb_header *)&r->data[r->keylen];
+	}
+
+	return r;
+}
+
+
+#if HAVE_SCHED_H
+#include <sched.h>
+#endif
+
+/*
+  if possible, make this task real time
+ */
+void ctdb_set_scheduler(struct ctdb_context *ctdb)
+{
+#if HAVE_SCHED_SETSCHEDULER	
+	struct sched_param p;
+	if (ctdb->saved_scheduler_param == NULL) {
+		ctdb->saved_scheduler_param = talloc_size(ctdb, sizeof(p));
+	}
+	
+	if (sched_getparam(0, (struct sched_param *)ctdb->saved_scheduler_param) == -1) {
+		DEBUG(DEBUG_ERR,("Unable to get old scheduler params\n"));
+		return;
+	}
+
+	p = *(struct sched_param *)ctdb->saved_scheduler_param;
+	p.sched_priority = 1;
+
+	if (sched_setscheduler(0, SCHED_FIFO, &p) == -1) {
+		DEBUG(DEBUG_CRIT,("Unable to set scheduler to SCHED_FIFO (%s)\n", 
+			 strerror(errno)));
+	} else {
+		DEBUG(DEBUG_NOTICE,("Set scheduler to SCHED_FIFO\n"));
+	}
+#endif
+}
+
+/*
+  restore previous scheduler parameters
+ */
+void ctdb_restore_scheduler(struct ctdb_context *ctdb)
+{
+#if HAVE_SCHED_SETSCHEDULER	
+	if (ctdb->saved_scheduler_param == NULL) {
+		ctdb_fatal(ctdb, "No saved scheduler parameters\n");
+	}
+	if (sched_setscheduler(0, SCHED_OTHER, (struct sched_param *)ctdb->saved_scheduler_param) == -1) {
+		ctdb_fatal(ctdb, "Unable to restore old scheduler parameters\n");
+	}
+#endif
+}
+
+/*
+ * This function forks a child process and drops the realtime 
+ * scheduler for the child process.
+ */
+pid_t ctdb_fork(struct ctdb_context *ctdb)
+{
+	pid_t pid;
+
+	pid = fork();
+	if (pid == 0) {
+		if (ctdb->do_setsched) {
+			ctdb_restore_scheduler(ctdb);
+		}
+	}
+	return pid;
+}
+
+void set_nonblocking(int fd)
+{
+	unsigned v;
+	v = fcntl(fd, F_GETFL, 0);
+        fcntl(fd, F_SETFL, v | O_NONBLOCK);
+}
+
+void set_close_on_exec(int fd)
+{
+	unsigned v;
+	v = fcntl(fd, F_GETFD, 0);
+        fcntl(fd, F_SETFD, v | FD_CLOEXEC);
+}
+
+
+bool parse_ipv4(const char *s, unsigned port, struct sockaddr_in *sin)
+{
+	sin->sin_family = AF_INET;
+	sin->sin_port   = htons(port);
+
+	if (inet_pton(AF_INET, s, &sin->sin_addr) != 1) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to translate %s into sin_addr\n", s));
+		return false;
+	}
+
+	return true;
+}
+
+static bool parse_ipv6(const char *s, const char *ifaces, unsigned port, ctdb_sock_addr *saddr)
+{
+	saddr->ip6.sin6_family   = AF_INET6;
+	saddr->ip6.sin6_port     = htons(port);
+	saddr->ip6.sin6_flowinfo = 0;
+	saddr->ip6.sin6_scope_id = 0;
+
+	if (inet_pton(AF_INET6, s, &saddr->ip6.sin6_addr) != 1) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to translate %s into sin6_addr\n", s));
+		return false;
+	}
+
+	if (ifaces && IN6_IS_ADDR_LINKLOCAL(&saddr->ip6.sin6_addr)) {
+		if (strchr(ifaces, ',')) {
+			DEBUG(DEBUG_ERR, (__location__ " Link local address %s "
+					  "is specified for multiple ifaces %s\n",
+					  s, ifaces));
+			return false;
+		}
+		saddr->ip6.sin6_scope_id = if_nametoindex(ifaces);
+	}
+
+	return true;
+}
+/*
+  parse a ip:port pair
+ */
+bool parse_ip_port(const char *addr, ctdb_sock_addr *saddr)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	char *s, *p;
+	unsigned port;
+	char *endp = NULL;
+	bool ret;
+
+	s = talloc_strdup(tmp_ctx, addr);
+	if (s == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed strdup()\n"));
+		talloc_free(tmp_ctx);
+		return false;
+	}
+
+	p = rindex(s, ':');
+	if (p == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " This addr: %s does not contain a port number\n", s));
+		talloc_free(tmp_ctx);
+		return false;
+	}
+
+	port = strtoul(p+1, &endp, 10);
+	if (endp == NULL || *endp != 0) {
+		/* trailing garbage */
+		DEBUG(DEBUG_ERR, (__location__ " Trailing garbage after the port in %s\n", s));
+		talloc_free(tmp_ctx);
+		return false;
+	}
+	*p = 0;
+
+
+	/* now is this a ipv4 or ipv6 address ?*/
+	ret = parse_ip(s, NULL, port, saddr);
+
+	talloc_free(tmp_ctx);
+	return ret;
+}
+
+/*
+  parse an ip
+ */
+bool parse_ip(const char *addr, const char *ifaces, unsigned port, ctdb_sock_addr *saddr)
+{
+	char *p;
+	bool ret;
+
+	/* now is this a ipv4 or ipv6 address ?*/
+	p = index(addr, ':');
+	if (p == NULL) {
+		ret = parse_ipv4(addr, port, &saddr->ip);
+	} else {
+		ret = parse_ipv6(addr, ifaces, port, saddr);
+	}
+
+	return ret;
+}
+
+/*
+  parse a ip/mask pair
+ */
+bool parse_ip_mask(const char *str, const char *ifaces, ctdb_sock_addr *addr, unsigned *mask)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	char *s, *p;
+	char *endp = NULL;
+	bool ret;
+
+	ZERO_STRUCT(*addr);
+	s = talloc_strdup(tmp_ctx, str);
+	if (s == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed strdup()\n"));
+		talloc_free(tmp_ctx);
+		return false;
+	}
+
+	p = rindex(s, '/');
+	if (p == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " This addr: %s does not contain a mask\n", s));
+		talloc_free(tmp_ctx);
+		return false;
+	}
+
+	*mask = strtoul(p+1, &endp, 10);
+	if (endp == NULL || *endp != 0) {
+		/* trailing garbage */
+		DEBUG(DEBUG_ERR, (__location__ " Trailing garbage after the mask in %s\n", s));
+		talloc_free(tmp_ctx);
+		return false;
+	}
+	*p = 0;
+
+
+	/* now is this a ipv4 or ipv6 address ?*/
+	ret = parse_ip(s, ifaces, 0, addr);
+
+	talloc_free(tmp_ctx);
+	return ret;
+}
+
+/*
+   This is used to canonicalize a ctdb_sock_addr structure.
+*/
+void ctdb_canonicalize_ip(const ctdb_sock_addr *ip, ctdb_sock_addr *cip)
+{
+	char prefix[12] = { 0,0,0,0,0,0,0,0,0,0,0xff,0xff };
+
+	memcpy(cip, ip, sizeof (*cip));
+
+	if ( (ip->sa.sa_family == AF_INET6)
+	&& !memcmp(&ip->ip6.sin6_addr, prefix, 12)) {
+		memset(cip, 0, sizeof(*cip));
+#ifdef HAVE_SOCK_SIN_LEN
+		cip->ip.sin_len = sizeof(*cip);
+#endif
+		cip->ip.sin_family = AF_INET;
+		cip->ip.sin_port   = ip->ip6.sin6_port;
+		memcpy(&cip->ip.sin_addr, &ip->ip6.sin6_addr.s6_addr32[3], 4);
+	}
+}
+
+bool ctdb_same_ip(const ctdb_sock_addr *tip1, const ctdb_sock_addr *tip2)
+{
+	ctdb_sock_addr ip1, ip2;
+
+	ctdb_canonicalize_ip(tip1, &ip1);
+	ctdb_canonicalize_ip(tip2, &ip2);
+	
+	if (ip1.sa.sa_family != ip2.sa.sa_family) {
+		return false;
+	}
+
+	switch (ip1.sa.sa_family) {
+	case AF_INET:
+		return ip1.ip.sin_addr.s_addr == ip2.ip.sin_addr.s_addr;
+	case AF_INET6:
+		return !memcmp(&ip1.ip6.sin6_addr.s6_addr[0],
+				&ip2.ip6.sin6_addr.s6_addr[0],
+				16);
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " CRITICAL Can not compare sockaddr structures of type %u\n", ip1.sa.sa_family));
+		return false;
+	}
+
+	return true;
+}
+
+/*
+  compare two ctdb_sock_addr structures
+ */
+bool ctdb_same_sockaddr(const ctdb_sock_addr *ip1, const ctdb_sock_addr *ip2)
+{
+	return ctdb_same_ip(ip1, ip2) && ip1->ip.sin_port == ip2->ip.sin_port;
+}
+
+char *ctdb_addr_to_str(ctdb_sock_addr *addr)
+{
+	static char cip[128] = "";
+
+	switch (addr->sa.sa_family) {
+	case AF_INET:
+		inet_ntop(addr->ip.sin_family, &addr->ip.sin_addr, cip, sizeof(cip));
+		break;
+	case AF_INET6:
+		inet_ntop(addr->ip6.sin6_family, &addr->ip6.sin6_addr, cip, sizeof(cip));
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family %u\n", addr->sa.sa_family));
+	}
+
+	return cip;
+}
+
+unsigned ctdb_addr_to_port(ctdb_sock_addr *addr)
+{
+	switch (addr->sa.sa_family) {
+	case AF_INET:
+		return ntohs(addr->ip.sin_port);
+		break;
+	case AF_INET6:
+		return ntohs(addr->ip6.sin6_port);
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family %u\n", addr->sa.sa_family));
+	}
+
+	return 0;
+}
+
+void ctdb_block_signal(int signum)
+{
+	sigset_t set;
+	sigemptyset(&set);
+	sigaddset(&set,signum);
+	sigprocmask(SIG_BLOCK,&set,NULL);
+}
+
+void ctdb_unblock_signal(int signum)
+{
+	sigset_t set;
+	sigemptyset(&set);
+	sigaddset(&set,signum);
+	sigprocmask(SIG_UNBLOCK,&set,NULL);
+}
+
+struct debug_levels debug_levels[] = {
+	{DEBUG_EMERG,	"EMERG"},
+	{DEBUG_ALERT,	"ALERT"},
+	{DEBUG_CRIT,	"CRIT"},
+	{DEBUG_ERR,	"ERR"},
+	{DEBUG_WARNING,	"WARNING"},
+	{DEBUG_NOTICE,	"NOTICE"},
+	{DEBUG_INFO,	"INFO"},
+	{DEBUG_DEBUG,	"DEBUG"},
+	{0, NULL}
+};
+
+const char *get_debug_by_level(int32_t level)
+{
+	int i;
+
+	for (i=0; debug_levels[i].description != NULL; i++) {
+		if (debug_levels[i].level == level) {
+			return debug_levels[i].description;
+		}
+	}
+	return "Unknown";
+}
+
+int32_t get_debug_by_desc(const char *desc)
+{
+	int i;
+
+	for (i=0; debug_levels[i].description != NULL; i++) {
+		if (!strcmp(debug_levels[i].description, desc)) {
+			return debug_levels[i].level;
+		}
+	}
+
+	return DEBUG_ERR;
+}
+
+/* we don't lock future pages here; it would increase the chance that
+ * we'd fail to mmap later on. */
+void ctdb_lockdown_memory(struct ctdb_context *ctdb)
+{
+#ifdef HAVE_MLOCKALL
+	/* Extra stack, please! */
+	char dummy[10000];
+	memset(dummy, 0, sizeof(dummy));
+
+	if (ctdb->valgrinding) {
+		return;
+	}
+
+	/* Avoid compiler optimizing out dummy. */
+	mlock(dummy, sizeof(dummy));
+	if (mlockall(MCL_CURRENT) != 0) {
+		DEBUG(DEBUG_WARNING,("Failed to lock memory: %s'\n",
+				     strerror(errno)));
+	}
+#endif
+}
+
+const char *ctdb_eventscript_call_names[] = {
+	"init",
+	"setup",
+	"startup",
+	"startrecovery",
+	"recovered",
+	"takeip",
+	"releaseip",
+	"stopped",
+	"monitor",
+	"status",
+	"shutdown",
+	"reload",
+	"updateip",
+	"ipreallocated"
+};

Added: branches/ctdb/squeeze-backports/common/rb_tree.c
===================================================================
--- branches/ctdb/squeeze-backports/common/rb_tree.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/rb_tree.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1073 @@
+/* 
+   a talloc based red-black tree
+
+   Copyright (C) Ronnie Sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "rb_tree.h"
+
+#define NO_MEMORY_FATAL(p) do { if (!(p)) { \
+          DEBUG(DEBUG_CRIT,("Out of memory for %s at %s\n", #p, __location__)); \
+	  exit(10); \
+	  }} while (0)
+
+
+static void 
+tree_destructor_traverse_node(TALLOC_CTX *mem_ctx, trbt_node_t *node)
+{
+	talloc_set_destructor(node, NULL);
+	if (node->left) {
+		tree_destructor_traverse_node(mem_ctx, node->left);
+	}
+	if (node->right) {
+		tree_destructor_traverse_node(mem_ctx, node->right);
+	}
+	talloc_steal(mem_ctx, node);
+}
+
+/*
+  destroy a tree and remove all its nodes
+ */
+static int tree_destructor(trbt_tree_t *tree)
+{
+	TALLOC_CTX *tmp_ctx;
+	trbt_node_t *node;
+
+	if (tree == NULL) {
+		return 0;
+	}
+
+	node=tree->root;
+	if (node == NULL) {
+		return 0;
+	}
+
+	/* traverse the tree and remove the node destructor and steal
+	   the node to the temporary context.
+	   we dont want to use the existing destructor for the node
+	   since that will remove the nodes one by one from the tree.
+	   since the entire tree will be completely destroyed we dont care
+	   if it is inconsistent or unbalanced while freeing the
+	   individual nodes
+	*/
+	tmp_ctx = talloc_new(NULL);
+	tree_destructor_traverse_node(tmp_ctx, node);
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+
+/* create a red black tree */
+trbt_tree_t *
+trbt_create(TALLOC_CTX *memctx, uint32_t flags)
+{
+	trbt_tree_t *tree;
+
+	tree = talloc_zero(memctx, trbt_tree_t);
+	NO_MEMORY_FATAL(tree);
+
+	/* If the tree is freed, we must walk over all entries and steal the
+	   node from the stored data pointer and release the node.
+	   Note, when we free the tree  we only free the tree and not any of 
+	   the data stored in the tree.
+	*/
+	talloc_set_destructor(tree, tree_destructor);
+	tree->flags = flags;
+
+	return tree;
+}
+
+static inline trbt_node_t *
+trbt_parent(trbt_node_t *node)
+{
+	return node->parent;
+}
+
+static inline trbt_node_t *
+trbt_grandparent(trbt_node_t *node)
+{
+	trbt_node_t *parent;
+
+	parent=trbt_parent(node);
+	if(parent){
+		return parent->parent;
+	}
+	return NULL;
+}
+
+static inline trbt_node_t *
+trbt_uncle(trbt_node_t *node)
+{
+	trbt_node_t *parent, *grandparent;
+
+	parent=trbt_parent(node);
+	if(!parent){
+		return NULL;
+	}
+	grandparent=trbt_parent(parent);
+	if(!grandparent){
+		return NULL;
+	}
+	if(parent==grandparent->left){
+		return grandparent->right;
+	}
+	return grandparent->left;
+}
+
+
+static inline void trbt_insert_case1(trbt_tree_t *tree, trbt_node_t *node);
+static inline void trbt_insert_case2(trbt_tree_t *tree, trbt_node_t *node);
+
+static inline void
+trbt_rotate_left(trbt_node_t *node)
+{
+	trbt_tree_t *tree = node->tree;
+
+	if(node->parent){
+		if(node->parent->left==node){
+			node->parent->left=node->right;
+		} else {
+			node->parent->right=node->right;
+		}
+	} else {
+		tree->root=node->right;
+	}
+	node->right->parent=node->parent;
+	node->parent=node->right;
+	node->right=node->right->left;
+	if(node->right){
+		node->right->parent=node;
+	}
+	node->parent->left=node;
+}
+
+static inline void
+trbt_rotate_right(trbt_node_t *node)
+{
+	trbt_tree_t *tree = node->tree;
+
+	if(node->parent){
+		if(node->parent->left==node){
+			node->parent->left=node->left;
+		} else {
+			node->parent->right=node->left;
+		}
+	} else {
+		tree->root=node->left;
+	}
+	node->left->parent=node->parent;
+	node->parent=node->left;
+	node->left=node->left->right;
+	if(node->left){
+		node->left->parent=node;
+	}
+	node->parent->right=node;
+}
+
+/* NULL nodes are black by definition */
+static inline int trbt_get_color(trbt_node_t *node)
+{
+	if (node==NULL) {
+		return TRBT_BLACK;
+	}
+	return node->rb_color;
+}
+static inline int trbt_get_color_left(trbt_node_t *node)
+{
+	if (node==NULL) {
+		return TRBT_BLACK;
+	}
+	if (node->left==NULL) {
+		return TRBT_BLACK;
+	}
+	return node->left->rb_color;
+}
+static inline int trbt_get_color_right(trbt_node_t *node)
+{
+	if (node==NULL) {
+		return TRBT_BLACK;
+	}
+	if (node->right==NULL) {
+		return TRBT_BLACK;
+	}
+	return node->right->rb_color;
+}
+/* setting a NULL node to black is a nop */
+static inline void trbt_set_color(trbt_node_t *node, int color)
+{
+	if ( (node==NULL) && (color==TRBT_BLACK) ) {
+		return;
+	}
+	node->rb_color = color;
+}
+static inline void trbt_set_color_left(trbt_node_t *node, int color)
+{
+	if ( ((node==NULL)||(node->left==NULL)) && (color==TRBT_BLACK) ) {
+		return;
+	}
+	node->left->rb_color = color;
+}
+static inline void trbt_set_color_right(trbt_node_t *node, int color)
+{
+	if ( ((node==NULL)||(node->right==NULL)) && (color==TRBT_BLACK) ) {
+		return;
+	}
+	node->right->rb_color = color;
+}
+
+static inline void
+trbt_insert_case5(trbt_tree_t *tree, trbt_node_t *node)
+{
+	trbt_node_t *grandparent;
+	trbt_node_t *parent;
+
+	parent=trbt_parent(node);
+	grandparent=trbt_parent(parent);
+	parent->rb_color=TRBT_BLACK;
+	grandparent->rb_color=TRBT_RED;
+	if( (node==parent->left) && (parent==grandparent->left) ){
+		trbt_rotate_right(grandparent);
+	} else {
+		trbt_rotate_left(grandparent);
+	}
+}
+
+static inline void
+trbt_insert_case4(trbt_tree_t *tree, trbt_node_t *node)
+{
+	trbt_node_t *grandparent;
+	trbt_node_t *parent;
+
+	parent=trbt_parent(node);
+	grandparent=trbt_parent(parent);
+	if(!grandparent){
+		return;
+	}
+	if( (node==parent->right) && (parent==grandparent->left) ){
+		trbt_rotate_left(parent);
+		node=node->left;
+	} else if( (node==parent->left) && (parent==grandparent->right) ){
+		trbt_rotate_right(parent);
+		node=node->right;
+	}
+	trbt_insert_case5(tree, node);
+}
+
+static inline void
+trbt_insert_case3(trbt_tree_t *tree, trbt_node_t *node)
+{
+	trbt_node_t *grandparent;
+	trbt_node_t *parent;
+	trbt_node_t *uncle;
+
+	uncle=trbt_uncle(node);
+	if(uncle && (uncle->rb_color==TRBT_RED)){
+		parent=trbt_parent(node);
+		parent->rb_color=TRBT_BLACK;
+		uncle->rb_color=TRBT_BLACK;
+		grandparent=trbt_grandparent(node);
+		grandparent->rb_color=TRBT_RED;
+		trbt_insert_case1(tree, grandparent);
+	} else {
+		trbt_insert_case4(tree, node);
+	}
+}
+
+static inline void
+trbt_insert_case2(trbt_tree_t *tree, trbt_node_t *node)
+{
+	trbt_node_t *parent;
+
+	parent=trbt_parent(node);
+	/* parent is always non-NULL here */
+	if(parent->rb_color==TRBT_BLACK){
+		return;
+	}
+	trbt_insert_case3(tree, node);
+}
+
+static inline void
+trbt_insert_case1(trbt_tree_t *tree, trbt_node_t *node)
+{
+	trbt_node_t *parent;
+
+	parent=trbt_parent(node);
+	if(!parent){
+		node->rb_color=TRBT_BLACK;
+		return;
+	}
+	trbt_insert_case2(tree, node);
+}
+
+static inline trbt_node_t *
+trbt_sibling(trbt_node_t *node)
+{
+	trbt_node_t *parent;
+
+	parent=trbt_parent(node);
+	if(!parent){
+		return NULL;
+	}
+
+	if (node == parent->left) {
+		return parent->right;
+	} else {
+		return parent->left;
+	}
+}
+
+static inline void
+trbt_delete_case6(trbt_node_t *node)
+{
+	trbt_node_t *sibling, *parent;
+
+	sibling = trbt_sibling(node);
+	parent  = trbt_parent(node);
+
+	trbt_set_color(sibling, parent->rb_color);
+	trbt_set_color(parent, TRBT_BLACK);
+	if (node == parent->left) {
+		trbt_set_color_right(sibling, TRBT_BLACK);
+		trbt_rotate_left(parent);
+	} else {
+		trbt_set_color_left(sibling, TRBT_BLACK);
+		trbt_rotate_right(parent);
+	}
+}
+
+
+static inline void
+trbt_delete_case5(trbt_node_t *node)
+{
+	trbt_node_t *parent, *sibling;
+
+	parent = trbt_parent(node);
+	sibling = trbt_sibling(node);
+	if ( (node == parent->left)
+	   &&(trbt_get_color(sibling)        == TRBT_BLACK)
+	   &&(trbt_get_color_left(sibling)   == TRBT_RED)
+	   &&(trbt_get_color_right(sibling)  == TRBT_BLACK) ){
+		trbt_set_color(sibling, TRBT_RED);
+		trbt_set_color_left(sibling, TRBT_BLACK);
+		trbt_rotate_right(sibling);
+		trbt_delete_case6(node);
+		return;
+	} 
+	if ( (node == parent->right)
+	   &&(trbt_get_color(sibling)        == TRBT_BLACK)
+	   &&(trbt_get_color_right(sibling)  == TRBT_RED)
+	   &&(trbt_get_color_left(sibling)   == TRBT_BLACK) ){
+		trbt_set_color(sibling, TRBT_RED);
+		trbt_set_color_right(sibling, TRBT_BLACK);
+		trbt_rotate_left(sibling);
+		trbt_delete_case6(node);
+		return;
+	}
+
+	trbt_delete_case6(node);
+}
+
+static inline void
+trbt_delete_case4(trbt_node_t *node)
+{
+	trbt_node_t *sibling;
+
+	sibling = trbt_sibling(node);
+	if ( (trbt_get_color(node->parent)   == TRBT_RED)
+	   &&(trbt_get_color(sibling)        == TRBT_BLACK)
+	   &&(trbt_get_color_left(sibling)   == TRBT_BLACK)
+	   &&(trbt_get_color_right(sibling)  == TRBT_BLACK) ){
+		trbt_set_color(sibling, TRBT_RED);
+		trbt_set_color(node->parent, TRBT_BLACK);
+	} else {
+		trbt_delete_case5(node);
+	}
+}
+
+static void trbt_delete_case1(trbt_node_t *node);
+
+static inline void
+trbt_delete_case3(trbt_node_t *node)
+{
+	trbt_node_t *sibling;
+
+	sibling = trbt_sibling(node);
+	if ( (trbt_get_color(node->parent)   == TRBT_BLACK)
+	   &&(trbt_get_color(sibling)        == TRBT_BLACK)
+	   &&(trbt_get_color_left(sibling)   == TRBT_BLACK)
+	   &&(trbt_get_color_right(sibling)  == TRBT_BLACK) ){
+		trbt_set_color(sibling, TRBT_RED);
+		trbt_delete_case1(node->parent);
+	} else {
+		trbt_delete_case4(node);
+	}
+}
+	
+static inline void
+trbt_delete_case2(trbt_node_t *node)
+{
+	trbt_node_t *sibling;
+
+	sibling = trbt_sibling(node);
+	if (trbt_get_color(sibling) == TRBT_RED) {
+		trbt_set_color(node->parent, TRBT_RED);
+		trbt_set_color(sibling, TRBT_BLACK);
+		if (node == node->parent->left) {
+			trbt_rotate_left(node->parent);
+		} else {
+			trbt_rotate_right(node->parent);
+		}
+	}
+	trbt_delete_case3(node);
+}	
+
+static void
+trbt_delete_case1(trbt_node_t *node)
+{
+	if (!node->parent) {
+		return;
+	} else {
+		trbt_delete_case2(node);
+	}
+}
+
+static void
+delete_node(trbt_node_t *node, BOOL from_destructor)
+{
+	trbt_node_t *parent, *child, dc;
+	trbt_node_t *temp = NULL;
+
+	/* This node has two child nodes, then just copy the content
+	   from the next smaller node with this node and delete the 
+	   predecessor instead.
+	   The predecessor is guaranteed to have at most one child
+	   node since its right arm must be NULL
+	   (It must be NULL since we are its sucessor and we are above
+	    it in the tree)
+	 */
+	if (node->left != NULL && node->right != NULL) {
+		/* This node has two children, just copy the data */
+		/* find the predecessor */
+		temp = node->left;
+
+		while (temp->right != NULL) {
+			temp = temp->right;
+		}
+
+		/* swap the predecessor data and key with the node to
+		   be deleted.
+		 */
+		node->key32 = temp->key32;
+		node->data  = temp->data;
+		/* now we let node hang off the new data */
+		talloc_steal(node->data, node);
+	
+		temp->data  = NULL;
+		temp->key32 = -1;
+		/* then delete the temp node.
+		   this node is guaranteed to have at least one leaf 
+		   child */
+		delete_node(temp, from_destructor);
+		goto finished;
+	}
+
+
+	/* There is at most one child to this node to be deleted */
+	child = node->left;
+	if (node->right) {
+		child = node->right;
+	}
+
+	/* If the node to be deleted did not have any child at all we
+	   create a temporary dummy node for the child and mark it black.
+	   Once the delete of the node is finished, we remove this dummy
+	   node, which is simple to do since it is guaranteed that it will
+	   still not have any children after the delete operation.
+	   This is because we dont represent the leaf-nodes as actual nodes
+	   in this implementation.
+	 */
+	if (!child) {
+		child = &dc;
+		child->tree = node->tree;
+		child->left=NULL;
+		child->right=NULL;
+		child->rb_color=TRBT_BLACK;
+		child->data=NULL;
+	}
+
+	/* replace node with child */
+	parent = trbt_parent(node);
+	if (parent) {
+		if (parent->left == node) {
+			parent->left = child;
+		} else {
+			parent->right = child;
+		}
+	} else {
+		node->tree->root = child;
+	}
+	child->parent = node->parent;
+
+
+	if (node->rb_color == TRBT_BLACK) {
+		if (trbt_get_color(child) == TRBT_RED) {
+			child->rb_color = TRBT_BLACK;
+		} else {
+			trbt_delete_case1(child);
+		}
+	}
+
+	/* If we had to create a temporary dummy node to represent a black 
+	   leaf child we now has to delete it.
+	   This is simple since this dummy node originally had no children
+	   and we are guaranteed that it will also not have any children 
+	   after the node has been deleted and any possible rotations 
+	   have occured.
+
+	   The only special case is if this was the last node of the tree
+	   in which case we have to reset the root to NULL as well.
+	   Othervise it is enough to just unlink the child from its new
+	   parent.
+	 */
+	if (child == &dc) {
+		if (child->parent == NULL) {
+			node->tree->root = NULL;
+		} else if (child == child->parent->left) {
+			child->parent->left = NULL;
+		} else {
+			child->parent->right = NULL;
+		}
+	}
+
+finished:
+	if (!from_destructor) {
+		talloc_free(node);
+	}
+
+	/* if we came from a destructor and temp!=NULL  this means we
+	   did the node-swap but now the tree still contains the old
+	   node  which was freed in the destructor. Not good.
+	*/
+	if (from_destructor && temp) {
+		temp->key32    = node->key32;
+		temp->rb_color = node->rb_color;
+
+		temp->data = node->data;
+		talloc_steal(temp->data, temp);
+
+		temp->parent = node->parent;
+		if (temp->parent) {
+			if (temp->parent->left == node) {
+				temp->parent->left = temp;
+			} else {
+				temp->parent->right = temp;
+			}
+		}
+
+		temp->left = node->left;
+		if (temp->left) {
+			temp->left->parent = temp;
+		}
+		temp->right = node->right;
+		if (temp->right) {
+			temp->right->parent = temp;
+		}
+
+		if (temp->tree->root == node) {
+			temp->tree->root = temp;
+		}
+	}
+
+	if ( (node->tree->flags & TRBT_AUTOFREE)
+	&&   (node->tree->root == NULL) ) {
+		talloc_free(node->tree);
+	}
+
+	return;
+}
+
+/*
+  destroy a node and remove it from its tree
+ */
+static int node_destructor(trbt_node_t *node)
+{
+	delete_node(node, True);
+
+	return 0;
+}
+
+static inline trbt_node_t *
+trbt_create_node(trbt_tree_t *tree, trbt_node_t *parent, uint32_t key, void *data)
+{
+	trbt_node_t *node;
+
+	node=talloc_zero(tree, trbt_node_t);
+	NO_MEMORY_FATAL(node);
+
+	node->tree=tree;
+	node->rb_color=TRBT_BLACK;
+	node->parent=parent;
+	node->left=NULL;
+	node->right=NULL;
+	node->key32=key;
+	node->data = data;
+
+	/* let this node hang off data so that it is removed when
+	   data is freed
+	 */
+	talloc_steal(data, node);
+	talloc_set_destructor(node, node_destructor);
+
+	return node;
+}
+
+/* insert a new node in the tree. 
+   if there is already a node with a matching key in the tree 
+   we replace it with the new data and return a pointer to the old data
+   in case the caller wants to take any special action
+ */
+void *
+trbt_insert32(trbt_tree_t *tree, uint32_t key, void *data)
+{
+	trbt_node_t *node;
+
+	node=tree->root;
+
+	/* is this the first node ?*/
+	if(!node){
+		node = trbt_create_node(tree, NULL, key, data);
+
+		tree->root=node;
+		return NULL;
+	}
+
+	/* it was not the new root so walk the tree until we find where to
+	 * insert this new leaf.
+	 */
+	while(1){
+		/* this node already exists, replace data and return the 
+		   old data
+		 */
+		if(key==node->key32){
+			void *old_data;
+
+			old_data = node->data;
+			node->data  = data;
+			/* Let the node now be owned by the new data
+			   so the node is freed when the enw data is released
+			*/
+			talloc_steal(node->data, node);
+
+			return old_data;
+		}
+		if(key<node->key32) {
+			if(!node->left){
+				/* new node to the left */
+				trbt_node_t *new_node;
+
+				new_node = trbt_create_node(tree, node, key, data);
+				node->left=new_node;
+				node=new_node;
+
+				break;
+			}
+			node=node->left;
+			continue;
+		}
+		if(key>node->key32) {
+			if(!node->right){
+				/* new node to the right */
+				trbt_node_t *new_node;
+
+				new_node = trbt_create_node(tree, node, key, data);
+				node->right=new_node;
+				node=new_node;
+				break;
+			}
+			node=node->right;
+			continue;
+		}
+	}
+
+	/* node will now point to the newly created node */
+	node->rb_color=TRBT_RED;
+	trbt_insert_case1(tree, node);
+	return NULL;
+}
+
+void *
+trbt_lookup32(trbt_tree_t *tree, uint32_t key)
+{
+	trbt_node_t *node;
+
+	node=tree->root;
+
+	while(node){
+		if(key==node->key32){
+			return node->data;
+		}
+		if(key<node->key32){
+			node=node->left;
+			continue;
+		}
+		if(key>node->key32){
+			node=node->right;
+			continue;
+		}
+	}
+	return NULL;
+}
+
+
+/* This deletes a node from the tree.
+   Note that this does not release the data that the node points to
+*/
+void 
+trbt_delete32(trbt_tree_t *tree, uint32_t key)
+{
+	trbt_node_t *node;
+
+	node=tree->root;
+
+	while(node){
+		if(key==node->key32){
+			delete_node(node, False);
+			return;
+		}
+		if(key<node->key32){
+			node=node->left;
+			continue;
+		}
+		if(key>node->key32){
+			node=node->right;
+			continue;
+		}
+	}
+}
+
+
+void 
+trbt_insert32_callback(trbt_tree_t *tree, uint32_t key, void *(*callback)(void *param, void *data), void *param)
+{
+	trbt_node_t *node;
+
+	node=tree->root;
+
+	/* is this the first node ?*/
+	if(!node){
+		node = trbt_create_node(tree, NULL, key, 
+				callback(param, NULL));
+
+		tree->root=node;
+		return;
+	}
+
+	/* it was not the new root so walk the tree until we find where to
+	 * insert this new leaf.
+	 */
+	while(1){
+		/* this node already exists, replace it 
+		 */
+		if(key==node->key32){
+			node->data  = callback(param, node->data);
+			talloc_steal(node->data, node); 
+
+			return;
+		}
+		if(key<node->key32) {
+			if(!node->left){
+				/* new node to the left */
+				trbt_node_t *new_node;
+
+				new_node = trbt_create_node(tree, node, key,
+						callback(param, NULL));
+				node->left=new_node;
+				node=new_node;
+
+				break;
+			}
+			node=node->left;
+			continue;
+		}
+		if(key>node->key32) {
+			if(!node->right){
+				/* new node to the right */
+				trbt_node_t *new_node;
+
+				new_node = trbt_create_node(tree, node, key,
+						callback(param, NULL));
+				node->right=new_node;
+				node=new_node;
+				break;
+			}
+			node=node->right;
+			continue;
+		}
+	}
+
+	/* node will now point to the newly created node */
+	node->rb_color=TRBT_RED;
+	trbt_insert_case1(tree, node);
+	return;
+}
+
+
+struct trbt_array_param {
+	void *(*callback)(void *param, void *data);
+	void *param;
+	uint32_t keylen;
+	uint32_t *key;
+	trbt_tree_t *tree;
+};
+static void *array_insert_callback(void *p, void *data)
+{
+	struct trbt_array_param *param = (struct trbt_array_param *)p;
+	trbt_tree_t *tree = NULL;
+
+
+	/* if keylen has reached 0 we are done and can call the users 
+	   callback function with the users parameters
+	*/
+	if (param->keylen == 0) {
+		return param->callback(param->param, data);
+	}
+
+
+	/* keylen is not zero yes so we must create/process more subtrees */
+	/* if data is NULL this means we did not yet have a subtree here
+	   and we must create one.
+	*/
+	if (data == NULL) {
+		/* create a new subtree and hang it off our current tree
+		   set it to autofree so that the tree is freed when
+		   the last node in it has been released.
+		*/
+		tree = trbt_create(param->tree, TRBT_AUTOFREE);
+	} else {
+		/* we already have a subtree for this path */
+		tree = (trbt_tree_t *)data;
+	}
+		
+	trbt_insertarray32_callback(tree, param->keylen, param->key, param->callback, param->param);
+
+	/* now return either the old tree we got in *data or the new tree
+	   we created to our caller so he can update his pointer in his
+	   tree to point to our subtree
+	*/
+	return tree;
+}
+
+
+
+/* insert into the tree using an array of uint32 as a key */
+void 
+trbt_insertarray32_callback(trbt_tree_t *tree, uint32_t keylen, uint32_t *key, void *(*cb)(void *param, void *data), void *pm)
+{
+	struct trbt_array_param tap;
+
+	/* keylen-1 and key[1]  since the call to insert32 will consume the
+	   first part of the key.
+	*/
+	tap.callback= cb;
+	tap.param   = pm;
+	tap.keylen  = keylen-1;
+	tap.key     = &key[1];
+	tap.tree    = tree;
+
+	trbt_insert32_callback(tree, key[0], array_insert_callback, &tap);
+}
+
+/* lookup the tree using an array of uint32 as a key */
+void *
+trbt_lookuparray32(trbt_tree_t *tree, uint32_t keylen, uint32_t *key)
+{
+	/* if keylen is 1 we can do a regular lookup and return this to the
+	   user 
+	*/
+	if (keylen == 1) {
+		return trbt_lookup32(tree, key[0]);
+	}
+
+	/* we need to lookup the next subtree */
+	tree = trbt_lookup32(tree, key[0]);
+	if (tree == NULL) {
+		/* the key does not exist, return NULL */
+		return NULL;
+	}
+
+	/* now lookup the next part of the key in our new tree */
+	return trbt_lookuparray32(tree, keylen-1, &key[1]);
+}
+
+
+/* traverse a tree starting at node */
+static void 
+trbt_traversearray32_node(trbt_node_t *node, uint32_t keylen, 
+	void (*callback)(void *param, void *data), 
+	void *param)
+{
+	if (node->left) {
+		trbt_traversearray32_node(node->left, keylen, callback, param);
+	}
+
+	/* this is the smallest node in this subtree
+	   if keylen is 0 this means we can just call the callback
+	   otherwise we must pull the next subtree and traverse that one as well
+	*/
+	if (keylen == 0) {
+		callback(param, node->data);
+	} else {
+		trbt_traversearray32(node->data, keylen, callback, param);
+	}
+
+	if (node->right) {
+		trbt_traversearray32_node(node->right, keylen, callback, param);
+	}
+}
+	
+
+/* traverse the tree using an array of uint32 as a key */
+void 
+trbt_traversearray32(trbt_tree_t *tree, uint32_t keylen, 
+	void (*callback)(void *param, void *data), 
+	void *param)
+{
+	trbt_node_t *node;
+
+	if (tree == NULL) {
+		return;
+	}
+
+	node=tree->root;
+	if (node == NULL) {
+		return;
+	}
+
+	trbt_traversearray32_node(node, keylen-1, callback, param);
+}
+
+
+/* this function will return the first node in a tree where
+   the key is an array of uint32_t
+*/
+void *
+trbt_findfirstarray32(trbt_tree_t *tree, uint32_t keylen)
+{
+	trbt_node_t *node;
+
+	if (keylen < 1) {
+		return NULL;
+	}
+	
+	if (tree == NULL) {
+		return NULL;
+	}
+
+	node=tree->root;
+	if (node == NULL) {
+		return NULL;
+	}
+
+	while (node->left) {
+		node = node->left;
+	}
+
+	/* we found our node so return the data */
+	if (keylen == 1) {
+		return node->data;
+	}
+
+	/* we are still traversing subtrees so find the first node in the
+	   next level of trees
+	*/
+	return trbt_findfirstarray32(node->data, keylen-1);
+}
+
+
+#if 0
+static void printtree(trbt_node_t *node, int levels)
+{
+	int i;
+	if(node==NULL)return;
+	printtree(node->left, levels+1);
+
+	for(i=0;i<levels;i++)printf("    ");
+	printf("key:%d COLOR:%s (node:0x%08x parent:0x%08x left:0x%08x right:0x%08x)\n",node->key32,node->rb_color==TRBT_BLACK?"BLACK":"RED",(int)node,(int)node->parent, (int)node->left,(int)node->right);
+
+	printtree(node->right, levels+1);
+	printf("\n");
+}
+
+void print_tree(trbt_tree_t *tree)
+{
+	if(tree->root==NULL){
+		printf("tree is empty\n");
+		return;
+	}
+	printf("---\n");
+	printtree(tree->root->left, 1);
+	printf("root node key:%d COLOR:%s (node:0x%08x left:0x%08x right:0x%08x)\n",tree->root->key32,tree->root->rb_color==TRBT_BLACK?"BLACK":"RED",(int)tree->root,(int)tree->root->left,(int)tree->root->right);
+	printtree(tree->root->right, 1);
+	printf("===\n");
+}
+#endif
+
+# if 0
+void 
+test_tree(void)
+{
+	trbt_tree_t *tree;
+	char *str;
+	int i, ret;
+	int NUM=15;
+	int cnt=0;
+
+	tree=trbt_create(talloc_new(NULL));
+#if 0
+	for(i=0;i<10;i++){
+		printf("adding node %i\n",i);
+		trbt_insert32(tree, i, NULL);
+		print_tree(tree);
+	}
+	printf("deleting node %i\n",3);
+	trbt_delete32(tree, 3);
+	print_tree(tree);
+	for(i=0;i<10;i++){
+		printf("deleting node %i\n",i);
+		trbt_delete32(tree, i);
+		print_tree(tree);
+	}
+exit(0);
+#endif
+	while(++cnt){
+		int i;
+		printf("iteration : %d\n",cnt);
+		i=random()%20;
+		printf("adding node %i\n",i);
+		trbt_insert32(tree, i, NULL);
+		print_tree(tree);
+
+		i=random()%20;
+		printf("deleting node %i\n",i);
+		trbt_delete32(tree, i);
+		print_tree(tree);
+	}
+
+}
+
+#endif

Added: branches/ctdb/squeeze-backports/common/rb_tree.h
===================================================================
--- branches/ctdb/squeeze-backports/common/rb_tree.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/rb_tree.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,82 @@
+/* 
+   a talloc based red-black tree
+
+   Copyright (C) Ronnie Sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+
+#define TRBT_RED		0x00
+#define TRBT_BLACK		0x01
+typedef struct trbt_node {
+	struct trbt_tree *tree;
+	struct trbt_node *parent;
+	struct trbt_node *left;
+	struct trbt_node *right;
+	uint32_t rb_color;
+	uint32_t key32;
+	void *data;
+} trbt_node_t;
+
+typedef struct trbt_tree {
+	trbt_node_t *root;
+/* automatically free the tree when the last node has been deleted */
+#define TRBT_AUTOFREE		0x00000001
+	uint32_t flags;
+} trbt_tree_t;
+
+
+
+/* Create a RB tree */
+trbt_tree_t *trbt_create(TALLOC_CTX *memctx, uint32_t flags);
+
+/* Lookup a node in the tree and return a pointer to data or NULL */
+void *trbt_lookup32(trbt_tree_t *tree, uint32_t key);
+
+/* Insert a new node into the tree. If there was already a node with this
+   key the pointer to the previous data is returned.
+   The tree will talloc_steal() the data inserted into the tree .
+*/
+void *trbt_insert32(trbt_tree_t *tree, uint32_t key, void *data);
+
+/* Insert a new node into the tree.
+   If this is a new node:
+     callback is called with data==NULL and param=param
+     the returned value from the callback is talloc_stolen and inserted in the
+     tree.
+   If a node already exists for this key then:
+     callback is called with data==existing data and param=param
+     the returned calue is talloc_stolen and inserted in the tree
+*/
+void trbt_insert32_callback(trbt_tree_t *tree, uint32_t key, void *(*callback)(void *param, void *data), void *param);
+
+/* Delete a node from the tree and free all data associated with it */
+void trbt_delete32(trbt_tree_t *tree, uint32_t key);
+
+
+/* insert into the tree with a key based on an array of uint32 */
+void trbt_insertarray32_callback(trbt_tree_t *tree, uint32_t keylen, uint32_t *key, void *(*callback)(void *param, void *data), void *param);
+
+/* Lookup a node in the tree with a key based on an array of uint32 
+   and return a pointer to data or NULL */
+void *trbt_lookuparray32(trbt_tree_t *tree, uint32_t keylen, uint32_t *key);
+
+/* Traverse a tree with a key based on an array of uint32 */
+void trbt_traversearray32(trbt_tree_t *tree, uint32_t keylen, void (*callback)(void *param, void *data), void *param);
+
+/* Lookup the first node in the tree with a key based on an array of uint32 
+   and return a pointer to data or NULL */
+void *trbt_findfirstarray32(trbt_tree_t *tree, uint32_t keylen);

Added: branches/ctdb/squeeze-backports/common/system_aix.c
===================================================================
--- branches/ctdb/squeeze-backports/common/system_aix.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/system_aix.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,364 @@
+/* 
+   ctdb system specific code to manage raw sockets on aix
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+#include <netinet/if_ether.h>
+#include <netinet/ip6.h>
+#include <net/if_arp.h>
+#include <sys/ndd_var.h>
+#include <sys/kinfo.h>
+#include <pcap.h>
+
+
+
+#if 0
+This function is no longer used and its code should be moved into
+send tcp packet   after that function has been enhanced to do ipv6 as well.
+
+/* This function is used to open a raw socket to send tickles from
+ */
+int ctdb_sys_open_sending_socket(void)
+{
+	int s, ret;
+	uint32_t one = 1;
+
+	s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+	if (s == -1) {
+		DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
+			 strerror(errno)));
+		return -1;
+	}
+
+	ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
+			 strerror(errno)));
+		close(s);
+		return -1;
+	}
+
+	set_nonblocking(s);
+	set_close_on_exec(s);
+
+	return s;
+}
+#endif
+
+/*
+  simple TCP checksum - assumes data is multiple of 2 bytes long
+ */
+static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
+{
+	uint32_t sum = uint16_checksum(data, n);
+	uint16_t sum2;
+
+	sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
+	sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
+	sum += ip->ip_p + n;
+	sum = (sum & 0xFFFF) + (sum >> 16);
+	sum = (sum & 0xFFFF) + (sum >> 16);
+	sum2 = htons(sum);
+	sum2 = ~sum2;
+	if (sum2 == 0) {
+		return 0xFFFF;
+	}
+	return sum2;
+}
+
+/*
+  Send tcp segment from the specified IP/port to the specified
+  destination IP/port. 
+
+  This is used to trigger the receiving host into sending its own ACK,
+  which should trigger early detection of TCP reset by the client
+  after IP takeover
+
+  This can also be used to send RST segments (if rst is true) and also
+  if correct seq and ack numbers are provided.
+ */
+int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
+		      const ctdb_sock_addr *src,
+		      uint32_t seq, uint32_t ack, int rst)
+{
+	int s;
+  	int ret;
+	uint32_t one = 1;
+	ctdb_sock_addr *tmpdest;
+	
+	struct {
+		struct ip ip;
+		struct tcphdr tcp;
+	} ip4pkt;
+
+
+	/* for now, we only handle AF_INET addresses */
+	if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
+		DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
+		return -1;
+	}
+
+
+
+	s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+	if (s == -1) {
+		DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
+			 strerror(errno)));
+		return -1;
+	}
+
+	ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
+			 strerror(errno)));
+		close(s);
+		return -1;
+	}
+
+	set_nonblocking(s);
+	set_close_on_exec(s);
+
+	memset(&ip4pkt, 0, sizeof(ip4pkt));
+	ip4pkt.ip.ip_v     = 4;
+	ip4pkt.ip.ip_hl    = sizeof(ip4pkt.ip)/4;
+	ip4pkt.ip.ip_len   = htons(sizeof(ip4pkt));
+	ip4pkt.ip.ip_ttl   = 255;
+	ip4pkt.ip.ip_p     = IPPROTO_TCP;
+	ip4pkt.ip.ip_src.s_addr   = src->ip.sin_addr.s_addr;
+	ip4pkt.ip.ip_dst.s_addr   = dest->ip.sin_addr.s_addr;
+	ip4pkt.ip.ip_sum   = 0;
+
+	ip4pkt.tcp.th_sport   = src->ip.sin_port;
+	ip4pkt.tcp.th_dport     = dest->ip.sin_port;
+	ip4pkt.tcp.th_seq      = seq;
+	ip4pkt.tcp.th_ack    = ack;
+	ip4pkt.tcp.th_flags  = TH_ACK;
+	if (rst) {
+		ip4pkt.tcp.th_flags      = TH_RST;
+	}
+	ip4pkt.tcp.th_off    = sizeof(ip4pkt.tcp)/4;
+	ip4pkt.tcp.th_win   = htons(1234);
+	ip4pkt.tcp.th_sum    = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
+
+	ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
+	if (ret != sizeof(ip4pkt)) {
+		DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* This function is used to open a raw socket to capture from
+ */
+int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
+{
+	pcap_t *pt;
+
+	pt=pcap_open_live(iface, 100, 0, 0, NULL);
+	if (pt == NULL) {
+		DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
+		return -1;
+	}
+	*((pcap_t **)private_data) = pt;
+
+	return pcap_fileno(pt);
+}
+
+
+/* This function is used to close the capture socket
+ */
+int ctdb_sys_close_capture_socket(void *private_data)
+{
+	pcap_t *pt = (pcap_t *)private_data;
+	pcap_close(pt);
+	return 0;
+}
+
+
+
+/*
+  send gratuitous arp reply after we have taken over an ip address
+
+  saddr is the address we are trying to claim
+  iface is the interface name we will be using to claim the address
+ */
+int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
+{
+	/* We dont do grat arp on aix yet */
+	return 0;
+}
+
+
+
+/*
+  get ethernet MAC address on AIX
+ */
+static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
+{
+        size_t ksize;
+        struct kinfo_ndd *ndd;
+	int count, i;
+
+        ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
+        if (ksize == 0) {
+		errno = ENOSYS;
+		return -1;
+        }
+
+        ndd = (struct kinfo_ndd *)malloc(ksize);
+        if (ndd == NULL) {
+		errno = ENOMEM;
+		return -1;
+        }
+
+        if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
+		errno = ENOSYS;
+		return -1;
+        }
+
+	count= ksize/sizeof(struct kinfo_ndd);
+	for (i=0;i<count;i++) {
+		if ( (ndd[i].ndd_type != NDD_ETHER) 
+		&&   (ndd[i].ndd_type != NDD_ISO88023) ) {
+			continue;
+		}
+		if (ndd[i].ndd_addrlen != 6) {
+			continue;
+		}
+		if (!(ndd[i].ndd_flags&NDD_UP)) {
+			continue;
+		}
+		if ( strcmp(device_name, ndd[i].ndd_name)
+		&&   strcmp(device_name, ndd[i].ndd_alias) ) {
+			continue;
+		}
+                memcpy(mac, ndd[i].ndd_addr, 6);
+		free(ndd);
+		return 0;
+        }
+	free(ndd);
+	errno = ENOENT;
+	return -1;
+}
+
+int ctdb_sys_read_tcp_packet(int s, void *private_data, 
+			ctdb_sock_addr *src, ctdb_sock_addr *dst,
+			uint32_t *ack_seq, uint32_t *seq)
+{
+	int ret;
+	struct ether_header *eth;
+	struct ip *ip;
+	struct ip6_hdr *ip6;
+	struct tcphdr *tcp;
+	struct ctdb_killtcp_connection *conn;
+	struct pcap_pkthdr pkthdr;
+	const u_char *buffer;
+	pcap_t *pt = (pcap_t *)private_data;
+
+	buffer=pcap_next(pt, &pkthdr);
+	if (buffer==NULL) {
+		return -1;
+	}
+
+	/* Ethernet */
+	eth = (struct ether_header *)buffer;
+
+	/* we want either IPv4 or IPv6 */
+	if (eth->ether_type == htons(ETHERTYPE_IP)) {
+		/* IP */
+		ip = (struct ip *)(eth+1);
+
+		/* We only want IPv4 packets */
+		if (ip->ip_v != 4) {
+			return -1;
+		}
+		/* Dont look at fragments */
+		if ((ntohs(ip->ip_off)&0x1fff) != 0) {
+			return -1;
+		}
+		/* we only want TCP */
+		if (ip->ip_p != IPPROTO_TCP) {
+			return -1;
+		}
+
+		/* make sure its not a short packet */
+		if (offsetof(struct tcphdr, th_ack) + 4 + 
+		    (ip->ip_hl*4) > ret) {
+			return -1;
+		}
+		/* TCP */
+		tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
+	
+		/* tell the caller which one we've found */
+		src->ip.sin_family      = AF_INET;
+		src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
+		src->ip.sin_port        = tcp->th_sport;
+		dst->ip.sin_family      = AF_INET;
+		dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
+		dst->ip.sin_port        = tcp->th_dport;
+		*ack_seq                = tcp->th_ack;
+		*seq                    = tcp->th_seq;
+
+
+		return 0;
+#ifndef ETHERTYPE_IP6
+#define ETHERTYPE_IP6 0x86dd
+#endif
+	} else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
+	  		/* IP6 */
+		ip6 = (struct ip6_hdr *)(eth+1);
+
+		/* we only want TCP */
+		if (ip6->ip6_nxt != IPPROTO_TCP) {
+			return -1;
+		}
+
+		/* TCP */
+		tcp = (struct tcphdr *)(ip6+1);
+
+		/* tell the caller which one we've found */
+		src->ip6.sin6_family = AF_INET6;
+		src->ip6.sin6_port   = tcp->th_sport;
+		src->ip6.sin6_addr   = ip6->ip6_src;
+
+		dst->ip6.sin6_family = AF_INET6;
+		dst->ip6.sin6_port   = tcp->th_dport;
+		dst->ip6.sin6_addr   = ip6->ip6_dst;
+
+		*ack_seq             = tcp->th_ack;
+		*seq                 = tcp->th_seq;
+
+		return 0;
+	}
+
+	return -1;
+}
+
+
+bool ctdb_sys_check_iface_exists(const char *iface)
+{
+	return true;
+}
+

Added: branches/ctdb/squeeze-backports/common/system_common.c
===================================================================
--- branches/ctdb/squeeze-backports/common/system_common.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/system_common.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,77 @@
+/* 
+   ctdb system specific code to manage raw sockets on linux
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+
+/*
+  uint16 checksum for n bytes
+ */
+uint32_t uint16_checksum(uint16_t *data, size_t n)
+{
+	uint32_t sum=0;
+	while (n>=2) {
+		sum += (uint32_t)ntohs(*data);
+		data++;
+		n -= 2;
+	}
+	if (n == 1) {
+		sum += (uint32_t)ntohs(*(uint8_t *)data);
+	}
+	return sum;
+}
+
+/*
+  see if we currently have an interface with the given IP
+
+  we try to bind to it, and if that fails then we don't have that IP
+  on an interface
+ */
+bool ctdb_sys_have_ip(ctdb_sock_addr *_addr)
+{
+	int s;
+	int ret;
+	ctdb_sock_addr __addr = *_addr;
+	ctdb_sock_addr *addr = &__addr;
+	socklen_t addrlen;
+
+	switch (addr->sa.sa_family) {
+	case AF_INET:
+		addr->ip.sin_port = 0;
+		addrlen = sizeof(struct sockaddr_in);
+		break;
+	case AF_INET6:
+		addr->ip6.sin6_port = 0;
+		addrlen = sizeof(struct sockaddr_in6);
+		break;
+	}
+
+	s = socket(addr->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+	if (s == -1) {
+		return false;
+	}
+
+	ret = bind(s, (struct sockaddr *)addr, addrlen);
+
+	close(s);
+	return ret == 0;
+}
+
+

Added: branches/ctdb/squeeze-backports/common/system_linux.c
===================================================================
--- branches/ctdb/squeeze-backports/common/system_linux.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/common/system_linux.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,561 @@
+/* 
+   ctdb system specific code to manage raw sockets on linux
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+#include "lib/tevent/tevent.h"
+#include <netinet/if_ether.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <net/if_arp.h>
+#include <netpacket/packet.h>
+
+#ifndef ETHERTYPE_IP6
+#define ETHERTYPE_IP6 0x86dd
+#endif
+
+/*
+  calculate the tcp checksum for tcp over ipv6
+*/
+static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
+{
+	uint32_t phdr[2];
+	uint32_t sum = 0;
+	uint16_t sum2;
+
+	sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
+	sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
+
+	phdr[0] = htonl(n);
+	phdr[1] = htonl(ip6->ip6_nxt);
+	sum += uint16_checksum((uint16_t *)phdr, 8);
+
+	sum += uint16_checksum(data, n);
+
+	sum = (sum & 0xFFFF) + (sum >> 16);
+	sum = (sum & 0xFFFF) + (sum >> 16);
+	sum2 = htons(sum);
+	sum2 = ~sum2;
+	if (sum2 == 0) {
+		return 0xFFFF;
+	}
+	return sum2;
+}
+
+/*
+  send gratuitous arp reply after we have taken over an ip address
+
+  saddr is the address we are trying to claim
+  iface is the interface name we will be using to claim the address
+ */
+int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
+{
+	int s, ret;
+	struct sockaddr_ll sall;
+	struct ether_header *eh;
+	struct arphdr *ah;
+	struct ip6_hdr *ip6;
+	struct icmp6_hdr *icmp6;
+	struct ifreq if_hwaddr;
+	unsigned char buffer[78]; /* ipv6 neigh solicitation size */
+	char *ptr;
+	char bdcast[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+	struct ifreq ifr;
+
+	ZERO_STRUCT(sall);
+
+	switch (addr->ip.sin_family) {
+	case AF_INET:
+		s = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_ARP));
+		if (s == -1){
+			DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
+			return -1;
+		}
+
+		DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
+		strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+		if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+			DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
+			close(s);
+			return -1;
+		}
+
+		/* get the mac address */
+		strcpy(if_hwaddr.ifr_name, iface);
+		ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
+		if ( ret < 0 ) {
+			close(s);
+			DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
+			return -1;
+		}
+		if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
+			DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
+			close(s);
+			return 0;
+		}
+		if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
+			close(s);
+			errno = EINVAL;
+			DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
+				 if_hwaddr.ifr_hwaddr.sa_family));
+			return -1;
+		}
+
+
+		memset(buffer, 0 , 64);
+		eh = (struct ether_header *)buffer;
+		memset(eh->ether_dhost, 0xff, ETH_ALEN);
+		memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+		eh->ether_type = htons(ETHERTYPE_ARP);
+	
+		ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
+		ah->ar_hrd = htons(ARPHRD_ETHER);
+		ah->ar_pro = htons(ETH_P_IP);
+		ah->ar_hln = ETH_ALEN;
+		ah->ar_pln = 4;
+
+		/* send a gratious arp */
+		ah->ar_op  = htons(ARPOP_REQUEST);
+		ptr = (char *)&ah[1];
+		memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+		ptr+=ETH_ALEN;
+		memcpy(ptr, &addr->ip.sin_addr, 4);	  
+		ptr+=4;
+		memset(ptr, 0, ETH_ALEN); 
+		ptr+=ETH_ALEN;
+		memcpy(ptr, &addr->ip.sin_addr, 4);	  
+		ptr+=4;
+	
+		sall.sll_family = AF_PACKET;
+		sall.sll_halen = 6;
+		memcpy(&sall.sll_addr[0], bdcast, sall.sll_halen);
+		sall.sll_protocol = htons(ETH_P_ALL);
+		sall.sll_ifindex = ifr.ifr_ifindex;
+		ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
+		if (ret < 0 ){
+			close(s);
+			DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
+			return -1;
+		}	
+
+		/* send unsolicited arp reply broadcast */
+		ah->ar_op  = htons(ARPOP_REPLY);
+		ptr = (char *)&ah[1];
+		memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+		ptr+=ETH_ALEN;
+		memcpy(ptr, &addr->ip.sin_addr, 4);	  
+		ptr+=4;
+		memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+		ptr+=ETH_ALEN;
+		memcpy(ptr, &addr->ip.sin_addr, 4);	  
+		ptr+=4;
+
+		ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
+		if (ret < 0 ){
+			DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
+			close(s);
+			return -1;
+		}
+
+		close(s);
+		break;
+	case AF_INET6:
+		s = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_ARP));
+		if (s == -1){
+			DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
+			return -1;
+		}
+
+		DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
+		strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+		if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+			DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
+			close(s);
+			return -1;
+		}
+
+		/* get the mac address */
+		strcpy(if_hwaddr.ifr_name, iface);
+		ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
+		if ( ret < 0 ) {
+			close(s);
+			DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
+			return -1;
+		}
+		if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
+			DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
+			close(s);
+			return 0;
+		}
+		if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
+			close(s);
+			errno = EINVAL;
+			DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
+				 if_hwaddr.ifr_hwaddr.sa_family));
+			return -1;
+		}
+
+		memset(buffer, 0 , sizeof(buffer));
+		eh = (struct ether_header *)buffer;
+		memset(eh->ether_dhost, 0xff, ETH_ALEN);
+		memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+		eh->ether_type = htons(ETHERTYPE_IP6);
+
+		ip6 = (struct ip6_hdr *)(eh+1);
+		ip6->ip6_vfc  = 0x60;
+		ip6->ip6_plen = htons(24);
+		ip6->ip6_nxt  = IPPROTO_ICMPV6;
+		ip6->ip6_hlim = 255;
+		ip6->ip6_dst  = addr->ip6.sin6_addr;
+
+		icmp6 = (struct icmp6_hdr *)(ip6+1);
+		icmp6->icmp6_type = ND_NEIGHBOR_SOLICIT;
+		icmp6->icmp6_code = 0;
+		memcpy(&icmp6->icmp6_data32[1], &addr->ip6.sin6_addr, 16);
+
+		icmp6->icmp6_cksum = tcp_checksum6((uint16_t *)icmp6, ntohs(ip6->ip6_plen), ip6);
+
+		sall.sll_family = AF_PACKET;
+		sall.sll_halen = 6;
+		memcpy(&sall.sll_addr[0], bdcast, sall.sll_halen);
+		sall.sll_protocol = htons(ETH_P_ALL);
+		sall.sll_ifindex = ifr.ifr_ifindex;
+		ret = sendto(s, buffer, 78, 0, (struct sockaddr *)&sall, sizeof(sall));
+		if (ret < 0 ){
+			close(s);
+			DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
+			return -1;
+		}	
+
+		close(s);
+		break;
+	default:
+		DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/ipv6 address (family is %u)\n", addr->ip.sin_family));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+  simple TCP checksum - assumes data is multiple of 2 bytes long
+ */
+static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
+{
+	uint32_t sum = uint16_checksum(data, n);
+	uint16_t sum2;
+	sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
+			       sizeof(ip->saddr));
+	sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
+			       sizeof(ip->daddr));
+	sum += ip->protocol + n;
+	sum = (sum & 0xFFFF) + (sum >> 16);
+	sum = (sum & 0xFFFF) + (sum >> 16);
+	sum2 = htons(sum);
+	sum2 = ~sum2;
+	if (sum2 == 0) {
+		return 0xFFFF;
+	}
+	return sum2;
+}
+
+/*
+  Send tcp segment from the specified IP/port to the specified
+  destination IP/port. 
+
+  This is used to trigger the receiving host into sending its own ACK,
+  which should trigger early detection of TCP reset by the client
+  after IP takeover
+
+  This can also be used to send RST segments (if rst is true) and also
+  if correct seq and ack numbers are provided.
+ */
+int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, 
+		      const ctdb_sock_addr *src,
+		      uint32_t seq, uint32_t ack, int rst)
+{
+	int s;
+	int ret;
+	uint32_t one = 1;
+	uint16_t tmpport;
+	ctdb_sock_addr *tmpdest;
+	struct {
+		struct iphdr ip;
+		struct tcphdr tcp;
+	} ip4pkt;
+	struct {
+		struct ip6_hdr ip6;
+		struct tcphdr tcp;
+	} ip6pkt;
+
+	switch (src->ip.sin_family) {
+	case AF_INET:
+		ZERO_STRUCT(ip4pkt);
+		ip4pkt.ip.version  = 4;
+		ip4pkt.ip.ihl      = sizeof(ip4pkt.ip)/4;
+		ip4pkt.ip.tot_len  = htons(sizeof(ip4pkt));
+		ip4pkt.ip.ttl      = 255;
+		ip4pkt.ip.protocol = IPPROTO_TCP;
+		ip4pkt.ip.saddr    = src->ip.sin_addr.s_addr;
+		ip4pkt.ip.daddr    = dest->ip.sin_addr.s_addr;
+		ip4pkt.ip.check    = 0;
+
+		ip4pkt.tcp.source   = src->ip.sin_port;
+		ip4pkt.tcp.dest     = dest->ip.sin_port;
+		ip4pkt.tcp.seq      = seq;
+		ip4pkt.tcp.ack_seq  = ack;
+		ip4pkt.tcp.ack      = 1;
+		if (rst) {
+			ip4pkt.tcp.rst      = 1;
+		}
+		ip4pkt.tcp.doff     = sizeof(ip4pkt.tcp)/4;
+		/* this makes it easier to spot in a sniffer */
+		ip4pkt.tcp.window   = htons(1234);
+		ip4pkt.tcp.check    = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
+
+		/* open a raw socket to send this segment from */
+		s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+		if (s == -1) {
+			DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
+				 strerror(errno)));
+			return -1;
+		}
+
+		ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
+		if (ret != 0) {
+			DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
+				 strerror(errno)));
+			close(s);
+			return -1;
+		}
+
+		set_nonblocking(s);
+		set_close_on_exec(s);
+
+		ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, &dest->ip, sizeof(dest->ip));
+		close(s);
+		if (ret != sizeof(ip4pkt)) {
+			DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
+			return -1;
+		}
+		break;
+	case AF_INET6:
+		ZERO_STRUCT(ip6pkt);
+		ip6pkt.ip6.ip6_vfc  = 0x60;
+		ip6pkt.ip6.ip6_plen = htons(20);
+		ip6pkt.ip6.ip6_nxt  = IPPROTO_TCP;
+		ip6pkt.ip6.ip6_hlim = 64;
+		ip6pkt.ip6.ip6_src  = src->ip6.sin6_addr;
+		ip6pkt.ip6.ip6_dst  = dest->ip6.sin6_addr;
+
+		ip6pkt.tcp.source   = src->ip6.sin6_port;
+		ip6pkt.tcp.dest     = dest->ip6.sin6_port;
+		ip6pkt.tcp.seq      = seq;
+		ip6pkt.tcp.ack_seq  = ack;
+		ip6pkt.tcp.ack      = 1;
+		if (rst) {
+			ip6pkt.tcp.rst      = 1;
+		}
+		ip6pkt.tcp.doff     = sizeof(ip6pkt.tcp)/4;
+		/* this makes it easier to spot in a sniffer */
+		ip6pkt.tcp.window   = htons(1234);
+		ip6pkt.tcp.check    = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
+
+		s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
+		if (s == -1) {
+			DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
+			return -1;
+
+		}
+		/* sendto() dont like if the port is set and the socket is
+		   in raw mode.
+		*/
+		tmpdest = discard_const(dest);
+		tmpport = tmpdest->ip6.sin6_port;
+
+		tmpdest->ip6.sin6_port = 0;
+		ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0, &dest->ip6, sizeof(dest->ip6));
+		tmpdest->ip6.sin6_port = tmpport;
+		close(s);
+
+		if (ret != sizeof(ip6pkt)) {
+			DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
+			return -1;
+		}
+		break;
+
+	default:
+		DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* 
+   This function is used to open a raw socket to capture from
+ */
+int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
+{
+	int s;
+
+	/* Open a socket to capture all traffic */
+	s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (s == -1) {
+		DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
+		return -1;
+	}
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created RAW SOCKET FD:%d for tcp tickle\n", s));
+
+	set_nonblocking(s);
+	set_close_on_exec(s);
+
+	return s;
+}
+
+/* 
+   This function is used to do any additional cleanup required when closing
+   a capture socket.
+   Note that the socket itself is closed automatically in the caller.
+ */
+int ctdb_sys_close_capture_socket(void *private_data)
+{
+	return 0;
+}
+
+
+/*
+  called when the raw socket becomes readable
+ */
+int ctdb_sys_read_tcp_packet(int s, void *private_data, 
+			ctdb_sock_addr *src, ctdb_sock_addr *dst,
+			uint32_t *ack_seq, uint32_t *seq)
+{
+	int ret;
+#define RCVPKTSIZE 100
+	char pkt[RCVPKTSIZE];
+	struct ether_header *eth;
+	struct iphdr *ip;
+	struct ip6_hdr *ip6;
+	struct tcphdr *tcp;
+
+	ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
+	if (ret < sizeof(*eth)+sizeof(*ip)) {
+		return -1;
+	}
+
+	/* Ethernet */
+	eth = (struct ether_header *)pkt;
+
+	/* we want either IPv4 or IPv6 */
+	if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
+		/* IP */
+		ip = (struct iphdr *)(eth+1);
+
+		/* We only want IPv4 packets */
+		if (ip->version != 4) {
+			return -1;
+		}
+		/* Dont look at fragments */
+		if ((ntohs(ip->frag_off)&0x1fff) != 0) {
+			return -1;
+		}
+		/* we only want TCP */
+		if (ip->protocol != IPPROTO_TCP) {
+			return -1;
+		}
+
+		/* make sure its not a short packet */
+		if (offsetof(struct tcphdr, ack_seq) + 4 + 
+		    (ip->ihl*4) + sizeof(*eth) > ret) {
+			return -1;
+		}
+		/* TCP */
+		tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
+
+		/* tell the caller which one we've found */
+		src->ip.sin_family      = AF_INET;
+		src->ip.sin_addr.s_addr = ip->saddr;
+		src->ip.sin_port        = tcp->source;
+		dst->ip.sin_family      = AF_INET;
+		dst->ip.sin_addr.s_addr = ip->daddr;
+		dst->ip.sin_port        = tcp->dest;
+		*ack_seq                = tcp->ack_seq;
+		*seq                    = tcp->seq;
+
+		return 0;
+	} else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
+		/* IP6 */
+		ip6 = (struct ip6_hdr *)(eth+1);
+
+		/* we only want TCP */
+		if (ip6->ip6_nxt != IPPROTO_TCP) {
+			return -1;
+		}
+
+		/* TCP */
+		tcp = (struct tcphdr *)(ip6+1);
+
+		/* tell the caller which one we've found */
+		src->ip6.sin6_family = AF_INET6;
+		src->ip6.sin6_port   = tcp->source;
+		src->ip6.sin6_addr   = ip6->ip6_src;
+
+		dst->ip6.sin6_family = AF_INET6;
+		dst->ip6.sin6_port   = tcp->dest;
+		dst->ip6.sin6_addr   = ip6->ip6_dst;
+
+		*ack_seq             = tcp->ack_seq;
+		*seq                 = tcp->seq;
+
+		return 0;
+	}
+
+	return -1;
+}
+
+
+bool ctdb_sys_check_iface_exists(const char *iface)
+{
+	int s;
+	struct ifreq ifr;
+
+	s = socket(PF_PACKET, SOCK_RAW, 0);
+	if (s == -1){
+		/* We dont know if the interface exists, so assume yes */
+		DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
+		return true;
+	}
+
+	strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0 && errno == ENODEV) {
+		DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
+		close(s);
+		return false;
+	}
+	close(s);
+	
+	return true;
+}

Added: branches/ctdb/squeeze-backports/config/README
===================================================================
--- branches/ctdb/squeeze-backports/config/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,37 @@
+This directory contains run-time support scripts for CTDB.
+
+Selected highlights:
+
+  ctdb.init
+
+    An initscript for starting ctdbd at boot time.
+
+  events.d/
+
+    Eventscripts.  See events.d/README for more details.
+
+  functions
+
+    Support functions, sourced by eventscripts and other scripts.
+
+  interface_modify.sh
+
+    Script to support add/remove IPs and other funky stuff.  Not sure
+    why this is separate... but it certainly allows easy wrapping by
+    flock.
+
+  statd-callout
+
+    rpc.statd high-availability callout to support lock migration on
+    failover.
+
+Notes:
+
+* All of these scripts are written in POSIX Bourne shell.  Please
+  avoid bash-isms, including the use of "local" variables (which are
+  not available in POSIX shell).
+
+* Do not use absolute paths for commands.  Unit tests attempt to
+  replace many commands with stubs and can not do this if commands are
+  specified with absolute paths.  The functions file controls $PATH so
+  absolute paths should not be required.

Added: branches/ctdb/squeeze-backports/config/ctdb-crash-cleanup.sh
===================================================================
--- branches/ctdb/squeeze-backports/config/ctdb-crash-cleanup.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/ctdb-crash-cleanup.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# This script can be called from a cronjob to automatically drop/release
+# all public ip addresses if CTDBD has crashed or stopped running.
+#
+
+[ -z "$CTDB_BASE" ] && {
+    CTDB_BASE=/etc/ctdb
+}
+
+[ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
+	CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses
+}
+
+[ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
+	echo "No public addresses file found. Cant cleanup."
+	exit 1
+}
+
+# if ctdb is running, just return
+ctdb status 2>/dev/null && {
+    exit 0
+}
+
+(cat /etc/sysconfig/ctdb | egrep "^CTDB_NATGW_PUBLIC_IP" | sed -e "s/.*=//" -e "s/\/.*//";cat "$CTDB_PUBLIC_ADDRESSES" | cut -d/ -f1) | while read _IP; do
+	_IP_HELD=`/sbin/ip addr show | grep "inet $_IP/"`
+	[ -z "$_IP_HELD" ] || {
+		_IFACE=`echo $_IP_HELD | sed -e "s/.*\s//"`
+		_NM=`echo $_IP_HELD | sed -e "s/.*$_IP\///" -e "s/\s.*//"`
+		logger "Removing public address $_IP/$_NM from device $_IFACE"
+		/sbin/ip addr del $_IP/$_NM dev $_IFACE
+	}
+done
+
+


Property changes on: branches/ctdb/squeeze-backports/config/ctdb-crash-cleanup.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/ctdb.init
===================================================================
--- branches/ctdb/squeeze-backports/config/ctdb.init	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/ctdb.init	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,399 @@
+#!/bin/sh
+#
+##############################
+# ctdb:                        Starts the clustered tdb daemon
+#
+# chkconfig:           - 90 01
+#
+# description:                 Starts and stops the clustered tdb daemon
+# pidfile:             /var/run/ctdbd/ctdbd.pid
+#
+
+### BEGIN INIT INFO
+# Provides:            ctdb
+# Required-Start:      $network
+# Required-Stop:       $network
+# Default-Stop:
+# Default-Start:       3 5
+# Short-Description:   start and stop ctdb service
+# Description:         initscript for the ctdb service
+### END INIT INFO
+
+# Source function library.
+if [ -f /etc/init.d/functions ] ; then
+    . /etc/init.d/functions
+elif [ -f /etc/rc.d/init.d/functions ] ; then
+    . /etc/rc.d/init.d/functions
+fi
+
+[ -f /etc/rc.status ] && {
+    . /etc/rc.status
+    rc_reset
+    LC_ALL=en_US.UTF-8
+}
+
+# Avoid using root's TMPDIR
+unset TMPDIR
+
+[ -z "$CTDB_BASE" ] && {
+    export CTDB_BASE="/etc/ctdb"
+}
+
+. $CTDB_BASE/functions
+loadconfig network
+loadconfig ctdb
+
+# check networking is up (for redhat)
+[ "$NETWORKING" = "no" ] && exit 0
+
+detect_init_style
+export CTDB_INIT_STYLE
+
+ctdbd=${CTDBD:-/usr/sbin/ctdbd}
+
+if [ "$CTDB_VALGRIND" = "yes" ]; then
+    init_style="valgrind"
+else
+    init_style="$CTDB_INIT_STYLE"
+fi
+
+build_ctdb_options () {
+
+    maybe_set () {
+	# If the 2nd arg is null then return - don't set anything.
+	# Else if the 3rd arg is set and it doesn't match the 2nd arg
+	# then return
+	[ -z "$2" -o \( -n "$3" -a "$3" != "$2" \) ] && return
+
+	val="'$2'"
+	case "$1" in
+	    --*) sep="=" ;;
+	    -*)  sep=" " ;;
+	esac
+	# For these options we're only passing a value-less flag.
+	[ -n "$3" ] && {
+	    val=""
+	    sep=""
+	}
+
+	CTDB_OPTIONS="${CTDB_OPTIONS}${CTDB_OPTIONS:+ }${1}${sep}${val}"
+    }
+
+    [ -z "$CTDB_RECOVERY_LOCK" ] && {
+        echo "No recovery lock specified. Starting CTDB without split brain prevention"
+    }
+    maybe_set "--reclock"                "$CTDB_RECOVERY_LOCK"
+
+    # build up CTDB_OPTIONS variable from optional parameters
+    maybe_set "--logfile"                "$CTDB_LOGFILE"
+    maybe_set "--nlist"                  "$CTDB_NODES"
+    maybe_set "--socket"                 "$CTDB_SOCKET"
+    maybe_set "--public-addresses"       "$CTDB_PUBLIC_ADDRESSES"
+    maybe_set "--public-interface"       "$CTDB_PUBLIC_INTERFACE"
+    maybe_set "--dbdir"                  "$CTDB_DBDIR"
+    maybe_set "--dbdir-persistent"       "$CTDB_DBDIR_PERSISTENT"
+    maybe_set "--event-script-dir"       "$CTDB_EVENT_SCRIPT_DIR"
+    maybe_set "--transport"              "$CTDB_TRANSPORT"
+    maybe_set "-d"                       "$CTDB_DEBUGLEVEL"
+    maybe_set "--notification-script"    "$CTDB_NOTIFY_SCRIPT"
+    maybe_set "--start-as-disabled"      "$CTDB_START_AS_DISABLED"    "yes"
+    maybe_set "--start-as-stopped "      "$CTDB_START_AS_STOPPED"     "yes"
+    maybe_set "--no-recmaster"           "$CTDB_CAPABILITY_RECMASTER" "no"
+    maybe_set "--no-lmaster"             "$CTDB_CAPABILITY_LMASTER"   "no"
+    maybe_set "--lvs --single-public-ip" "$CTDB_LVS_PUBLIC_IP"
+    maybe_set "--script-log-level"       "$CTDB_SCRIPT_LOG_LEVEL"
+    maybe_set "--log-ringbuf-size"       "$CTDB_LOG_RINGBUF_SIZE"
+    maybe_set "--syslog"                 "$CTDB_SYSLOG"               "yes"
+    maybe_set "--max-persistent-check-errors" "$CTDB_MAX_PERSISTENT_CHECK_ERRORS"
+}
+
+check_tdb () {
+	local PDBASE=$1
+
+	test x"$TDBTOOL_HAS_CHECK" = x"1" && {
+		#
+		# Note tdbtool always exits with 0
+		#
+		local OK=`tdbtool $PDBASE check | grep "Database integrity is OK" | wc -l`
+		test x"$OK" = x"1" || {
+			return 1;
+		}
+
+		return 0;
+	}
+
+	tdbdump $PDBASE >/dev/null 2>/dev/null || {
+		return $?;
+	}
+
+	return 0;
+}
+
+check_persistent_databases () {
+    PERSISTENT_DB_DIR="${CTDB_DBDIR:-/var/ctdb}/persistent"
+    mkdir -p $PERSISTENT_DB_DIR 2>/dev/null
+    local ERRCOUNT=$CTDB_MAX_PERSISTENT_CHECK_ERRORS
+
+    test -z "$ERRCOUNT" && {
+	ERRCOUNT="0"
+    }
+    test x"$ERRCOUNT" != x"0" && {
+	return 0;
+    }
+
+    if test -x /usr/bin/tdbtool ; then
+        HAVE_TDBTOOL=1
+    else
+        HAVE_TDBTOOL=0
+    fi
+
+    if test x"$HAVE_TDBTOOL" = x"1" ; then
+        TDBTOOL_HAS_CHECK=`echo "help" | /usr/bin/tdbtool | grep check | wc -l`
+    else
+        TDBTOOL_HAS_CHECK=0
+    fi
+
+    if test -x /usr/bin/tdbdump ; then
+        HAVE_TDBDUMP=1
+    else
+        HAVE_TDBDUMP=0
+    fi
+
+    if test x"$HAVE_TDBDUMP" = x"0" -a x"$TDBTOOL_HAS_CHECK" = x"0" ; then
+        echo "WARNING: Cannot check persistent databases since"
+        echo "neither 'tdbdump' nor 'tdbtool check' is available."
+        echo "Consider installing tdbtool or at least tdbdump!"
+        return 0
+    fi
+
+    if test x"$HAVE_TDBDUMP" = x"1" -a x"$TDBTOOL_HAS_CHECK" = x"0" ; then
+        if test x"$HAVE_TDBTOOL" = x"0"; then
+            echo "WARNING: 'tdbtool' is not available. Using 'tdbdump' to"
+            echo "check the persistent databases."
+            echo "Consider installing a recent 'tdbtool' for better checks!"
+        else
+            echo "WARNING: The installed 'tdbtool' does not offer the 'check'"
+            echo "subcommand. Using 'tdbdump' for persistent database checks."
+            echo "Consider updating 'tdbtool' for better checks!"
+        fi
+    fi
+
+    for PDBASE in `ls $PERSISTENT_DB_DIR/*.tdb.[0-9] 2>/dev/null`; do
+	check_tdb $PDBASE || {
+	    echo "Persistent database $PDBASE is corrupted! CTDB will not start."
+	    return 1
+	}
+    done
+}
+
+set_ctdb_variables () {
+    # set any tunables from the config file
+    set | grep ^CTDB_SET_ | cut -d_ -f3- | 
+    while read v; do
+	varname=`echo $v | cut -d= -f1`
+	value=`echo $v | cut -d= -f2`
+	ctdb setvar $varname $value || RETVAL=1
+    done || exit 1
+}
+
+set_retval() {
+    return $1
+}
+
+wait_until_ready () {
+    _timeout="${1:-10}" # default is 10 seconds
+
+    _count=0
+    while ! ctdb ping >/dev/null 2>&1 ; do
+	if [ $_count -ge $_timeout ] ; then
+	    return 1
+	fi
+	sleep 1
+	_count=$(($_count + 1))
+    done
+}
+
+ctdbd=${CTDBD:-/usr/sbin/ctdbd}
+
+drop_all_public_ips() {
+    [ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
+	return
+    }
+
+    cat $CTDB_PUBLIC_ADDRESSES | while read IP IFACE REST; do
+	ip addr del $IP dev $IFACE >/dev/null 2>/dev/null
+    done
+}
+
+start() {
+    echo -n $"Starting ctdbd service: "
+
+    ctdb ping >/dev/null 2>&1 && {
+	echo $"CTDB is already running"
+	return 0
+    }
+
+    build_ctdb_options
+
+    # make sure we drop any ips that might still be held if previous
+    # instance of ctdb got killed with -9 or similar
+    drop_all_public_ips
+
+    check_persistent_databases || return $?
+
+    if [ "$CTDB_SUPPRESS_COREFILE" = "yes" ]; then
+	ulimit -c 0
+    else
+	ulimit -c unlimited
+    fi
+
+    case $init_style in
+	valgrind)
+	    eval valgrind -q --log-file=/var/log/ctdb_valgrind \
+		$ctdbd --valgrinding "$CTDB_OPTIONS"
+	    RETVAL=$?
+	    echo
+	    ;;
+	suse)
+	    eval startproc $ctdbd "$CTDB_OPTIONS"
+	    RETVAL=$?
+	    ;;
+	redhat)
+	    eval $ctdbd "$CTDB_OPTIONS"
+	    RETVAL=$?
+	    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ctdb || RETVAL=1
+	    ;;
+	debian)
+	    eval start-stop-daemon --start --quiet --background \
+		--exec $ctdbd -- "$CTDB_OPTIONS"
+	    RETVAL=$?
+	    ;;
+    esac
+
+    if [ $RETVAL -eq 0 ] ; then
+	if wait_until_ready ; then
+	    set_ctdb_variables
+	else
+	    RETVAL=1
+	    pkill -9 -f $ctdbd >/dev/null 2>&1
+	fi
+    fi
+
+    case $init_style in
+	suse)
+	    set_retval $RETVAL
+	    rc_status -v
+	    ;;
+	redhat)
+	    [ $RETVAL -eq 0 ] && success || failure
+	    echo
+	    ;;
+    esac
+
+    return $RETVAL
+}
+
+stop() {
+    echo -n $"Shutting down ctdbd service: "
+    pkill -0 -f $ctdbd || {
+	echo -n "  Warning: ctdbd not running ! "
+	case $init_style in
+	    suse)
+		rc_status -v
+		;;
+	    redhat)
+		echo ""
+		;;
+	esac
+	return 0
+    }
+    ctdb shutdown >/dev/null 2>&1
+    RETVAL=$?
+    count=0
+    while pkill -0 -f $ctdbd ; do
+	sleep 1
+	count=$(($count + 1))
+	[ $count -gt 10 ] && {
+	    echo -n $"killing ctdbd "
+	    pkill -9 -f $ctdbd
+	    pkill -9 -f $CTDB_BASE/events.d/
+	}
+    done
+    # make sure all ips are dropped, pfkill -9 might leave them hanging around
+    drop_all_public_ips
+
+    case $init_style in
+	suse)
+	    # re-set the return code to the recorded RETVAL in order
+	    # to print the correct status message
+	    set_retval $RETVAL
+	    rc_status -v
+	    ;;
+	redhat)
+            [ $RETVAL -eq 0 ] && success || failure
+	    [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ctdb
+	    echo ""
+	    ;;
+    esac
+
+    return $RETVAL
+}
+
+restart() {
+    stop
+    start
+}
+
+status() {
+    echo -n $"Checking for ctdbd service: "
+    ctdb ping >/dev/null 2>&1 || {
+	RETVAL=$?
+	echo -n "  ctdbd not running. "
+	case $init_style in
+	    suse)
+		set_retval $RETVAL
+		rc_status -v
+		;;
+	    redhat)
+		if [ -f /var/lock/subsys/ctdb ]; then
+			echo $"ctdb dead but subsys locked"
+			RETVAL=2
+		else
+			echo $"ctdb is stopped"
+			RETVAL=3
+		fi
+		;;
+	esac
+	return $RETVAL
+    }
+    echo ""
+    ctdb status
+}
+
+
+case "$1" in
+    start)
+  	start
+	;;
+    stop)
+  	stop
+	;;
+    restart|reload|force-reload)
+  	restart
+	;;
+    status)
+  	status
+	;;
+    condrestart|try-restart)
+  	ctdb status > /dev/null && restart || :
+	;;
+    cron)
+	# used from cron to auto-restart ctdb
+  	ctdb status > /dev/null || restart
+	;;
+    *)
+	echo $"Usage: $0 {start|stop|restart|reload|force-reload|status|cron|condrestart|try-restart}"
+	exit 1
+esac
+
+exit $?


Property changes on: branches/ctdb/squeeze-backports/config/ctdb.init
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/ctdb.sysconfig
===================================================================
--- branches/ctdb/squeeze-backports/config/ctdb.sysconfig	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/ctdb.sysconfig	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,313 @@
+# Options to ctdbd. This is read by /etc/init.d/ctdb
+
+# You must specify the location of a shared lock file across all the
+# nodes for split brain prevention to work.
+# This must be on shared storage.
+# CTDB can operate without a reclock file, but this means that there is no
+# protection against a split brain.
+# It is strongly suggested to NOT run ctdb without a reclock file.
+CTDB_RECOVERY_LOCK="/some/place/on/shared/storage"
+
+# when doing IP takeover you also may specify what network interface
+# to use by default for the public addresses. Otherwise you must
+# specify an interface on each line of the public addresses file
+# there is no default
+# CTDB_PUBLIC_INTERFACE=eth0
+
+# Should ctdb do IP takeover? If it should, then specify a file
+# containing the list of public IP addresses that ctdb will manage
+# Note that these IPs must be different from those in $NODES above
+# there is no default.
+# The syntax is one line per public address of the form :
+#   <ipaddress>/<netmask> <interface>
+# Example: 10.1.1.1/24 eth0
+#
+# CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses
+
+# Should CTDB present the cluster using a single public ip address to clients
+# and multiplex clients across all CONNECTED nodes ?
+# This is based on LVS 
+# When this is enabled, the entire cluster will present one single ip address
+# which clients will connect to.
+# CTDB_LVS_PUBLIC_IP=10.1.1.1
+
+
+# should ctdb manage starting/stopping the Samba service for you?
+# default is to not manage Samba
+# CTDB_MANAGES_SAMBA=yes
+
+# If there are very many shares it may not be feasible to check that all
+# of them are available during each monitoring interval.
+# In that case this check can be disabled
+# CTDB_SAMBA_SKIP_SHARE_CHECK=yes
+# CTDB_NFS_SKIP_SHARE_CHECK=yes
+
+# specify which ports we should check that there is a daemon listening to
+# by default we use testparm and look in smb.conf to figure out.
+# CTDB_SAMBA_CHECK_PORTS="445"
+
+# should ctdb manage starting/stopping Winbind service?
+# if left comented out then it will be autodetected based on smb.conf
+# CTDB_MANAGES_WINBIND=yes
+
+# should ctdb manage starting/stopping the VSFTPD service
+# CTDB_MANAGES_VSFTPD=yes
+
+# should ctdb manage starting/stopping the ISCSI service
+# CTDB_MANAGES_ISCSI=yes
+
+# should ctdb manage starting/stopping the NFS service
+# CTDB_MANAGES_NFS=yes
+
+# should ctdb manage starting/stopping the Apache web server httpd?
+# CTDB_MANAGES_HTTPD
+
+# The init style (redhat/suse/debian...) is usually auto-detected.
+# The names of init scripts of services managed by CTDB are set
+# based on the detected init style. You can override the init style
+# auto-detection here to explicitly use a scheme. This might be
+# useful when you have installed a packages (for instance samba
+# packages) with a different init script layout.
+# There is no default.
+# CTDB_INIT_STYLE=redhat
+
+# The following are specific Samba init scripts / services that you
+# can override from auto-detection.
+# There are no defaults.
+# CTDB_SERVICE_SMB=smb
+# CTDB_SERVICE_NMB=nmb
+# CTDB_SERVICE_WINBIND=winbind
+
+# you may wish to raise the file descriptor limit for ctdb
+# use a ulimit command here. ctdb needs one file descriptor per
+# connected client (ie. one per connected client in Samba)
+#  ulimit -n 10000
+
+# the NODES file must be specified or ctdb won't start
+# it should contain a list of IPs that ctdb will use
+# it must be exactly the same on all cluster nodes
+# defaults to /etc/ctdb/nodes
+# CTDB_NODES=/etc/ctdb/nodes
+
+# a script to run when node health changes
+# CTDB_NOTIFY_SCRIPT=/etc/ctdb/notify.sh
+
+# the directory to put the local ctdb database files in
+# defaults to /var/ctdb
+# CTDB_DBDIR=/var/ctdb
+
+# the directory to put the local persistent ctdb database files in
+# defaults to /var/ctdb/persistent
+# CTDB_DBDIR_PERSISTENT=/var/ctdb/persistent
+
+# the directory where service specific event scripts are stored
+# defaults to /etc/ctdb/events.d
+# CTDB_EVENT_SCRIPT_DIR=/etc/ctdb/events.d
+
+# the location of the local ctdb socket
+# defaults to /tmp/ctdb.socket
+# CTDB_SOCKET=/tmp/ctdb.socket
+
+# what transport to use. Only tcp is currently supported
+# defaults to tcp
+# CTDB_TRANSPORT="tcp"
+
+# These setting allow monitoring for low/out-out of memory conditions.
+#
+# If set, once available memory drops below CTDB_MONITOR_FREE_MEMORY_WARN
+# ctdb will start logging messages that memory is low, but will not
+# take any further action.
+#
+# If the amount of free memory drops below CTDB_MONITOR_FREE_MEMORY 
+# ctdb will fail all service over to a different node and finally shutdown.
+# Once this occurs, the administrator needs to find the reason for the OOM
+# situation, rectify it and restart ctdb with "service ctdb start"
+# The unit is MByte
+# CTDB_MONITOR_FREE_MEMORY_WARN=100
+# CTDB_MONITOR_FREE_MEMORY=10
+
+# When set to yes, the CTDB node will start in DISABLED mode and not host
+# any public ip addresses. The administrator needs to explicitely enable
+# the node with "ctdb enable"
+# CTDB_START_AS_DISABLED="yes"
+
+# LMASTER and RECMASTER capabilities.
+# By default all nodes are capable of both being LMASTER for records and
+# also for taking the RECMASTER role and perform recovery.
+# These parameters can be used to disable these two roles on a node.
+# Note: If there are NO available nodes left in a cluster that can perform
+# the RECMASTER role, the cluster will not be able to recover from a failure
+# and will remain in RECOVERY mode until an RECMASTER capable node becomes
+# available. Same for LMASTER.
+# These parametersd are useful for scenarios where you have one "remote" node
+# in a cluster and you do not want the remote node to be fully participating
+# in the cluster and slow things down.
+# For that case, set both roles to "no" for the remote node on the remote site
+# but leave the roles default to "yes" on the primary nodes in the central
+# datacentre.
+# CTDB_CAPABILITY_RECMASTER=yes
+# CTDB_CAPABILITY_LMASTER=yes
+
+# NAT-GW configuration
+# Some services running on nthe CTDB node may need to originate traffic to
+# remote servers before the node is assigned any IP addresses,
+# This is problematic since before the node has public addresses the node might
+# not be able to route traffic to the public networks.
+# One solution is to have static public addresses assigned with routing
+# in addition to the public address interfaces, thus guaranteeing that
+# a node always can route traffic to the external network.
+# This is the most simple solution but it uses up a large number of 
+# additional ip addresses.
+#
+# A more complex solution is NAT-GW.
+# In this mode we only need one additional ip address for the cluster from
+# the exsternal public network.
+# One of the nodes in the cluster is elected to be hosting this ip address
+# so it can reach the external services. This node is also configured
+# to use NAT MASQUERADING for all traffic from the internal private network
+# to the external network. This node is the NAT-GW node.
+#
+# All other nodes are set up with a default rote with a metric of 10 to point
+# to the nat-gw node.
+# 
+# The effect of this is that only when a node does not have a public address
+# and thus no proper routes to the external world it will instead
+# route all packets through the nat-gw node.
+#
+# CTDB_NATGW_NODES is the list of nodes that belong to this natgw group.
+# You can have multiple natgw groups in one cluster but each node
+# can only belong to one single natgw group.
+#
+# CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
+# CTDB_NATGW_PUBLIC_IFACE=eth0
+# CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
+# CTDB_NATGW_PRIVATE_NETWORK=10.1.1.0/24
+# CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+#
+# Normally any node in the natgw group can act as the natgw master.
+# In some configurations you may have special nodes that is a part of the
+# cluster/natgw group, but where the node lacks connectivity to the 
+# public network.
+# For these cases, set this variable to make these nodes not able to
+# become natgw master.
+#
+# CTDB_NATGW_SLAVE_ONLY=yes
+
+
+# PER_IP_ROUTING configuration
+#
+# Some setups have multiple network interfaces connected to the
+# same network. By default all traffic for a network is routed
+# through only one interface, while the others are idle.
+#
+# On Linux it possible to use policy based routing to spread the load
+# across all interfaces. The is implemented by using a separate
+# routing table per public ip address.
+#
+# The configuration file configured by CTDB_PER_IP_ROUTING_CONF
+# contains the list of additional routes. The routes are bound to the
+# interface that is holding the public ip address.
+#
+# The format of the config file looks like this:
+# <public_ip_address> <network> [<gateway>]
+# and it's possible to have multiple routes per public ip address.
+#
+# If the special value "__auto_link_local__" is used, the config
+# file autogenerated. Each public ip address gets a special route
+# for its own subnet bound to it's current interface.
+# E.g. 10.1.2.3/24 will result in a config file line
+# 10.1.2.3 10.1.2.0/24
+#
+# The CTDB_PER_IP_ROUTING_RULE_PREF option needs to be configured.
+# The value will be passed as "pref" argument of "ip rule".
+# The value should be between 1 and 32765. So that the rule
+# comes after the rule for "local" routing table and before
+# the rule for the "main" routing table. This way the specific
+# routing table just overloads the "main" routing table,
+# this is useful because with the "__auto_link_local__" setup
+# the default route still comes from the "main" routing table.
+#
+# The routing table ids are automaticly allocated. On
+# Linux the routing table ids must be in the range of 0 to 255.
+# But some are reserved values, see /etc/iproute2/rt_tables.
+# You need to configure a range (CTDB_PER_IP_ROUTING_TABLE_ID_LOW
+# and CTDB_PER_IP_ROUTING_TABLE_ID_HIGH) from which the table ids can be taken.
+#
+# The default value for CTDB_PER_IP_ROUTING_CONF is "",
+# which means the feature is disabled by default.
+#
+# CTDB_PER_IP_ROUTING_CONF="/etc/ctdb/per_ip_routing.conf"
+# CTDB_PER_IP_ROUTING_CONF="__auto_link_local__"
+# CTDB_PER_IP_ROUTING_TABLE_ID_LOW=10
+# CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=250
+# CTDB_PER_IP_ROUTING_RULE_PREF=10000
+
+# Make offline interfaces not a reason for being UNHEALTHY.
+# The CTDB_PARTIALLY_ONLINE_INTERFACES option changes
+# the behavior of the 10.interface monitor event.
+# In some setups it's desired that interfaces without
+# an active link don't change the node to unhealthy.
+# ctdbd is just informed about the interface status
+# and "ctdb status" dislays the node as "PARTIALLYONLINE".
+#
+# CTDB_PARTIALLY_ONLINE_INTERFACES="yes"
+
+# where to log messages
+# the default is /var/log/log.ctdb
+# CTDB_LOGFILE=/var/log/log.ctdb
+
+# what debug level to run at. Higher means more verbose
+# the default is ERR
+CTDB_DEBUGLEVEL=ERR
+
+# whether to suppress core files.  Default is no.
+# CTDB_SUPPRESS_COREFILE=yes
+
+# Write debug messages to syslog instead of logfile?
+# The default is not to use syslog.
+# CTDB_SYSLOG=no
+
+# Should the 99.timeout monitor event script be run?
+# This event script just sleeps long enough to trigger the
+# event script timeout. Might be useful for debugging.
+# The default is "no".
+# CTDB_RUN_TIMEOUT_MONITOR=no
+
+# Should ctdbd start with corrupted/unhealthy persistent databases?
+# This parameter specifies the max error count for persistent health
+# checks before the "startup" event. The value must be a positive
+# interger value, "0" or "-1".
+# The default is "0", which means ctdbd will not start.
+# "-1" means wait forever.
+# CTDB_MAX_PERSISTENT_CHECK_ERRORS=0
+
+# All log entries up to level 9 are also collected into a in-memory ringbuffer
+# in addition to the log that is written to the log file.
+# This parameter controls how many entries we allow for this in memory log
+# CTDB_LOG_RINGBUF_SIZE=500000
+
+# Monitor filesystem useage.
+# when set, and the 40.fs_use eventscript is enabled, this variable
+# allows to monitor the filesystem use and flag a node as unhealthy when
+# the filesystem becomes too full.
+# This is useful for example when /var grows too big.
+# Example: monitor both / and /var and make the node unhealthy when eitehr go
+# above 90%
+# CTDB_CHECK_FS_USE="/:90 /var:90"
+
+# Should CTDB automatically start and stop services when it is told to
+# newly manage or no longer manage them?
+CTDB_SERVICE_AUTOSTARTSTOP=yes
+
+# 
+#
+# set any default tuning options for ctdb
+# use CTDB_SET_XXXX=value where XXXX is the name of the tuning
+# variable
+# for example
+#    CTDB_SET_TRAVERSETIMEOUT=60
+# you can get a list of variables using "ctdb listvars"
+
+# any other options you might want. Run ctdbd --help for a list
+# CTDB_OPTIONS=
+

Added: branches/ctdb/squeeze-backports/config/events.d/00.ctdb
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/00.ctdb	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/00.ctdb	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,111 @@
+#!/bin/sh
+############################
+# main event script for ctdb
+#
+# This script is called with one of the following sets of arguments
+#     startup    : called when ctdb starts
+#     shutdown   : called when ctdb shuts down
+#     takeip     : called when an IP address is taken over
+#     releaseip  : called when an IP address is released
+#     recovered  : called when ctdb has finished a recovery event
+
+. $CTDB_BASE/functions
+loadconfig
+
+ctdb_setup_service_state_dir "ctdb"
+
+#
+update_config_from_tdb() {
+
+    # Pull optional ctdb configuration data out of config.tdb
+    _key="public_addresses:node#$(ctdb -t 1 xpnn|sed -e 's/.*://')"
+    _t="$service_state_dir/public_addresses"
+    rm -f "$_t"
+
+    if ctdb pfetch config.tdb "$_key" "$_t" 2>/dev/null && \
+	[ -s "$_t" -a -n "$CTDB_PUBLIC_ADDRESSES"] && \
+	! cmp -s "$_t" "$CTDB_PUBLIC_ADDRESSES" ; then
+
+	echo "CTDB public address configuration has changed."
+	echo "Extracting new configuration from database."
+	diff "$_t" "$CTDB_PUBLIC_ADDRESSES"
+	cp "$_t" "$CTDB_PUBLIC_ADDRESSES"
+	echo "Restarting CTDB"
+	service ctdb restart &
+    fi
+}
+
+ctdb_check_args "$@"
+
+case "$1" in 
+     init)
+        # make sure we have a blank state directory for the scripts to work with
+	rm -rf $CTDB_VARDIR/state
+	# Look at the pattern - this should not be -rf!!!
+	rm -f $ctdb_managed_dir/*
+	mkdir -p $CTDB_VARDIR/state || {
+	    ret=$?
+	    echo "mkdir -p $CTDB_VARDIR/state - failed - $ret"
+	    exit $ret
+	}
+	;;
+
+     setup)
+	# set any tunables from the config file
+	set | grep ^CTDB_SET_ | cut -d_ -f3- | 
+	while read v; do
+	    varname=`echo $v | cut -d= -f1`
+	    value=`echo $v | cut -d= -f2`
+	    ctdb setvar $varname $value || exit 1
+	    echo "Set $varname to $value"
+	done || exit 1
+	;;
+
+    startup)
+	update_config_from_tdb &
+	;;
+    monitor)
+	# Inherit the debug level from ctdbd on each monitor run.  If
+	# there's a more urgent need then override CTDB_CURRENT_DEBUGLEVEL
+	# using a file in $CTDB_BASE/rc.local.d/.
+        ctdb_set_current_debuglevel create
+
+	# We should never enter swap, so SwapTotal == SwapFree.
+	[ "$CTDB_CHECK_SWAP_IS_NOT_USED" = "yes" ] && {
+	    if [ -n "`grep '^Swap\(Total\|Free\)' /proc/meminfo | uniq -s 10 -u`" ]; then
+		echo We are swapping:
+		cat /proc/meminfo
+		ps auxfww
+	    fi
+	}
+
+	# warn when we get low on memory
+	[ -z "$CTDB_MONITOR_FREE_MEMORY_WARN" ] || {
+		FREE_MEM=`free -m | grep "buffers/cache" | while read A B C D ;do echo -n $D ; done`
+		[ `expr "$FREE_MEM" "<" "$CTDB_MONITOR_FREE_MEMORY_WARN"` != "0" ] && {
+			echo "Running low on memory. Free:$FREE_MEM while CTDB treshold is $CTDB_MONITOR_FREE_MEMORY_WARN"
+		}
+	}
+
+	# monitor that we are not running out of memory
+	[ -z "$CTDB_MONITOR_FREE_MEMORY" ] || {
+		FREE_MEM=`free -m | grep "buffers/cache" | while read A B C D ;do echo -n $D ; done`
+		[ `expr "$FREE_MEM" "<" "$CTDB_MONITOR_FREE_MEMORY"` != "0" ] && {
+			echo "OOM. Free:$FREE_MEM while CTDB treshold is $CTDB_MONITOR_FREE_MEMORY"
+			cat /proc/meminfo
+			ps auxfww
+			echo m > /proc/sysrq-trigger
+			ctdb disable
+			sleep 3
+			ctdb shutdown
+		}
+	}
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+# all OK
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/00.ctdb
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/01.reclock
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/01.reclock	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/01.reclock	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,46 @@
+#!/bin/sh
+# script to check accessibility to the reclock file on a node
+
+. $CTDB_BASE/functions
+loadconfig
+
+case "$1" in 
+    init)
+	ctdb_counter_init
+	;;
+    
+    monitor)
+	RECLOCKFILE=$(ctdb -Y getreclock)
+
+	ctdb_counter_incr
+	(ctdb_check_counter_limit 200 >/dev/null 2>&1) || {
+	    echo "Reclock file $RECLOCKFILE\" can not be accessed. Shutting down."
+	    df
+	    sleep 1
+	    ctdb shutdown
+	}
+
+	[ -z "$RECLOCKFILE" ] && {
+	    # we are not using a reclock file
+	    ctdb_counter_init
+	    exit 0
+	}
+
+	# try stat the reclock file as a background process
+	# so that we dont block in case the cluster filesystem is unavailable
+	(
+	    stat $RECLOCKFILE && {
+		# we could stat the file, reset the counter
+		ctdb_counter_init
+	    }
+	) >/dev/null 2>/dev/null &
+
+	ctdb_check_counter_limit 3 quiet
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/01.reclock
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/10.interface
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/10.interface	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/10.interface	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,284 @@
+#!/bin/sh
+
+#################################
+# interface event script for ctdb
+# this adds/removes IPs from your 
+# public interface
+
+. $CTDB_BASE/functions
+loadconfig
+
+[ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
+	CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses
+}
+
+[ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
+	if [ "$1" = "init" ]; then
+		echo "No public addresses file found. Nothing to do for 10.interfaces"
+	fi
+	exit 0
+}
+
+mark_up ()
+{
+    up_interfaces_found=true
+    ctdb setifacelink $1 up >/dev/null 2>&1
+}
+
+mark_down ()
+{
+    fail=true
+    ctdb setifacelink $1 down >/dev/null 2>&1
+}
+
+# This sets $all_interfaces as a side-effect.
+get_all_interfaces ()
+{
+    # Get all the interfaces listed in the public_addresses file
+    all_interfaces=$(sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//" $CTDB_PUBLIC_ADDRESSES)
+
+    # Add some special interfaces if they're defined
+    [ "$CTDB_PUBLIC_INTERFACE" ] && all_interfaces="$CTDB_PUBLIC_INTERFACE $all_interfaces"
+    [ "$CTDB_NATGW_PUBLIC_IFACE" ] && all_interfaces="$CTDB_NATGW_PUBLIC_IFACE $all_interfaces"
+
+    # For all but the 1st line, get the 2nd last field with commas
+    # changes to spaces.
+    ctdb_ifaces=$(ctdb -Y ip -v | sed -e '1d' -e 's/:[^:]*:$//' -e 's/^.*://' -e 's/,/ /g')
+
+    # Add $ctdb_interfaces and uniquify
+    all_interfaces=$(echo $all_interfaces $ctdb_ifaces | tr ' ' '\n' | sort -u)
+}
+
+monitor_interfaces()
+{
+	get_all_interfaces
+
+	fail=false
+	up_interfaces_found=false
+
+	for iface in $all_interfaces ; do
+
+	    ip addr show $iface 2>/dev/null >/dev/null || {
+		echo "WARNING: Interface $iface does not exist but it is used by public addresses."
+		continue
+	    }
+
+	    # These interfaces are sometimes bond devices
+	    # When we use VLANs for bond interfaces, there will only
+	    # be an entry in /proc for the underlying real interface
+	    realiface=`echo $iface |sed -e 's/\..*$//'`
+	    bi=$(get_proc "net/bonding/$realiface" 2>/dev/null) && {
+		echo "$bi" | grep -q 'Currently Active Slave: None' && {
+			echo "ERROR: No active slaves for bond device $realiface"
+			mark_down $iface
+			continue
+		}
+		echo "$bi" | grep -q '^MII Status: up' || {
+			echo "ERROR: public network interface $realiface is down"
+			mark_down $iface
+			continue
+		}
+		echo "$bi" | grep -q '^Bonding Mode: IEEE 802.3ad Dynamic link aggregation' && {
+			# This works around a bug in the driver where the
+			# overall bond status can be up but none of the actual
+			# physical interfaces have a link.
+			echo "$bi" | grep 'MII Status:' | tail -n +2 | grep -q '^MII Status: up' || {
+				echo "ERROR: No active slaves for 802.ad bond device $realiface"
+				mark_down $iface
+				continue
+			}
+		}
+		mark_up $iface
+		continue
+	    }
+
+	    case $iface in
+	    lo*)
+		# loopback is always working
+		mark_up $iface
+		;;
+	    ib*)
+		# we dont know how to test ib links
+		mark_up $iface
+		;;
+	    *)
+		[ -z "$iface" ] || {
+		    [ "$(basename $(readlink /sys/class/net/$iface/device/driver) 2>/dev/null)" = virtio_net ] ||
+		    ethtool $iface | grep -q 'Link detected: yes' || {
+			# On some systems, this is not successful when a
+			# cable is plugged but the interface has not been
+			# brought up previously. Bring the interface up and
+			# try again...
+			ip link set $iface up
+			ethtool $iface | grep -q 'Link detected: yes' || {
+			    echo "ERROR: No link on the public network interface $iface"
+			    mark_down $iface
+			    continue
+			}
+		    }
+		    mark_up $iface
+		}
+		;;
+	    esac
+
+	done
+
+	$fail || return 0
+
+	$up_interfaces_found && \
+	    [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" = "yes" ] && \
+	    return 0
+
+	return 1
+}
+
+ctdb_check_args "$@"
+
+case "$1" in 
+     #############################
+     # called when ctdbd starts up
+     init)
+	# make sure that we only respond to ARP messages from the NIC where
+	# a particular ip address is associated.
+	get_proc sys/net/ipv4/conf/all/arp_filter >/dev/null 2>&1 && {
+	    set_proc sys/net/ipv4/conf/all/arp_filter 1
+	}
+	;;
+
+     #############################
+     # called after ctdbd has done its initial recovery
+     # and we start the services to become healthy
+     startup)
+	# Assume all links are good initially
+	get_all_interfaces
+	for iface in $all_interfaces ; do
+		ctdb setifacelink $iface up >/dev/null 2>/dev/null
+	done
+	
+	monitor_interfaces
+
+	;;
+
+
+     ################################################
+     # called when ctdbd wants to claim an IP address
+     takeip)
+	iface=$2
+	ip=$3
+	maskbits=$4
+
+	add_ip_to_iface $iface $ip $maskbits || {
+		exit 1;
+	}
+
+	# cope with the script being killed while we have the interface blocked
+	iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
+
+	# flush our route cache
+	set_proc sys/net/ipv4/route/flush 1
+	;;
+
+
+     ##################################################
+     # called when ctdbd wants to release an IP address
+     releaseip)
+	# releasing an IP is a bit more complex than it seems. Once the IP
+	# is released, any open tcp connections to that IP on this host will end
+	# up being stuck. Some of them (such as NFS connections) will be unkillable
+	# so we need to use the killtcp ctdb function to kill them off. We also
+	# need to make sure that no new connections get established while we are 
+	# doing this! So what we do is this:
+	# 1) firewall this IP, so no new external packets arrive for it
+	# 2) use netstat -tn to find existing connections, and kill them 
+	# 3) remove the IP from the interface
+	# 4) remove the firewall rule
+	iface=$2
+	ip=$3
+	maskbits=$4
+
+	failed=0
+	# we do an extra delete to cope with the script being killed
+	iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
+	iptables -I INPUT -i $iface -d $ip -j DROP
+	kill_tcp_connections $ip
+
+	delete_ip_from_iface $iface $ip $maskbits || {
+		iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
+		exit 1;
+	}
+
+	iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
+
+	# flush our route cache
+	set_proc sys/net/ipv4/route/flush 1
+	;;
+
+     ##################################################
+     # called when ctdbd wants to update an IP address
+     updateip)
+	# moving an IP is a bit more complex than it seems.
+	# First we drop all traffic on the old interface.
+	# Then we try to add the ip to the new interface and before
+	# we finally remove it from the old interface.
+	#
+	# 1) firewall this IP, so no new external packets arrive for it
+	# 2) add the IP to the new interface
+	# 3) remove the IP from the old interface
+	# 4) remove the firewall rule
+	# 5) use ctdb gratiousarp to propagate the new mac address
+	# 6) use netstat -tn to find existing connections, and tickle them
+	oiface=$2
+	niface=$3
+	ip=$4
+	maskbits=$5
+
+	failed=0
+	# we do an extra delete to cope with the script being killed
+	iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
+	iptables -I INPUT -i $oiface -d $ip -j DROP
+
+	delete_ip_from_iface $oiface $ip $maskbits 2>/dev/null
+	delete_ip_from_iface $niface $ip $maskbits 2>/dev/null
+
+	add_ip_to_iface $niface $ip $maskbits || {
+		iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
+		exit 1;
+	}
+
+	# cope with the script being killed while we have the interface blocked
+	iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
+
+	# flush our route cache
+	set_proc sys/net/ipv4/route/flush 1
+
+	# propagate the new mac address
+	ctdb gratiousarp $ip $niface
+
+	# tickle all existing connections, so that dropped packets
+	# are retransmited and the tcp streams work
+
+	tickle_tcp_connections $ip
+
+	;;
+
+
+     ###########################################
+     # called when ctdbd has finished a recovery
+     recovered)
+	;;
+
+     ####################################
+     # called when ctdbd is shutting down
+     shutdown)
+	;;
+
+     monitor)
+	monitor_interfaces || exit 1
+	;;
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/config/events.d/10.interface
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/11.natgw
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/11.natgw	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/11.natgw	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,109 @@
+#!/bin/sh
+# Script to set up one of the nodes as a NAT gateway for all other nodes.
+# This is used to ensure that all nodes in the cluster can still originate
+# traffic to the external network even if there are no public addresses
+# available.
+#
+
+. $CTDB_BASE/functions
+loadconfig
+
+[ -z "$CTDB_NATGW_NODES" ] && exit 0
+
+# Update capabilities to show whether we support teh NATGW capability or not
+if [ "$CTDB_NATGW_SLAVE_ONLY" = "yes" ] ; then
+	ctdb setnatgwstate off
+else
+	ctdb setnatgwstate on
+fi
+
+delete_all() {
+	local _ip=`echo $CTDB_NATGW_PUBLIC_IP | cut -d '/' -f1`
+	local _maskbits=`echo $CTDB_NATGW_PUBLIC_IP | cut -d '/' -f2`
+
+	[ -z "$CTDB_NATGW_PUBLIC_IFACE" ] || {
+	    delete_ip_from_iface $CTDB_NATGW_PUBLIC_IFACE $_ip $_maskbits 2>/dev/null
+	}
+	ip route del 0.0.0.0/0 metric 10 >/dev/null 2>/dev/null
+
+	# Delete the masquerading setup from a previous iteration where we
+	# were the NAT-GW
+	iptables -D POSTROUTING -t nat -s $CTDB_NATGW_PRIVATE_NETWORK -d ! $CTDB_NATGW_PRIVATE_NETWORK -j MASQUERADE >/dev/null 2>/dev/null
+
+	# remove any iptables rule we may have on this address
+	iptables -D INPUT -p tcp --syn -d $_ip/32 -j REJECT 2>/dev/null
+}
+
+case "$1" in 
+    startup)
+	[ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
+		CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses
+	}
+	egrep "^$CTDB_NATGW_PUBLIC_IP[ \t]" $CTDB_PUBLIC_ADDRESSES >/dev/null
+	[ "$?" = "0" ] && {
+		echo ERROR: NATGW configured to use a public address. NATGW must not use a public address.
+		exit 1
+	}
+
+	# do not send out arp requests from loopback addresses
+	echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
+	;;
+
+    recovered|updatenatgw|ipreallocated)
+	MYPNN=`ctdb pnn | cut -d: -f2`
+	NATGWMASTER=`ctdb natgwlist | head -1 | sed -e "s/ .*//"`
+	NATGWIP=`ctdb natgwlist | head -1 | sed -e "s/^[^ ]* *//"`
+
+	CTDB_NATGW_PUBLIC_IP_HOST=`echo $CTDB_NATGW_PUBLIC_IP | sed -e "s/\/.*/\/32/"`
+
+	# block all incoming connections to the natgw address
+	iptables -D INPUT -p tcp --syn -d $CTDB_NATGW_PUBLIC_IP_HOST -j REJECT 2>/dev/null 
+	iptables -I INPUT -p tcp --syn -d $CTDB_NATGW_PUBLIC_IP_HOST -j REJECT 2>/dev/null 
+
+
+	if [ "$NATGWMASTER" = "-1" ]; then
+		echo "There is no NATGW master node"
+		exit 1
+	fi
+
+	delete_all
+
+	if [ "$MYPNN" = "$NATGWMASTER" ]; then
+		# This is the first node, set it up as the NAT GW
+		echo 1 >/proc/sys/net/ipv4/ip_forward
+		iptables -A POSTROUTING -t nat -s $CTDB_NATGW_PRIVATE_NETWORK -d ! $CTDB_NATGW_PRIVATE_NETWORK -j MASQUERADE
+
+		# block all incoming connections to the natgw address
+		CTDB_NATGW_PUBLIC_IP_HOST=`echo $CTDB_NATGW_PUBLIC_IP | sed -e "s/\/.*/\/32/"`
+		iptables -D INPUT -p tcp --syn -d $CTDB_NATGW_PUBLIC_IP_HOST -j REJECT 2>/dev/null
+		iptables -I INPUT -p tcp --syn -d $CTDB_NATGW_PUBLIC_IP_HOST -j REJECT 2>/dev/null
+
+		ip addr add $CTDB_NATGW_PUBLIC_IP dev $CTDB_NATGW_PUBLIC_IFACE
+		ip route add 0.0.0.0/0 via $CTDB_NATGW_DEFAULT_GATEWAY >/dev/null 2>/dev/null
+	else
+		# This is not the NAT-GW
+		# Assign the public ip to the private interface and make
+		# sure we dont respond to ARPs.
+		# We do this so that the ip address will exist on a
+		# non-loopback interface so that samba may send it along in the
+		# KDC requests.
+		ip route add 0.0.0.0/0 via $NATGWIP metric 10
+		# Make sure winbindd does not stay bound to this address
+		# if we are no longer natgwmaster
+		smbcontrol winbindd ip-dropped $CTDB_NATGW_PUBLIC_IP >/dev/null 2>/dev/null
+	fi
+
+	# flush our route cache
+	echo 1 > /proc/sys/net/ipv4/route/flush
+	;;
+
+    shutdown|stopped|removenatgw)
+	delete_all
+	;;
+
+    *)
+	ctdb_standard_event_handler "@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/11.natgw
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/11.routing
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/11.routing	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/11.routing	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,45 @@
+#!/bin/sh
+# script to add entries to the routing table after we have performed a
+# take ip event
+# (when we do a "releaseip" event and remove an ip address from an interface
+#  the kernel might automatically remove associated entries from
+#  the routing table. This is where we add them back)
+#
+# Routes to add are defined in /etc/ctdb/static-routes.
+# Syntax is :
+# IFACE NET/MASK GATEWAY
+#
+# Example
+# bond1 10.3.3.0/24 10.0.0.1
+
+. $CTDB_BASE/functions
+loadconfig
+
+[ -f $CTDB_BASE/static-routes ] || {
+    exit 0
+}
+
+case "$1" in
+    recovered|ipreallocated)
+        cat $CTDB_BASE/static-routes | while read IFACE DEST GW; do
+            ip route add $DEST via $GW dev $IFACE >/dev/null 2>/dev/null
+        done
+        ;;
+
+    updateip)
+	oiface=$2
+	niface=$3
+	cat $CTDB_BASE/static-routes | egrep "^$niface " | while read IFACE DEST GW; do
+	    ip route add $DEST via $GW dev $IFACE >/dev/null 2>/dev/null
+	done
+	cat $CTDB_BASE/static-routes | egrep "^$oiface " | while read IFACE DEST GW; do
+	    ip route add $DEST via $GW dev $IFACE >/dev/null 2>/dev/null
+	done
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/11.routing
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/13.per_ip_routing
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/13.per_ip_routing	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/13.per_ip_routing	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,494 @@
+#!/bin/sh
+
+. $CTDB_BASE/functions
+loadconfig
+
+ctdb_setup_service_state_dir "per_ip_routing"
+
+[ -z "$CTDB_PER_IP_ROUTING_STATE" ] && {
+	CTDB_PER_IP_ROUTING_STATE="$service_state_dir"
+}
+
+AUTO_LINK_LOCAL="no"
+
+case "$CTDB_PER_IP_ROUTING_CONF" in
+	__auto_link_local__)
+		AUTO_LINK_LOCAL="yes"
+		CTDB_PER_IP_ROUTING_CONF="$CTDB_PER_IP_ROUTING_STATE/auto_link_local.conf"
+		;;
+	*)
+		[ -z "$CTDB_PER_IP_ROUTING_CONF" ] && {
+			#echo "No config file found. Nothing to do for 13.per_ip_routing"
+			exit 0;
+		}
+		;;
+esac
+
+_low=$CTDB_PER_IP_ROUTING_TABLE_ID_LOW
+_high=$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH
+
+test -z "$_low" && {
+	echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_LOW not configured";
+	exit 1;
+}
+test -z "$_high" && {
+	echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_HIGH not configured";
+	exit 1;
+}
+test "$_low" -ge "$_high" && {
+	echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_LOW[$_low] needs to be below CTDB_PER_IP_ROUTING_TABLE_ID_HIGH[$_high]";
+	exit 1;
+}
+
+test -z "$CTDB_PER_IP_ROUTING_RULE_PREF" && {
+	echo "$0: CTDB_PER_IP_ROUTING_RULE_PREF not configured";
+	exit 1;
+}
+
+locknesting=0
+lock_root="$CTDB_PER_IP_ROUTING_STATE"
+host=`hostname`
+
+lock_debug()
+{
+	echo -n ""
+}
+
+############################
+# grab a lock file. Not atomic, but close :)
+# tries to cope with NFS
+lock_file() {
+	if [ -z "$lock_root" ]; then
+		lock_root=`pwd`;
+	fi
+	lckf="$lock_root/$1"
+	machine=`cat "$lckf" 2> /dev/null | cut -d: -f1`
+	pid=`cat "$lckf" 2> /dev/null | cut -d: -f2`
+
+	if [ "$pid" = "$$" ]; then
+		locknesting=`expr $locknesting + 1`
+		lock_debug "lock nesting now $locknesting"
+		return 0
+	fi
+
+	if test -f "$lckf"; then
+		test $machine = $host || {
+			lock_debug "lock file $lckf is valid for other machine $machine"
+			stat -c%y "$lckf"
+			return 1
+		}
+		kill -0 $pid && {
+			lock_debug "lock file $lckf is valid for process $pid"
+			stat -c%y "$lckf"
+			return 1
+		}
+		lock_debug "stale lock file $lckf for $machine:$pid"
+		cat "$lckf"
+		rm -f "$lckf"
+	fi
+	echo "$host:$$" > "$lckf"
+	return 0
+}
+
+############################
+# unlock a lock file
+unlock_file() {
+	if [ -z "$lock_root" ]; then
+		lock_root=`pwd`;
+	fi
+	if [ "$locknesting" != "0" ]; then
+		locknesting=`expr $locknesting - 1`
+		lock_debug "lock nesting now $locknesting"
+	else
+		lckf="$lock_root/$1"
+		rm -f "$lckf"
+	fi
+}
+
+generate_table_id () {
+	local _ip=$1
+	local _ipsdir="$CTDB_PER_IP_ROUTING_STATE/ips"
+	local _ipdir="$_ipsdir/$_ip"
+
+	mkdir -p $_ipdir
+
+	#echo "generate_table_id $_ip"
+
+	local _id=`cat $_ipdir/table_id 2>/dev/null| xargs`
+	test -n "$_id" && {
+		#echo "IP: $_ip => OLD TABLE: $_id"
+		table_id=$_id
+		return 0;
+	}
+
+	local _low="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW"
+	local _high="$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH"
+
+	local _newid=""
+	for _id in `seq $_low $_high | xargs`; do
+		local _table_lck="table_id_$_id.lock"
+		lock_file $_table_lck 2>/dev/null || {
+			continue;
+		}
+		local _taken=`grep "^$_id$" $_ipsdir/*/table_id 2>/dev/null| wc -l | xargs`
+		test x"$_taken" != x"0" && {
+			unlock_file $_table_lck
+			#echo "tableid: $_id taken"
+			continue
+		}
+		_newid=$_id;
+		echo "$_newid" > $_ipdir/table_id
+		unlock_file $_table_lck
+		break;
+	done
+
+	test -z "$_newid" && {
+		echo "generate_table_id: out of table ids: $_low - $_high"
+		exit 1;
+	}
+
+	#echo "IP: $_ip => NEW TABLE: $_newid"
+	table_id=$_newid
+	return 0;
+}
+
+run_release_script_once()
+{
+	local _script=$1
+
+	#echo "run_release_script_once[$_script]"
+
+	test -x "$_script" && {
+		#echo "run it: start"
+		$_script || {
+			echo "release_script: $_script - failed $?"
+			return $?;
+		}
+		#echo "run it: end"
+	}
+
+	echo '#!/bin/sh' > $_script
+	echo '#' >> $_script
+	echo >> $_script
+
+	chmod +x $_script
+
+	return 0;
+}
+
+generate_auto_link_local()
+{
+	local _ip=$1
+	local _maskbits=$2
+
+	#echo "generate_auto_link_local $_ip $_maskbits"
+
+	local _netip=`ipv4_host_addr_to_net_addr $_ip $_maskbits`
+
+	local _line="$_ip $_netip/$_maskbits"
+
+	local _lockfile="$CTDB_PER_IP_ROUTING_CONF.lock"
+	local _script="$CTDB_PER_IP_ROUTING_CONF.$$.sh"
+
+	echo "#!/bin/sh" > $_script
+	echo "#" >> $_script
+	echo "" >> $_script
+	echo "_config=\`cat $CTDB_PER_IP_ROUTING_CONF 2>/dev/null\`" >> $_script
+	echo "_exact=\`echo -n \"\$_config\" | grep \"^$_line\$\" | wc -l | xargs\`" >> $_script
+	echo "" >> $_script
+
+	echo "test x\"\$_exact\" = x\"1\" && {" >> $_script
+	echo "    exit 0;" >> $_script
+	echo "}" >> $_script
+	echo "" >> $_script
+
+	echo "_tmp=\"$CTDB_PER_IP_ROUTING_CONF.$$.tmp\"" >> $_script
+	echo "echo -n \"\$_config\" | grep -v \"^$_ip \" | cat > \$_tmp || {" >> $_script
+	echo "    echo \"echo -n \\\"\$_config\\\" | grep -v \\\"^$_ip \\\" > \$_tmp - failed\"" >> $_script
+	echo "    exit 1;" >> $_script
+	echo "}" >> $_script
+	echo "echo \"$_line\" >> \$_tmp || {" >> $_script
+	echo "    echo \"echo \\\"$_line\\\" >> \$_tmp - failed\"" >> $_script
+	echo "    exit 1;" >> $_script
+	echo "}" >> $_script
+	echo "" >> $_script
+
+	echo "mv \$_tmp $CTDB_PER_IP_ROUTING_CONF || {" >> $_script
+	echo "    echo \"mv \$_tmp $CTDB_PER_IP_ROUTING_CONF - failed\"" >> $_script
+	echo "    exit 1;" >> $_script
+	echo "}" >> $_script
+	echo "" >> $_script
+
+	echo "echo \"Added '$_line' to $CTDB_PER_IP_ROUTING_CONF\"">> $_script
+	echo "exit 0" >> $_script
+
+	chmod +x $_script
+
+	test -f $_lockfile || {
+		touch $_lockfile
+	}
+
+	flock --timeout 30 $_lockfile $_script
+	ret=$?
+	rm $_script
+	return $ret
+}
+
+generate_per_ip_routing()
+{
+	local _ip=$1
+	local _maskbits=$2
+	local _iface=$3
+	local _readonly=$4
+	local _ipdir="$CTDB_PER_IP_ROUTING_STATE/ips/$_ip"
+
+	table_id=""
+	release_script="$_ipdir/per_ip_routing_release.sh"
+	setup_script="$_ipdir/per_ip_routing_setup.sh"
+
+	test x"$_readonly" = x"yes" && {
+		test -d $_ipdir || {
+			return 1;
+		}
+		return 0;
+	}
+
+	mkdir -p $_ipdir || {
+		echo "mkdir -p $_ipdir failed"
+		return 1;
+	}
+	echo "$_ip" > $_ipdir/ip
+
+	generate_table_id $_ip
+
+	test x"$AUTO_LINK_LOCAL" = x"yes" && {
+		generate_auto_link_local $_ip $_maskbits
+	}
+
+	run_release_script_once $release_script
+
+	echo '#!/bin/sh' > $setup_script
+	echo '#' >> $setup_script
+	echo >> $setup_script
+	chmod +x $setup_script
+
+	return 0;
+}
+
+setup_per_ip_routing()
+{
+	local _ip=$1
+	local _iface=$2
+	local _table_id=$3
+	local _release_script=$4
+	local _setup_script=$5
+
+	local _config=`cat $CTDB_PER_IP_ROUTING_CONF`
+	local _lines=`echo -n "$_config" | grep -n "^$_ip " | cut -d ':' -f1 | xargs`
+
+	local _pref="$CTDB_PER_IP_ROUTING_RULE_PREF"
+
+	test -n "$_lines" && {
+		echo "ip rule del from $_ip pref $_pref table $_table_id" >> $_release_script
+		echo "ip route flush table $_table_id 2>/dev/null" >> $_release_script
+
+		cmd="ip rule del from $_ip pref $_pref 2>/dev/null"
+		echo "$cmd" >> $_setup_script
+
+		cmd="ip route flush table $_table_id 2>/dev/null"
+		echo "$cmd" >> $_setup_script
+
+		cmd="ip rule add from $_ip pref $_pref table $_table_id"
+		echo "$cmd || {" >> $_setup_script
+		echo "    echo \"$cmd - failed \$ret\"" >> $_setup_script
+		echo "    exit \$ret" >> $_setup_script
+		echo "}" >> $_setup_script
+	}
+	local _l
+	for _l in $_lines; do
+		local _line=`echo -n "$_config" | head -n $_l | tail -n 1`
+		local _dest=`echo -n "$_line" | cut -d ' ' -f 2`
+		local _gw=`echo -n "$_line" | cut -d ' ' -f 3`
+
+		local _via=""
+		test -n "$_gw" && {
+			_via="via $_gw"
+		}
+
+		cmd="ip route add $_dest $_via dev $_iface table $_table_id"
+		echo "$cmd || {" >> $_setup_script
+		echo "    echo \"$cmd - failed \$ret\"" >> $_setup_script
+		echo "    exit \$ret" >> $_setup_script
+		echo "}" >> $_setup_script
+	done
+
+	$_setup_script
+	return $?;
+}
+
+ctdb_check_args "$@"
+
+case "$1" in
+     #############################
+     # called when ctdbd starts up
+     startup)
+	# cleanup old rules
+	pref=$CTDB_PER_IP_ROUTING_RULE_PREF
+	rules=`ip rule show | grep "^$pref:" | sed -e 's/.*from \([^ ][^ ]*\) lookup \([^ ][^ ]*\)/\2;\1/' | xargs`
+	for r in $rules; do
+		table_id=`echo -n "$r" | cut -d ';' -f1`
+		ip=`echo -n "$r" | cut -d ';' -f2-`
+
+		echo "Removing ip rule for public address $ip for routing table $table_id"
+		cmd="ip rule del from $ip table $table_id pref $pref"
+		#echo $cmd
+		eval $cmd
+		cmd="ip route flush table $table_id"
+		#echo $cmd
+		eval $cmd 2>/dev/null
+	done
+
+	# make sure that we only respond to ARP messages from the NIC where
+	# a particular ip address is associated.
+	[ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
+	    echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
+	}
+
+	mkdir -p $CTDB_PER_IP_ROUTING_STATE
+
+	;;
+
+     shutdown)
+
+	for s in $CTDB_PER_IP_ROUTING_STATE/ips/*/per_ip_routing_release.sh; do
+		run_release_script_once "$s"
+	done
+	rm -rf $CTDB_PER_IP_ROUTING_STATE
+
+	;;
+
+     ################################################
+     # called when ctdbd wants to claim an IP address
+     takeip)
+	iface=$2
+	ip=$3
+	maskbits=$4
+
+	ipv4_is_valid_addr $ip || {
+		echo "$0: $1 not an ipv4 address skipping IP:$ip"
+		exit 0;
+	}
+
+	[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
+		echo "$0: $1 No state directory found, waiting for startup."
+		exit 0;
+	}
+
+	generate_per_ip_routing $ip $maskbits $iface "no" || {
+		echo "$0: $1: generate_per_ip_routing $ip $maskbits $iface no - failed"
+		exit 1;
+	}
+
+	setup_per_ip_routing $ip $iface $table_id $release_script $setup_script || {
+		echo "$0: $1: setup_per_ip_routing $ip $iface $table_id $release_script $setup_script - failed"
+		exit 1;
+	}
+
+	setup_iface_ip_readd_script $iface $ip $maskbits $setup_script || {
+		echo "$0: $1: setup_iface_ip_readd_script $iface $ip $maskbits $setup_script - failed"
+		exit 1;
+	}
+
+	# flush our route cache
+	echo 1 > /proc/sys/net/ipv4/route/flush
+	ctdb gratiousarp $ip $iface
+
+	;;
+
+     ################################################
+     # called when ctdbd wants to claim an IP address
+     updateip)
+	oiface=$2
+	niface=$3
+	ip=$4
+	maskbits=$5
+
+	ipv4_is_valid_addr $ip || {
+		echo "$0: $1 not an ipv4 address skipping IP:$ip"
+		exit 0;
+	}
+
+	[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
+		echo "$0: $1 No state directory found, waiting for startup."
+		exit 0;
+	}
+
+	generate_per_ip_routing $ip $maskbits $niface "no" || {
+		echo "$0: $1: generate_per_ip_routing $ip $maskbits $niface no - failed"
+		exit 1;
+	}
+
+	setup_per_ip_routing $ip $niface $table_id $release_script $setup_script || {
+		echo "$0: $1: setup_per_ip_routing $ip $niface $table_id $release_script $setup_script - failed"
+		exit 1;
+	}
+
+	setup_iface_ip_readd_script $niface $ip $maskbits $setup_script || {
+		echo "$0: $1: setup_iface_ip_readd_script $niface $ip $maskbits $setup_script - failed"
+		exit 1;
+	}
+
+	# flush our route cache
+	echo 1 > /proc/sys/net/ipv4/route/flush
+
+	ctdb gratiousarp $ip $niface
+	tickle_tcp_connections $ip
+
+	;;
+
+     ##################################################
+     # called when ctdbd wants to release an IP address
+     releaseip)
+	iface=$2
+	ip=$3
+	maskbits=$4
+
+	ipv4_is_valid_addr $ip || {
+		echo "$0: $1 not an ipv4 address skipping IP:$ip"
+		exit 0;
+	}
+
+	[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
+		echo "$0: $1 No state directory found, waiting for startup."
+		exit 0;
+	}
+
+	generate_per_ip_routing $ip $maskbits $iface "yes" || {
+		echo "$0: $1: generate_per_ip_routing $ip $maskbits $iface yes - failed"
+		exit 1;
+	}
+
+	run_release_script_once "$release_script"
+
+	;;
+
+
+     ###########################################
+     # called when ctdbd has finished a recovery
+     recovered)
+	;;
+
+     ####################################
+     # called when ctdbd is shutting down
+     shutdown)
+	;;
+
+     monitor)
+	;;
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/config/events.d/13.per_ip_routing
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/20.multipathd
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/20.multipathd	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/20.multipathd	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,94 @@
+#!/bin/sh
+# ctdb event script for monitoring the multipath daemon
+#
+# Configure monitporing of multipath devices by listing the device serials
+# in /etc/ctdb/multipathd :
+#   CTDB_MONITOR_MPDEVICES="device1 device2 ..."
+#
+
+. $CTDB_BASE/functions
+
+service_name="multipathd"
+
+loadconfig 
+
+[ -z "$CTDB_MONITOR_MPDEVICES" ] && {
+	exit 0
+}
+
+ctdb_setup_service_state_dir
+
+MPFAILURE="$service_state_dir/failure"
+
+multipathd_check_background()
+{
+	for DEVICE in $CTDB_MONITOR_MPDEVICES; do
+		# check that we can see all devices
+		if [ -z "`multipath -ll $DEVICE`" ]; then
+			echo Device $DEVICE not known to multipathd
+			exit 1
+		fi
+
+		# check that all devices are active
+		if [ -z "`multipath -ll $DEVICE|grep prio|grep active`" ]; then
+			echo Device $DEVICE has no active paths
+			exit 1
+		fi
+	done
+	exit 0
+}
+
+multipathd_check()
+{
+	# run the actual check in the background since the call to 
+	# multipath may block.
+	(
+	multipathd_check_background &
+	pid="$!"
+	timeleft=10
+
+	while [ $timeleft -gt 0 ]; do
+		timeleft=$(($timeleft - 1))
+
+		# see if the process still exists
+		kill -0 $pid > /dev/null 2>&1 || {
+			# it doesn't exist, grab its exit status
+			wait $pid
+			[ $? = 0 ] || {
+				echo "20.multipathd: multipath background update exited with status $?"
+				touch $MPFAILURE
+				exit 1
+			}
+			rm $MPFAILURE 2>/dev/null
+			exit 0
+		}
+		sleep 1
+	done
+	echo "20.multipathd: Callout to multipath checks hung."
+	touch $MPFAILURE
+	exit 1
+	) &
+
+	if [ -f $MPFAILURE ]; then
+		return 1
+	else
+		return 0
+	fi
+}
+
+case "$1" in
+    monitor)
+	multipathd_check
+	[ "$?" = "0" ] || {
+		echo 20.multipathd: monitoring of multipathing failed
+		exit 1
+	}
+	exit 0
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/20.multipathd
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/31.clamd
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/31.clamd	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/31.clamd	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,49 @@
+#!/bin/sh
+# event script to manage clamd in a cluster environment
+
+. $CTDB_BASE/functions
+
+detect_init_style
+
+case $CTDB_INIT_STYLE in
+	redhat)
+		service_name="clamd"
+		service_config="clamd"
+		;;
+	*)
+		service_name="clamav"
+		service_config="clamav"
+		;;
+esac
+
+service_start ()
+{
+    service $service_name stop > /dev/null 2>&1
+    service $service_name start
+}
+
+loadconfig
+
+ctdb_start_stop_service
+
+is_ctdb_managed_service || exit 0
+
+case "$1" in 
+    startup)
+	ctdb_service_start
+        ;;
+
+    shutdown)
+        ctdb_service_stop
+        ;;
+
+    monitor)
+        ctdb_check_unix_socket ${CTDB_CLAMD_SOCKET} || exit $?
+        ;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/31.clamd
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/40.fs_use
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/40.fs_use	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/40.fs_use	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,52 @@
+#!/bin/sh
+# ctdb event script for checking local file system utilization
+
+. $CTDB_BASE/functions
+loadconfig
+
+case "$1" in 
+    monitor)
+        # check each specified fs to be checked
+        # config format is <fs_mount>:<fs_threshold>
+        for fs in $CTDB_CHECK_FS_USE
+        do
+            # parse fs_mount and fs_threshold
+            fs_mount=`echo "$fs" | awk -F : '{print $1}'`
+            fs_threshold=`echo "$fs" | awk -F : '{print $2}'`
+
+            # check if given fs_mount is existing directory
+            if [ ! -d "$fs_mount" ]; then
+                echo "$0: Directory $fs_mount does not exist"
+                exit 1
+            fi
+
+            # check if given fs_threshold is number
+            if ! (echo "$fs_threshold" | egrep -q '^[0-9]+$')  ; then
+                echo "$0: Threshold $fs_threshold is invalid number"
+                exit 1
+            fi
+
+            # get utilization of given fs from df
+            fs_usage=`df -kP $fs_mount | grep '%' | awk {'print $5'} | sed 's/%//g' | tail -n 1`
+
+            # check if fs_usage is number
+            if ! (echo "$fs_usage" | egrep -q '^[0-9]+$') ; then
+                echo "$0: FS utilization $fs_usage is invalid number"
+                exit 1
+            fi
+
+            # check if fs_usage is higher than or equal to fs_threshold
+            if [ "$fs_usage" -ge "$fs_threshold" ] ; then
+                echo "ERROR: Utilization of $fs_mount ($fs_usage%) is higher than threshold ($fs_threshold%)"
+                exit 1
+            fi
+        done
+
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0

Added: branches/ctdb/squeeze-backports/config/events.d/40.vsftpd
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/40.vsftpd	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/40.vsftpd	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,59 @@
+#!/bin/sh
+# event strict to manage vsftpd in a cluster environment
+
+. $CTDB_BASE/functions
+
+service_name="vsftpd"
+# make sure the service is stopped first
+service_start ()
+{
+    service $service_name stop > /dev/null 2>&1
+    service $service_name start
+}
+service_stop ()
+{
+    service $service_name stop
+}
+
+service_fail_limit=2
+service_tcp_ports=21
+
+loadconfig
+
+ctdb_start_stop_service
+
+is_ctdb_managed_service || exit 0
+
+ctdb_service_check_reconfigure
+
+case "$1" in 
+    startup)
+	ctdb_service_start
+	;;
+
+    shutdown)
+	ctdb_service_stop
+	;;
+
+    takeip|releaseip)
+	ctdb_service_set_reconfigure
+	;;
+
+    monitor)
+	if [ -n "$service_tcp_ports" ] ; then
+	    if ctdb_check_tcp_ports $service_tcp_ports ; then
+		ctdb_counter_init
+	    else
+		ctdb_counter_incr
+		ctdb_check_counter_limit
+		exit 0 # only count 1 failure per monitor event
+	    fi
+	fi	
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/40.vsftpd
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/41.httpd
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/41.httpd	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/41.httpd	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,85 @@
+#!/bin/sh
+# event script to manage httpd in a cluster environment
+
+. $CTDB_BASE/functions
+
+detect_init_style
+
+case $CTDB_INIT_STYLE in
+    redhat)
+	service_name="httpd"
+	service_config="http"
+	;;
+    suse|debian|*)
+	service_name="apache2"
+	service_config="apache2"
+	;;
+esac
+
+# RHEL5 sometimes use a SIGKILL to terminate httpd, which then leaks
+# semaphores.  This is a hack to clean them up.
+cleanup_httpd_semaphore_leak() {
+    killall -q -0 "$service_name" ||
+    for i in $(ipcs -s | awk '$3 == "apache" { print $2 }') ; do
+	ipcrm -s $i
+    done
+}
+
+##########
+
+service_start ()
+{
+    cleanup_httpd_semaphore_leak
+    service $service_name start
+}
+service_stop ()
+{
+    service $service_name stop
+    killall -q -9 $service_name || true
+}
+
+loadconfig
+
+ctdb_start_stop_service
+
+is_ctdb_managed_service || exit 0
+
+ctdb_service_check_reconfigure
+
+case "$1" in
+    startup)
+	ctdb_service_start
+	;;
+
+    shutdown)
+	ctdb_service_stop
+	;;
+
+    monitor)
+	if ctdb_check_tcp_ports 80 >/dev/null 2>/dev/null ; then
+	    ctdb_counter_init
+	else
+	    ctdb_counter_incr
+
+	    ctdb_check_counter warn -eq 2 || {
+		echo "HTTPD is not running. Trying to restart HTTPD."
+		service_stop
+		service_start
+		exit 0
+	    }
+            ctdb_check_counter warn -ge 5 || {
+		echo "HTTPD is not running. Trying to restart HTTPD."
+		service_stop
+		service_start
+		exit 1
+	    }
+	fi
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/config/events.d/41.httpd
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/50.samba
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/50.samba	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/50.samba	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,317 @@
+#!/bin/sh
+# ctdb event script for Samba
+
+. $CTDB_BASE/functions
+
+detect_init_style
+
+case $CTDB_INIT_STYLE in
+	suse)
+		CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb}
+		CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-nmb}
+		CTDB_SERVICE_WINBIND=${CTDB_SERVICE_WINBIND:-winbind}
+		;;
+	debian)
+		CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-samba}
+		CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""}
+		CTDB_SERVICE_WINBIND=${CTDB_SERVICE_WINBIND:-winbind}
+		;;
+	*)
+		# should not happen, but for now use redhat style as default:
+		CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb}
+		CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""}
+		CTDB_SERVICE_WINBIND=${CTDB_SERVICE_WINBIND:-winbind}
+		;;
+esac
+
+service_name="samba"
+
+loadconfig
+
+ctdb_setup_service_state_dir
+
+service_start ()
+{
+	# If set then we force-start the relevant service.
+	_service_name="$1"
+
+	# make sure samba is not already started
+	if [ "$_service_name" = "samba" ] || \
+	    is_ctdb_managed_service "samba" ; then
+		service "$CTDB_SERVICE_SMB" stop > /dev/null 2>&1
+		if [ -n "$CTDB_SERVICE_NMB" ] ; then
+		    service "$CTDB_SERVICE_NMB" stop > /dev/null 2>&1
+		fi
+		killall -0 -q smbd && {
+		    sleep 1
+		    # make absolutely sure samba is dead
+		    killall -q -9 smbd
+		}
+
+		killall -0 -q nmbd && {
+		    sleep 1
+		    # make absolutely sure samba is dead
+		    killall -q -9 nmbd
+		}
+	fi
+
+	# make sure winbind is not already started
+	if [ "$_service_name" = "winbind" ] || \
+	    check_ctdb_manages_winbind ; then
+		service "$CTDB_SERVICE_WINBIND" stop > /dev/null 2>&1
+		killall -0 -q winbindd && {
+		    sleep 1
+          	    # make absolutely sure winbindd is dead
+		    killall -q -9 winbindd
+		}
+
+	fi
+
+	# start the winbind service
+	if [ "$_service_name" = "winbind" ] || \
+	    check_ctdb_manages_winbind ; then
+		service "$CTDB_SERVICE_WINBIND" start || {
+		    echo failed to start winbind
+		    exit 1
+		}
+	fi
+
+	# start Samba service. Start it reniced, as under very heavy load 
+	# the number of smbd processes will mean that it leaves few cycles for
+	# anything else
+	if [ "$_service_name" = "samba" ] || \
+	    is_ctdb_managed_service "samba" ; then
+		net serverid wipe
+
+		if [ -n "$CTDB_SERVICE_NMB" ] ; then
+		    nice_service "$CTDB_SERVICE_NMB" start || {
+			echo failed to start nmbd
+			exit 1
+		    }
+		fi
+		nice_service "$CTDB_SERVICE_SMB" start || {
+			echo failed to start samba
+			exit 1
+		}
+	fi
+}
+
+service_stop ()
+{
+	# If set then we force-stop the relevant service.
+	_service_name="$1"
+
+	# shutdown Samba when ctdb goes down
+	if [ "$_service_name" = "samba" ] || \
+	    is_ctdb_managed_service "samba" ; then
+		service "$CTDB_SERVICE_SMB" stop
+		if [ -n "$CTDB_SERVICE_NMB" ] ; then
+		    service "$CTDB_SERVICE_NMB" stop
+		fi
+	fi
+
+	# stop the winbind service
+	if [ "$_service_name" = "winbind" ] || \
+	    check_ctdb_manages_winbind ; then
+		service "$CTDB_SERVICE_WINBIND" stop
+	fi
+}
+
+service_reconfigure ()
+{
+    # Samba automatically reloads config - no restart needed.
+    :
+}
+
+# set default samba cleanup period - in minutes
+[ -z "$SAMBA_CLEANUP_PERIOD" ] && {
+    SAMBA_CLEANUP_PERIOD=10
+}
+
+# we keep a cached copy of smb.conf here
+smbconf_cache="$service_state_dir/smb.conf.cache"
+
+
+#############################################
+# update the smb.conf cache in the foreground
+testparm_foreground_update() {
+    testparm -s 2> /dev/null | egrep -v 'registry.shares.=|include.=' > "$smbconf_cache"
+}
+
+#############################################
+# update the smb.conf cache in the background
+testparm_background_update() {
+    # if the cache doesn't exist, then update in the foreground
+    [ -f $smbconf_cache ] || {
+	testparm_foreground_update
+    }
+    # otherwise do a background update
+    (
+	tmpfile="${smbconf_cache}.$$"
+	testparm -s > $tmpfile 2> /dev/null &
+	# remember the pid of the teamparm process
+	pid="$!"
+	# give it 10 seconds to run
+	timeleft=10
+	while [ $timeleft -gt 0 ]; do
+	    timeleft=$(($timeleft - 1))
+	    # see if the process still exists
+	    kill -0 $pid > /dev/null 2>&1 || {
+		# it doesn't exist, grab its exit status
+		wait $pid
+		[ $? = 0 ] || {
+		    echo "50.samba: smb.conf background update exited with status $?"
+		    rm -f "${tmpfile}"
+		    exit 1
+		}		
+		# put the new smb.conf contents in the cache (atomic rename)
+		# make sure we remove references to the registry while doing 
+		# this to ensure that running testparm on the cache does
+		# not use the registry
+		egrep -v 'registry.shares.=|include.=' < "$tmpfile" > "${tmpfile}.2"
+		rm -f "$tmpfile"
+		mv -f "${tmpfile}.2" "$smbconf_cache" || {
+		    echo "50.samba: failed to update background cache"
+		    rm -f "${tmpfile}.2"
+		    exit 1
+		}
+		exit 0
+	    }
+	    # keep waiting for testparm to finish
+	    sleep 1
+	done
+	# it took more than 10 seconds - kill it off
+	rm -f "${tmpfile}"
+	kill -9 "$pid" > /dev/null 2>&1
+	echo "50.samba: timed out updating smbconf cache in background"
+	exit 1
+    ) &
+}
+
+##################################################
+# show the testparm output using a cached smb.conf 
+# to avoid registry access
+testparm_cat() {
+    [ -f $smbconf_cache ] || {
+	testparm_foreground_update
+    }
+    testparm -s "$smbconf_cache" "$@" 2>/dev/null
+}
+
+# function to see if ctdb manages winbind - this overrides with extra
+# logic if $CTDB_MANAGES_WINBIND is not set or null.
+check_ctdb_manages_winbind() {
+    if is_ctdb_managed_service "winbind" ; then
+	return 0
+    elif [ -n "$CTDB_MANAGES_WINBIND" ] ; then
+	# If this variable is set we want to respect it.  We return
+	# false here because we know it is not set to "yes" - if it
+	# were then the 1st "if" above would have succeeded.
+	return 1
+    else
+	_secmode=`testparm_cat --parameter-name=security`
+	case "$_secmode" in
+	    ADS|DOMAIN)
+		return 0
+		;;
+	    *)
+		return 1
+		;;
+	esac
+    fi
+}
+
+list_samba_shares ()
+{
+    testparm_cat |
+    sed -n -e 's@^[[:space:]]*path[[:space:]]*=[[:space:]]@@p' |
+    sed -e 's/"//g'
+}
+
+
+###########################
+# periodic cleanup function
+periodic_cleanup() {
+    # running smbstatus scrubs any dead entries from the connections
+    # and sessionid database
+    # echo "Running periodic cleanup of samba databases"
+    smbstatus -np > /dev/null 2>&1 &
+}
+
+###########################
+
+ctdb_start_stop_service
+ctdb_start_stop_service "winbind"
+
+is_ctdb_managed_service || is_ctdb_managed_service "winbind" || exit 0
+
+###########################
+
+case "$1" in 
+     startup)
+	ctdb_service_start
+	;;
+	
+     shutdown)
+	ctdb_service_stop
+	;;
+
+     monitor)
+	# Create a dummy file to track when we need to do periodic cleanup
+	# of samba databases
+	periodic_cleanup_file="$service_state_dir/periodic_cleanup"
+	[ -f "$periodic_cleanup_file" ] || {
+		touch "$periodic_cleanup_file"
+	}
+	[ `find "$periodic_cleanup_file" -mmin +$SAMBA_CLEANUP_PERIOD | wc -l` -eq 1 ] && {
+		# Cleanup the databases
+	    	periodic_cleanup
+		touch "$periodic_cleanup_file"
+	}
+
+	is_ctdb_managed_service "samba" && {
+		[ "$CTDB_SAMBA_SKIP_SHARE_CHECK" = "yes" ] || {
+			testparm_background_update
+
+			testparm_cat | egrep '^WARNING|^ERROR|^Unknown' && {
+			    testparm_foreground_update
+			    testparm_cat | egrep '^WARNING|^ERROR|^Unknown' && {
+				echo "ERROR: testparm shows smb.conf is not clean"
+				exit 1
+			    }
+			}
+			
+			list_samba_shares |
+			ctdb_check_directories_probe || {
+			    testparm_foreground_update
+			    list_samba_shares |
+			    ctdb_check_directories
+			} || exit $?
+		}
+
+		smb_ports="$CTDB_SAMBA_CHECK_PORTS"
+		[ -z "$smb_ports" ] && {
+			smb_ports=`testparm_cat --parameter-name="smb ports"`
+		}
+		ctdb_check_tcp_ports $smb_ports || exit $?
+	}
+
+	# check winbind is OK
+	check_ctdb_manages_winbind && {
+		ctdb_check_command "winbind" "wbinfo -p"
+	}
+	;;
+
+     takeip|releaseip)
+	iface=$2
+	ip=$3
+	maskbits=$4
+
+	smbcontrol winbindd ip-dropped $ip >/dev/null 2>/dev/null
+	;;
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/50.samba
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/60.ganesha
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/60.ganesha	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/60.ganesha	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,158 @@
+#!/bin/sh
+# script to manage nfs in a clustered environment
+
+start_nfs() {
+       mkdir -p $CTDB_VARDIR/state/nfs
+       mkdir -p $CTDB_VARDIR/state/statd/ip
+       ctdb_service_stop
+       ctdb_service_start
+       echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
+}
+
+. $CTDB_BASE/functions
+
+loadconfig nfs
+
+[ "$NFS_SERVER_MODE" = "GANESHA" ] || exit 0
+
+service_name="nfs-ganesha-gpfs"
+
+ctdb_start_stop_service
+
+is_ctdb_managed_service || exit 0
+
+case "$1" in
+     init)
+       # read statd from persistent database
+       ;;
+     startup)
+       ctdb_service_start
+       mkdir -p $CTDB_VARDIR/state/statd
+       touch $CTDB_VARDIR/state/statd/update-trigger
+       ;;
+
+     shutdown)
+       ctdb_service_stop
+       ;;
+
+     takeip)
+       ctdb_service_set_reconfigure
+       ;;
+
+     releaseip)
+       ctdb_service_set_reconfigure
+       ;;
+
+      monitor)
+       if ctdb_service_needs_reconfigure ; then
+           ctdb_service_reconfigure
+           exit 0
+       fi
+
+       update_tickles 2049
+
+       # check that statd responds to rpc requests
+       # if statd is not running we try to restart it
+       if ctdb_check_rpc "STATD" status 1 >/dev/null ; then
+               (service_name="nfs_statd"; ctdb_counter_init)
+       else
+               p="rpc.statd" ; cmd="$p"
+               cmd="${cmd}${STATD_HOSTNAME:+ -n }${STATD_HOSTNAME}"
+               cmd="${cmd}${STATD_PORT:+ -p }${STATD_PORT}"
+               cmd="${cmd}${STATD_OUTGOING_PORT:+ -o }${STATD_OUTGOING_PORT}"
+               (
+                       service_name="nfs_statd"
+                       ctdb_counter_incr
+                       ctdb_check_counter_limit 10 quiet >/dev/null
+               ) || {
+                       echo "$ctdb_check_rpc_out"
+                       echo "Trying to restart STATD [$cmd]"
+               }
+               $cmd
+       fi
+
+       # check that NFS responds to rpc requests
+       [ "$CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK" = "yes" ] || {
+           if ctdb_check_rpc "NFS" nfs 3 >/dev/null ; then
+               (service_name="nfs_knfsd"; ctdb_counter_init)
+           else
+               (
+                       service_name="nfs_knfsd"
+                       ctdb_counter_incr
+
+                       ctdb_check_counter_equal 10 || {
+                               echo "Trying to restart NFS service"
+                               ctdb_service_stop
+                               ctdb_service_start
+                               exit 0
+                       }
+
+                       ctdb_check_counter_limit 15 quiet >/dev/null
+               ) || {
+                       echo "$ctdb_check_rpc_out"
+                       echo "Trying to restart NFS service"
+                       ctdb_service_stop
+                       ctdb_service_start
+                       exit 1
+               }
+           fi
+       }
+
+       # and that its directories are available
+       [ "$CTDB_NFS_SKIP_SHARE_CHECK" = "yes" ] || {
+           grep Path /etc/ganesha/gpfs.ganesha.exports.conf |
+           cut -f2 -d\" | ctdb_check_directories
+       } || exit $?
+
+       # check that lockd responds to rpc requests
+       ctdb_check_rpc "LOCKD" nlockmgr 4 || {
+               echo "Trying to restart lock manager service"
+               ctdb_service_stop
+               ctdb_service_start
+               exit 1
+       }
+
+       # check mounts responds to rpc requests
+       ctdb_check_rpc "MOUNTD" mountd 1 >/dev/null || {
+               echo "Trying to restart mountd service"
+               ctdb_service_stop
+               ctdb_service_start
+               exit 1
+       }
+
+       # rquotad needs special handling since it is sometimes not started
+       # correctly on RHEL5
+       # this is not a critical service so we dont flag the node as unhealthy
+       ctdb_check_rpc "RQUOTAD" rquotad 1 || {
+               p="rpc.rquotad"
+               cmd="${p}${RQUOTAD_PORT:+ -p }${RQUOTAD_PORT}"
+               echo "Trying to restart RQUOTAD [${cmd}]"
+               killall -q -9 $p
+               $cmd &
+       }
+
+       # once every 60 seconds, update the statd state database for which
+       # clients need notifications
+       LAST_UPDATE=`stat --printf="%Y" $CTDB_VARDIR/state/statd/update-trigger 2>/dev/null`
+       CURRENT_TIME=`date +"%s"`
+       [ $CURRENT_TIME -ge $(($LAST_UPDATE + 60)) ] && {
+           mkdir -p $CTDB_VARDIR/state/statd
+           touch $CTDB_VARDIR/state/statd/update-trigger
+           $CTDB_BASE/statd-callout updatelocal &
+           $CTDB_BASE/statd-callout updateremote &
+       }
+               ;;
+
+    ipreallocated)
+       # if the ips have been reallocated, we must restart the lockmanager
+       # across all nodes and ping all statd listeners
+       [ -x $CTDB_BASE/statd-callout ] && {
+               $CTDB_BASE/statd-callout notify &
+       } >/dev/null 2>&1
+       ;;
+    *)
+       ctdb_standard_event_handler "$@"
+       ;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/60.ganesha
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/60.nfs
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/60.nfs	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/60.nfs	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,130 @@
+#!/bin/sh
+# script to manage nfs in a clustered environment
+
+. $CTDB_BASE/functions
+
+service_name="nfs"
+service_start ()
+{
+    startstop_nfs stop
+    startstop_nfs start
+    set_proc "sys/net/ipv4/tcp_tw_recycle" 1
+}
+service_stop ()
+{
+    startstop_nfs stop
+}
+service_reconfigure ()
+{
+    startstop_nfs restart
+
+    # if the ips have been reallocated, we must restart the lockmanager
+    # across all nodes and ping all statd listeners
+    [ -x $CTDB_BASE/statd-callout ] && {
+	$CTDB_BASE/statd-callout notify &
+    } >/dev/null 2>&1
+}
+
+loadconfig
+
+[ "$NFS_SERVER_MODE" != "GANESHA" ] || exit 0
+
+ctdb_setup_service_state_dir
+
+statd_update_trigger="$service_state_dir/update-trigger"
+# We want this file to always exist.  The corner case is when
+# auto-start/stop is switched off, NFS is added as a managed service
+# some time after ctdbd is started and someone else starts the NFS
+# service for us.  In this case this file might not otherwise exist
+# when we get to a monitor event.
+touch "$statd_update_trigger"
+
+ctdb_start_stop_service
+
+is_ctdb_managed_service || exit 0
+
+ctdb_service_check_reconfigure
+
+case "$1" in 
+     init)
+	# read statd from persistent database
+	;;
+     startup)
+	ctdb_service_start
+	;;
+
+     shutdown)
+	ctdb_service_stop
+	;;
+
+     takeip)
+	ctdb_service_set_reconfigure
+	;;
+
+     releaseip)
+	ctdb_service_set_reconfigure
+	;;
+
+      monitor)
+	# Check that directories for shares actually exist.
+	[ "$CTDB_NFS_SKIP_SHARE_CHECK" = "yes" ] || {
+	    exportfs -v | grep '^/' | 
+	    sed -r -e 's@[[:space:]]+[^[:space:]()]+\([^[:space:]()]+\)$@@' | 
+	    sort -u | 
+	    ctdb_check_directories 
+	} || exit $?
+
+	update_tickles 2049
+
+	# check that statd responds to rpc requests
+	# if statd is not running we try to restart it
+	# we only do this IF we have a rpc.statd command.
+	# For platforms where rpc.statd does not exist, we skip
+	# the check completely
+        p="rpc.statd"
+        which $p >/dev/null 2>/dev/null && \
+	    nfs_check_rpc_service "statd" \
+	        -ge 6 "verbose unhealthy" \
+	        -eq 4 "verbose restart" \
+		-eq 2 "restart:bs"
+
+	# check that NFS responds to rpc requests
+	if [ "$CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK" != "yes" ] ; then
+	    nfs_check_rpc_service "knfsd" \
+		-ge 6 "verbose unhealthy" \
+		-eq 4 "verbose restart" \
+		-eq 2 "restart:bs"
+	fi
+
+	# check that lockd responds to rpc requests
+	nfs_check_rpc_service "lockd" \
+	    -ge 15 "verbose restart unhealthy" \
+	    -eq 10 "restart:bs"
+
+	# mountd is sometimes not started correctly on RHEL5
+	nfs_check_rpc_service "mountd" \
+	    -ge 10 "verbose restart:b unhealthy" \
+	    -eq 5 "restart:b"
+
+	# rquotad is sometimes not started correctly on RHEL5
+	# not a critical service so we dont flag the node as unhealthy
+	nfs_check_rpc_service "rquotad" \
+	    -gt 0 "verbose restart:b"
+
+	# once every 600 seconds, update the statd state database for which
+	# clients need notifications
+	LAST_UPDATE=`stat --printf="%Y" "$statd_update_trigger"`
+	CURRENT_TIME=`date +"%s"`
+	[ $CURRENT_TIME -ge $(($LAST_UPDATE + 600)) ] && {
+	    touch "$statd_update_trigger"
+	    $CTDB_BASE/statd-callout updatelocal &
+	    $CTDB_BASE/statd-callout updateremote &
+	}
+       	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/60.nfs
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/62.cnfs
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/62.cnfs	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/62.cnfs	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,78 @@
+#!/bin/sh
+# event script to integrate with gpfs cnfs
+
+. $CTDB_BASE/functions
+
+loadconfig
+
+ctdb_setup_service_state_dir "gpfs"
+
+check_if_healthy() {
+        mkdir -p "$service_state_dir/fs"
+
+        [ -f "$service_state_dir/gpfsnoquorum" ] && {
+                logger No GPFS quorum. Node is UNHEALTHY
+                $CTDB_BASE/events.d/62.cnfs unhealthy "No GPFS quorum. Nodfe is UNHEALTHY."
+		exit 0
+	}
+
+        logger All required GPFS resources are available. CNFS part is healthy.
+        $CTDB_BASE/events.d/62.cnfs healthy
+}
+
+case "$1" in
+    startup)
+        check_if_healthy
+        ;;
+
+
+    gpfsquorumreached)
+        rm -f "$service_state_dir/gpfsnoquorum"
+        logger "GPFS quorum has been reached."
+        check_if_healthy
+        ;;
+
+    gpfsquorumloss)
+        touch "$service_state_dir/gpfsnoquorum"
+        logger "GPFS quorum has been lost."
+        $CTDB_BASE/events.d/62.cnfs unhealthy "GPFS quorum was lost! Marking node as UNHEALTHY."
+        ;;
+
+    unhealthy)
+        # Mark the node as UNHEALTHY which means all public addresses
+        # will be migrated off the node.
+        shift
+        TMPFILE=/tmp/ctdb.cnfs.$$
+        echo "$*" > $TMPFILE
+        ctdb_setstatus unhealthy $TMPFILE
+        rm $TMPFILE
+
+        # force a monitor event so we pick up immediately that this script
+        # will now fail and make the node unhealthy.
+        ctdb eventscript monitor
+
+        # Wait until we no longer serve any ip addresses at all
+        PNN=`ctdb pnn | cut -d: -f2`
+        while `ctdb -Y ip | cut -d: -f3 | egrep "^$PNN$" >/dev/null`; do
+                sleep 1
+        done
+        ;;
+
+    healthy)
+        # mark the node as healthy
+        ctdb_setstatus healthy
+        ;;
+
+
+    monitor)
+        ctdb_checkstatus
+        exit $?
+        ;;
+
+    *)
+        ctdb_standard_event_handler "$@"
+        ;;
+esac
+
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/config/events.d/62.cnfs
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/70.iscsi
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/70.iscsi	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/70.iscsi	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,62 @@
+#!/bin/sh
+# ctdb event script for TGTD based iSCSI
+
+. $CTDB_BASE/functions
+
+service_name="iscsi"
+
+ctdb_start_stop_service
+
+is_ctdb_managed_service || exit 0
+
+[ -z "$CTDB_START_ISCSI_SCRIPTS" ] && {
+	echo "No iscsi start script directory found"
+	exit 0
+}
+
+case "$1" in 
+    recovered)
+	# block the iscsi port
+	iptables -I INPUT 1 -p tcp --dport 3260 -j DROP
+	
+	# shut down the iscsi service
+	killall -9 tgtd >/dev/null 2>/dev/null
+
+	THIS_NODE=`ctdb status | grep "THIS NODE" | sed -e "s/pnn://" -e "s/ .*//"`
+	[ -z $THIS_NODE ] && {
+		echo "70.iscsi: Failed to get node pnn"
+		exit 0
+	}
+
+	# start the iscsi daemon
+	tgtd >/dev/null 2>/dev/null
+
+	for NODE in `ctdb ip | grep -v "Public" | egrep " ${THIS_NODE}$" | sed -e "s/ .*//"`; do
+		[ -f $CTDB_START_ISCSI_SCRIPTS/${NODE}.sh ] && {
+			echo Starting iscsi service for public address $NODE
+			$CTDB_START_ISCSI_SCRIPTS/${NODE}.sh
+		}
+	done
+
+	# remove all iptables rules
+	while iptables -D INPUT -p tcp --dport 3260 -j DROP 2>/dev/null >/dev/null ;  do
+	    :
+	done
+
+	;;
+
+    shutdown)
+	# shutdown iscsi when ctdb goes down
+	killall -9 tgtd >/dev/null 2>/dev/null
+	;;
+
+    monitor)
+	ctdb_check_tcp_ports 3260 || exit $?
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/70.iscsi
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/91.lvs
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/91.lvs	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/91.lvs	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,86 @@
+#!/bin/sh
+# script to manage the lvs ip multiplexer for a single public address cluster
+
+. $CTDB_BASE/functions
+
+loadconfig ctdb
+
+[ -z "$CTDB_LVS_PUBLIC_IP" ] && exit 0
+[ -z "$CTDB_PUBLIC_INTERFACE" ] && exit 0
+
+[ -x /sbin/ipvsadm ] || {
+    echo "LVS configured but /sbin/ipvsadm is not installed."
+    exit 0
+}
+
+case "$1" in 
+     startup)
+	ipvsadm -D -t $CTDB_LVS_PUBLIC_IP:0
+	ipvsadm -D -u $CTDB_LVS_PUBLIC_IP:0
+
+	ip addr add $CTDB_LVS_PUBLIC_IP/32 dev lo scope host >/dev/null 2>/dev/null
+
+	# do not respond to ARPs that are for ip addresses with scope 'host'
+	echo 3 > /proc/sys/net/ipv4/conf/all/arp_ignore
+	# do not send out arp requests from loopback addresses
+	echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
+	;;
+
+     shutdown)
+	ipvsadm -D -t $CTDB_LVS_PUBLIC_IP:0
+	ipvsadm -D -u $CTDB_LVS_PUBLIC_IP:0
+
+	# remove the ip
+	ip addr del $CTDB_LVS_PUBLIC_IP/32 dev lo >/dev/null 2>/dev/null
+
+	# flush our route cache
+	echo 1 > /proc/sys/net/ipv4/route/flush
+	;;
+
+     recovered|stopped|ipreallocated)
+	# kill off any tcp connections
+	ipvsadm -D -t $CTDB_LVS_PUBLIC_IP:0
+	ipvsadm -D -u $CTDB_LVS_PUBLIC_IP:0
+	kill_tcp_connections_local_only $CTDB_LVS_PUBLIC_IP
+
+	PNN=`ctdb pnn | sed -e "s/.*PNN://"`
+	LVSMASTER=`ctdb lvsmaster | sed -e "s/.*Node //" -e "s/ .*//"`
+
+	[ "$PNN" != "$LVSMASTER" ] && {
+	    # we are not the lvs master so we have to
+	    # change the ip address to have scope host so we wont respond
+	    # to arps
+	    ip addr del $CTDB_LVS_PUBLIC_IP/32 dev lo >/dev/null 2>/dev/null
+	    ip addr add $CTDB_LVS_PUBLIC_IP/32 dev lo scope host >/dev/null 2>/dev/null
+	    exit 0
+	}
+
+	# change the scope so we start responding to arps
+	ip addr del $CTDB_LVS_PUBLIC_IP/32 dev lo >/dev/null 2>/dev/null
+	ip addr add $CTDB_LVS_PUBLIC_IP/32 dev lo >/dev/null 2>/dev/null
+
+	ipvsadm -A -t $CTDB_LVS_PUBLIC_IP:0 -p 1999999 -s lc
+	ipvsadm -A -u $CTDB_LVS_PUBLIC_IP:0 -p 1999999 -s lc
+
+	# add all nodes (except ourselves) to the lvs config
+	ctdb lvs | egrep -v "^$PNN:" | sed -e "s/.*://" | while read IP; do
+		ipvsadm -a -t $CTDB_LVS_PUBLIC_IP:0 -r $IP -g
+		ipvsadm -a -u $CTDB_LVS_PUBLIC_IP:0 -r $IP -g
+	done
+	# and add the localhost too
+	ipvsadm -a -t $CTDB_LVS_PUBLIC_IP:0 -r 127.0.0.1
+	ipvsadm -a -u $CTDB_LVS_PUBLIC_IP:0 -r 127.0.0.1
+
+	# send out a gratious arp so our peers will update their arp tables
+	ctdb gratiousarp $CTDB_LVS_PUBLIC_IP $CTDB_PUBLIC_INTERFACE >/dev/null 2>/dev/null
+
+	# flush our route cache
+	echo 1 > /proc/sys/net/ipv4/route/flush
+	;;
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/events.d/91.lvs
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/99.timeout
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/99.timeout	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/99.timeout	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# Event script to just sleep longer than the timeout
+# in the monitor action. The purpose is to trigger
+# the event timeout mechanism.
+
+. $CTDB_BASE/functions
+loadconfig ctdb
+
+[ "$CTDB_RUN_TIMEOUT_MONITOR" = "yes" ] || exit 0
+
+case "$1" in
+    monitor)
+	TIMEOUT=$(ctdb listvars | awk '$1 == "EventScriptTimeout" {print $3}')
+	echo "sleeping for $((TIMEOUT * 2)) seconds..."
+	sleep $((TIMEOUT * 2))
+	;;
+
+
+    *)
+	ctdb_standard_event_handler "$@"
+	;;
+esac
+
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/config/events.d/99.timeout
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/events.d/README
===================================================================
--- branches/ctdb/squeeze-backports/config/events.d/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/events.d/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,171 @@
+This directory is where you should put any local or application
+specific event scripts for ctdb to call.
+
+All event scripts start with the prefic 'NN.' where N is a digit.
+The event scripts are run in sequence based on NN.
+Thus 10.interfaces will be run before 60.nfs.
+
+Each NN must be unique and duplicates will cause undefined behaviour.
+I.e. having both 10.interfaces and 10.otherstuff is not allowed.
+
+
+As a special case, any eventscript that ends with a '~' character will be 
+ignored since this is a common postfix that some editors will append to 
+older versions of a file.
+
+
+The eventscripts are called with varying number of arguments.
+The first argument is the "event" and the rest of the arguments depend
+on which event was triggered.
+
+All of the events except the 'shutdown' and 'startrecovery' events will be
+called with the ctdb daemon in NORMAL mode (ie. not in recovery)
+
+The events currently implemented are
+init
+	This event does not take any additional arguments.
+	This event is only invoked once, when ctdb is starting up.
+	This event is used to do some cleanup work from earlier runs
+	and prepare the basic setup.
+	At this stage 'ctdb' commands won't work.
+
+	Example: 00.ctdb cleans up $CTDB_VARDIR/state
+
+setup
+	This event does not take any additional arguments.
+	This event is only invoked once, when ctdb is starting up.
+	This event is used to do some cleanup work from earlier runs
+	and prepare the basic setup.
+
+	Example: 00.ctdb cleans up $CTDB_VARDIR/state
+
+startup
+	This event does not take any additional arguments.
+	This event is only invoked once, when ctdb has finished
+	the initial recoveries. This event is used to wait for
+	the service to start and all resources for the service
+	becoming available.
+
+	This is used to prevent ctdb from starting up and advertize its
+	services until all dependent services have become available.
+
+	All services that are managed by ctdb should implement this
+	event and use it to start the service.
+
+	Example: 50.samba uses this event to start the samba daemon
+	and then wait until samba and all its associated services have
+	become available. It then also proceeds to wait until all
+	shares have become available.
+
+shutdown
+	This event is called when the ctdb service is shuting down.
+	
+	All services that are managed by ctdb should implement this event
+	and use it to perform a controlled shutdown of the service.
+
+	Example: 60.nfs uses this event to shut down nfs and all associated
+	services and stop exporting any shares when this event is invoked.
+
+monitor
+	This event is invoked every X number of seconds.
+	The interval can be configured using the MonitorInterval tunable
+	but defaults to 15 seconds.
+
+	This event is triggered by ctdb to continuously monitor that all
+	managed services are healthy.
+	When invoked, the event script will check that the service is healthy
+	and return 0 if so. If the service is not healthy the event script
+	should return non zero.
+
+	If a service returns nonzero from this script this will cause ctdb
+	to consider the node status as UNHEALTHY and will cause the public
+	address and all associated services to be failed over to a different
+	node in the cluster.
+
+	All managed services should implement this event.
+
+	Example: 10.interfaces which checks that the public interface (if used)
+	is healthy, i.e. it has a physical link established.
+
+takeip
+	This event is triggered everytime the node takes over a public ip
+	address during recovery.
+	This event takes three additional arguments :
+	'interface' 'ipaddress' and 'netmask'
+
+	Before this event there will always be a 'startrecovery' event.
+
+	This event will always be followed by a 'recovered' event once
+	all ipaddresses have been reassigned to new nodes and the ctdb database
+	has been recovered.
+	If multiple ip addresses are reassigned during recovery it is
+	possible to get several 'takeip' events followed by a single 
+	'recovered' event.
+
+	Since there might involve substantial work for the service when an ip
+	address is taken over and since multiple ip addresses might be taken 
+	over in a single recovery it is often best to only mark which addresses
+	are being taken over in this event and defer the actual work to 
+	reconfigure or restart the services until the 'recovered' event.
+
+	Example: 60.nfs which just records which ip addresses are being taken
+	over into a local state directory   and which defers the actual
+	restart of the services until the 'recovered' event.
+
+
+releaseip
+	This event is triggered everytime the node releases a public ip
+	address during recovery.
+	This event takes three additional arguments :
+	'interface' 'ipaddress' and 'netmask'
+
+	In all other regards this event is analog to the 'takeip' event above.
+
+	Example: 60.nfs
+
+updateip
+	This event is triggered everytime the node moves a public ip
+	address between interfaces
+	This event takes four additional arguments :
+	'old-interface' 'new-interface' 'ipaddress' and 'netmask'
+
+	Example: 10.interface
+
+startrecovery
+	This event is triggered everytime we start a recovery process
+	or before we start changing ip address allocations.
+
+recovered
+	This event is triggered every time we have finished a full recovery
+	and also after we have finished reallocating the public ip addresses
+	across the cluster.
+
+	Example: 60.nfs which if the ip address configuration has changed
+	during the recovery (i.e. if addresses have been taken over or
+	released) will kill off any tcp connections that exist for that
+	service and also send out statd notifications to all registered 
+	clients.
+	
+stopped
+	This event is called when a node is STOPPED and can be used to
+	perform additional cleanup that is required.
+	Note that a stopped node is considered inactive, so it will not
+	be issuing the recovered event once the cluster has recovered.
+	See 91.lvs for a use of this event.
+
+Additional note for takeip, releaseip, recovered:
+
+ALL services that depend on the ip address configuration of the node must 
+implement all three of these events.
+
+ALL services that use TCP should also implement these events and at least
+kill off any tcp connections to the service if the ip address config has 
+changed in a similar fashion to how 60.nfs does it.
+The reason one must do this is that ESTABLISHED tcp connections may survive
+when an ip address is released and removed from the host until the ip address
+is re-takenover.
+Any tcp connections that survive a release/takeip sequence can potentially
+cause the client/server tcp connection to get out of sync with sequence and 
+ack numbers and cause a disruptive ack storm.
+
+

Added: branches/ctdb/squeeze-backports/config/functions
===================================================================
--- branches/ctdb/squeeze-backports/config/functions	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/functions	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1428 @@
+# Hey Emacs, this is a -*- shell-script -*- !!!
+
+# utility functions for ctdb event scripts
+
+PATH=/bin:/usr/bin:/usr/sbin:/sbin:$PATH
+
+[ -z "$CTDB_VARDIR" ] && {
+    export CTDB_VARDIR="/var/ctdb"
+}
+[ -z "$CTDB_ETCDIR" ] && {
+    export CTDB_ETCDIR="/etc"
+}
+
+#######################################
+# pull in a system config file, if any
+_loadconfig() {
+
+    if [ -z "$1" ] ; then
+	foo="${service_config:-${service_name}}"
+	if [ -n "$foo" ] ; then
+	    loadconfig "$foo"
+	fi
+    elif [ "$1" != "ctdb" ] ; then
+	loadconfig "ctdb"
+    fi
+
+    if [ -f $CTDB_ETCDIR/sysconfig/$1 ]; then
+	. $CTDB_ETCDIR/sysconfig/$1
+    elif [ -f $CTDB_ETCDIR/default/$1 ]; then
+	. $CTDB_ETCDIR/default/$1
+    elif [ -f $CTDB_BASE/sysconfig/$1 ]; then
+	. $CTDB_BASE/sysconfig/$1
+    fi
+}
+
+loadconfig () {
+    _loadconfig "$@"
+}
+
+##############################################################
+# make sure CTDB_CURRENT_DEBUGLEVEL is set to the desired debug level
+# (integer)
+#
+# If it is already set then do nothing, since it might have been set
+# via a file in rc.local.d/.  If it is not set then set it by sourcing
+# /var/ctdb/eventscript_debuglevel. If this file does not exist then
+# create it using output from "ctdb getdebug".  If the option 1st arg
+# is "create" then don't source an existing file but create a new one
+# instead - this is useful for creating the file just once in each
+# event run in 00.ctdb.  If there's a problem getting the debug level
+# from ctdb then it is silently set to 0 - no use spamming logs if our
+# debug code is broken...
+ctdb_set_current_debuglevel ()
+{
+    [ -z "$CTDB_CURRENT_DEBUGLEVEL" ] || return 0
+
+    _f="$CTDB_VARDIR/eventscript_debuglevel"
+
+    if [ "$1" = "create" -o ! -r "$_f" ] ; then
+	_t=$(ctdb getdebug -Y 2>/dev/null)
+	# get last field of output
+	_t="${_t%:}"
+	_t="${_t##*:}"
+	# Defaults to 0
+	echo "export CTDB_CURRENT_DEBUGLEVEL=\"${_t:-0}\"" >"$_f"
+    fi
+
+    . "$_f"
+}
+
+debug ()
+{
+    if [ $CTDB_CURRENT_DEBUGLEVEL -ge 4 ] ; then
+	# If there are arguments then echo them.  Otherwise expect to
+	# use stdin, which allows us to pass lots of debug using a
+	# here document.
+	if [ -n "$1" ] ; then
+	    echo "DEBUG: $*"
+	elif ! tty -s ; then
+	    sed -e 's@^@DEBUG: @'
+	fi
+    fi
+}
+
+##############################################################
+# check number of args for different events
+ctdb_check_args ()
+{
+    case "$1" in
+	takeip|releaseip)
+	    if [ $# != 4 ]; then
+		echo "ERROR: must supply interface, IP and maskbits"
+		exit 1
+	    fi
+	    ;;
+	updateip)
+	    if [ $# != 5 ]; then
+		echo "ERROR: must supply old interface, new interface, IP and maskbits"
+		exit 1
+	    fi
+	    ;;
+    esac
+}
+
+##############################################################
+# determine on what type of system (init style) we are running
+detect_init_style() {
+    # only do detection if not already set:
+    test "x$CTDB_INIT_STYLE" != "x" && return
+
+    if [ -x /sbin/startproc ]; then
+        CTDB_INIT_STYLE="suse"
+    elif [ -x /sbin/start-stop-daemon ]; then
+        CTDB_INIT_STYLE="debian"
+    else
+        CTDB_INIT_STYLE="redhat"
+    fi
+}
+
+######################################################
+# simulate /sbin/service on platforms that don't have it
+# _service() makes it easier to hook the service() function for
+# testing.
+_service ()
+{
+  _service_name="$1"
+  _op="$2"
+
+  # do nothing, when no service was specified
+  [ -z "$_service_name" ] && return
+
+  if [ -x /sbin/service ]; then
+      $_nice /sbin/service "$_service_name" "$_op"
+  elif [ -x $CTDB_ETCDIR/init.d/$_service_name ]; then
+      $_nice $CTDB_ETCDIR/init.d/$_service_name "$_op"
+  elif [ -x $CTDB_ETCDIR/rc.d/init.d/$_service_name ]; then
+      $_nice $CTDB_ETCDIR/rc.d/init.d/$_service_name "$_op"
+  fi
+}
+
+service()
+{
+    _nice=""
+    _service "$@"
+}
+
+######################################################
+# simulate /sbin/service (niced) on platforms that don't have it
+nice_service()
+{
+    _nice="nice"
+    _service "$@"
+}
+
+######################################################
+# wrapper around /proc/ settings to allow them to be hooked
+# for testing
+# 1st arg is relative path under /proc/, 2nd arg is value to set
+set_proc ()
+{
+    echo "$2" >"/proc/$1"
+}
+
+######################################################
+# wrapper around getting file contents from /proc/ to allow
+# this to be hooked for testing
+# 1st arg is relative path under /proc/
+get_proc ()
+{
+    cat "/proc/$1"
+}
+
+######################################################
+# Check that an RPC service is healthy -
+# this includes allowing a certain number of failures
+# before marking the NFS service unhealthy.
+#
+# usage: nfs_check_rpc_service SERVICE_NAME [ triple ...]
+#
+# each triple is a set of 3 arguments: an operator, a 
+# fail count limit and an action string.
+#
+# For example:
+#
+# 	nfs_check_rpc_service "lockd" \
+#	    -ge 15 "verbose restart unhealthy" \
+#	    -eq 10 "restart:bs"
+#
+# says that if lockd is down for 15 iterations then do
+# a verbose restart of lockd and mark the node unhealthy.
+# Before this, after 10 iterations of failure, the
+# service is restarted silently in the background.
+# Order is important: the number of failures need to be
+# specified in reverse order because processing stops
+# after the first condition that is true.
+######################################################
+nfs_check_rpc_service ()
+{
+    _prog_name="$1" ; shift
+
+    _version=1
+    _rpc_prog="$_prog_name"
+    _restart=""
+    _opts=""
+    case "$_prog_name" in
+	knfsd)
+	    _rpc_prog=nfs
+	    _version=3
+	    _restart="echo 'Trying to restart NFS service'"
+	    _restart="${_restart}; startstop_nfs restart"
+	    ;;
+	mountd)
+	    _opts="${MOUNTD_PORT:+ -p }${MOUNTD_PORT}"
+	    ;;
+	rquotad)
+	    _opts="${RQUOTAD_PORT:+ -p }${RQUOTAD_PORT}"
+	    ;;
+	lockd)
+	    _rpc_prog=nlockmgr
+	    _version=4
+	    _restart="echo 'Trying to restart lock manager service'"
+	    _restart="${_restart}; startstop_nfslock restart"
+	    ;;
+	statd)
+	    _rpc_prog=status
+	    _opts="${STATD_HOSTNAME:+ -n }${STATD_HOSTNAME}"
+	    _opts="${_opts}${STATD_PORT:+ -p }${STATD_PORT}"
+	    _opts="${_opts}${STATD_OUTGOING_PORT:+ -o }${STATD_OUTGOING_PORT}"
+	    ;;
+	*)
+	    echo "Internal error: unknown RPC program \"$_prog_name\"."
+	    exit 1
+    esac
+
+    _service_name="nfs_${_prog_name}"
+
+    if ctdb_check_rpc "$_rpc_prog" $_version >/dev/null ; then
+	ctdb_counter_init "$_service_name"
+	return 0
+    fi
+
+    ctdb_counter_incr "$_service_name"
+
+    while [ -n "$3" ] ; do
+	ctdb_check_counter "quiet" "$1" "$2" "$_service_name" || {
+	    for _action in $3 ; do
+		case "$_action" in
+		    verbose)
+			echo "$ctdb_check_rpc_out"
+			;;
+		    restart|restart:*)
+			# No explicit command specified, construct rpc command.
+			if [ -z "$_restart" ] ; then
+			    _p="rpc.${_prog_name}"
+			    _restart="echo 'Trying to restart $_prog_name [${_p}${_opts}]'"
+			    _restart="${_restart}; killall -q -9 $_p"
+			    _restart="${_restart}; $_p $_opts"
+			fi
+
+			# Process restart flags...
+			_flags="${_action#restart:}"
+			# There may not have been a colon...
+			[ "$_flags" != "$_action" ] || _flags=""
+			# q=quiet - everything to /dev/null
+			if [ "${_flags#*q}" != "$_flags" ] ; then
+			    _restart="{ ${_restart} ; } >/dev/null 2>&1"
+			fi
+			# s=stealthy - last command to /dev/null
+			if [ "${_flags#*s}" != "$_flags" ] ; then
+			    _restart="${_restart} >/dev/null 2>&1"
+			fi
+			# b=background - the whole thing, easy and reliable
+			if [ "${_flags#*b}" != "$_flags" ] ; then
+			    _restart="{ ${_restart} ; } &"
+			fi
+
+			# Do it!
+			eval "${_restart}"
+			;;
+		    unhealthy)
+			exit 1
+			;;
+		    *)
+			echo "Internal error: unknown action \"$_action\"."
+			exit 1
+		esac
+	    done
+
+	    # Only process the first action group.
+	    break
+	}
+	shift 3
+    done
+}
+
+######################################################
+# check that a rpc server is registered with portmap
+# and responding to requests
+# usage: ctdb_check_rpc SERVICE_NAME VERSION
+######################################################
+ctdb_check_rpc ()
+{
+    progname="$1"
+    version="$2"
+
+    if ! ctdb_check_rpc_out=$(rpcinfo -u localhost $progname $version 2>&1) ; then
+	ctdb_check_rpc_out="ERROR: $progname failed RPC check:
+$ctdb_check_rpc_out"
+	echo "$ctdb_check_rpc_out"
+	return 1
+    fi
+}
+
+######################################################
+# check a set of directories is available
+# return 1 on a missing directory
+# usage: ctdb_check_directories_probe SERVICE_NAME <directories...>
+######################################################
+ctdb_check_directories_probe() {
+    while IFS="" read d ; do
+	case "$d" in
+	    *%*)
+		continue
+		;;
+	    *)
+		[ -d "${d}/." ] || return 1
+	esac
+    done
+}
+
+######################################################
+# check a set of directories is available
+# usage: ctdb_check_directories SERVICE_NAME <directories...>
+######################################################
+ctdb_check_directories() {
+    n="${1:-${service_name}}"
+    ctdb_check_directories_probe || {
+	echo "ERROR: $n directory \"$d\" not available"
+	exit 1
+    }
+}
+
+######################################################
+# check a set of tcp ports
+# usage: ctdb_check_tcp_ports <ports...>
+######################################################
+
+# This flag file is created when a service is initially started.  It
+# is deleted the first time TCP port checks for that service succeed.
+# Until then ctdb_check_tcp_ports() prints a more subtle "error"
+# message if a port check fails.
+_ctdb_check_tcp_common ()
+{
+    _ctdb_service_started_file="$ctdb_fail_dir/$service_name.started"
+}
+
+ctdb_check_tcp_init ()
+{
+    _ctdb_check_tcp_common
+    mkdir -p "${_ctdb_service_started_file%/*}" # dirname
+    touch "$_ctdb_service_started_file"
+}
+
+ctdb_check_tcp_ports()
+{
+    if [ -z "$1" ] ; then
+	echo "INTERNAL ERROR: ctdb_check_tcp_ports - no ports specified"
+	exit 1
+    fi
+
+    # Set default value for CTDB_TCP_PORT_CHECKS if unset.
+    # If any of these defaults are unsupported then this variable can
+    # be overridden in /etc/sysconfig/ctdb or via a file in
+    # /etc/ctdb/rc.local.d/.
+    : ${CTDB_TCP_PORT_CHECKERS:=ctdb nmap netstat}
+
+    for _c in $CTDB_TCP_PORT_CHECKERS ; do
+	ctdb_check_tcp_ports_$_c "$@"
+	case "$?" in
+	    0)
+		_ctdb_check_tcp_common
+		rm -f "$_ctdb_service_started_file"
+		return 0
+		;;
+	    1)
+		_ctdb_check_tcp_common
+		if [ ! -f "$_ctdb_service_started_file" ] ; then
+		    echo "ERROR: $service_name tcp port $_p is not responding"
+		    debug <<EOF
+$ctdb_check_tcp_ports_debug
+EOF
+		else
+		    echo "INFO: $service_name tcp port $_p is not responding"
+		fi
+
+		return 1
+		;;
+	    127)
+		debug <<EOF
+ctdb_check_ports - checker $_c not implemented
+output from checker was:
+$ctdb_check_tcp_ports_debug
+EOF
+		;;
+	    *)
+		
+	esac
+    done
+
+    echo "INTERNAL ERROR: ctdb_check_ports - no working checkers in CTDB_TCP_PORT_CHECKERS=\"$CTDB_TCP_PORT_CHECKERS\""
+
+    return 127
+}
+
+ctdb_check_tcp_ports_netstat ()
+{
+    _cmd='netstat -l -t -n'
+    _ns=$($_cmd 2>&1)
+    if [ $? -eq 127 ] ; then
+	# netstat probably not installed - unlikely?
+	ctdb_check_tcp_ports_debug="$_ns"
+	return 127
+    fi
+
+    for _p ; do  # process each function argument (port)
+	for _a in '0\.0\.0\.0' '::' ; do
+	    _pat="[[:space:]]${_a}:${_p}[[:space:]]+[^[:space:]]+[[:space:]]+LISTEN"
+	    if echo "$_ns" | grep -E -q "$_pat" ; then
+		# We matched the port, so process next port
+		continue 2
+	    fi
+	done
+
+	# We didn't match the port, so flag an error.
+	ctdb_check_tcp_ports_debug="$_cmd shows this output:
+$_ns"
+	return 1
+    done
+
+    return 0
+}
+
+ctdb_check_tcp_ports_nmap ()
+{
+    # nmap wants a comma-separated list of ports
+    _ports=""
+    for _p ; do
+	_ports="${_ports}${_ports:+,}${_p}"
+    done
+
+    _cmd="nmap -n -oG - -PS 127.0.0.1 -p $_ports"
+
+    _nmap_out=$($_cmd 2>&1)
+    if [ $? -eq 127 ] ; then
+	# nmap probably not installed
+	ctdb_check_tcp_ports_debug="$_nmap_out"
+	return 127
+    fi
+
+    # get the port-related output
+    _port_info=$(echo "$_nmap_out" | sed -n -r -e 's@^.*Ports:[[:space:]]@@p')
+
+    for _p ; do
+	# looking for something like this:
+	#  445/open/tcp//microsoft-ds///
+	# possibly followed by a comma
+	_t="$_p/open/tcp//"
+	case "$_port_info" in
+	    # The info we're after must be either at the beginning of
+	    # the string or it must follow a space.
+            $_t*|*\ $_t*) : ;;
+	    *)
+		# Nope, flag an error...
+		ctdb_check_tcp_ports_debug="$_cmd shows this output:
+$_nmap_out"
+		return 1
+	esac
+    done
+
+    return 0
+}
+
+# Use the new "ctdb checktcpport" command to check the port.
+# This is very cheap.
+ctdb_check_tcp_ports_ctdb ()
+{
+    for _p ; do  # process each function argument (port)
+	_cmd="ctdb checktcpport $_p"
+	_out=$($_cmd 2>&1)
+	_ret=$?
+	case "$_ret" in
+	    0)
+		ctdb_check_tcp_ports_debug="\"$_cmd\" was able to bind to port"
+		return 1
+		;;
+	    98)
+		# Couldn't bind, something already listening, next port...
+		continue
+		;;
+	    *)
+		ctdb_check_tcp_ports_debug="$_cmd (exited with $_ret) with output:
+$_out"
+		# assume not implemented
+		return 127
+	esac
+    done
+
+    return 0
+}
+
+######################################################
+# check a unix socket
+# usage: ctdb_check_unix_socket SERVICE_NAME <socket_path>
+######################################################
+ctdb_check_unix_socket() {
+    socket_path="$1"
+    [ -z "$socket_path" ] && return
+
+    if ! netstat --unix -a -n | grep -q "^unix.*LISTEN.*${socket_path}$"; then
+        echo "ERROR: $service_name socket $socket_path not found"
+        return 1
+    fi
+}
+
+######################################################
+# check a command returns zero status
+# usage: ctdb_check_command SERVICE_NAME <command>
+######################################################
+ctdb_check_command() {
+  service_name="$1"
+  wait_cmd="$2"
+  [ -z "$wait_cmd" ] && return;
+  $wait_cmd > /dev/null 2>&1 || {
+      echo "ERROR: $service_name - $wait_cmd returned error"
+      exit 1
+  }
+}
+
+################################################
+# kill off any TCP connections with the given IP
+################################################
+kill_tcp_connections() {
+    _IP="$1"    
+    _failed=0
+
+    _killcount=0
+    connfile="$CTDB_VARDIR/state/connections.$_IP"
+    netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
+    netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
+
+    while read dest src; do
+	srcip=`echo $src | sed -e "s/:[^:]*$//"`
+	srcport=`echo $src | sed -e "s/^.*://"`
+	destip=`echo $dest | sed -e "s/:[^:]*$//"`
+	destport=`echo $dest | sed -e "s/^.*://"`
+	echo "Killing TCP connection $srcip:$srcport $destip:$destport"
+	ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
+	case $destport in
+	  # we only do one-way killtcp for CIFS
+	  139|445) : ;;
+	  # for all others we do 2-way
+	  *) 
+	  	ctdb killtcp $destip:$destport $srcip:$srcport >/dev/null 2>&1 || _failed=1
+		;;
+	esac
+	_killcount=`expr $_killcount + 1`
+     done < $connfile
+    rm -f $connfile
+
+    [ $_failed = 0 ] || {
+	echo "Failed to send killtcp control"
+	return;
+    }
+    [ $_killcount -gt 0 ] || {
+	return;
+    }
+    _count=0
+    while netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" > /dev/null; do
+	sleep 1
+	_count=`expr $_count + 1`
+	[ $_count -gt 3 ] && {
+	    echo "Timed out killing tcp connections for IP $_IP"
+	    return;
+	}
+    done
+    echo "killed $_killcount TCP connections to released IP $_IP"
+}
+
+##################################################################
+# kill off the local end for any TCP connections with the given IP
+##################################################################
+kill_tcp_connections_local_only() {
+    _IP="$1"    
+    _failed=0
+
+    _killcount=0
+    connfile="$CTDB_VARDIR/state/connections.$_IP"
+    netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
+    netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
+
+    while read dest src; do
+	srcip=`echo $src | sed -e "s/:[^:]*$//"`
+	srcport=`echo $src | sed -e "s/^.*://"`
+	destip=`echo $dest | sed -e "s/:[^:]*$//"`
+	destport=`echo $dest | sed -e "s/^.*://"`
+	echo "Killing TCP connection $srcip:$srcport $destip:$destport"
+	ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
+	_killcount=`expr $_killcount + 1`
+     done < $connfile
+    rm -f $connfile
+
+    [ $_failed = 0 ] || {
+	echo "Failed to send killtcp control"
+	return;
+    }
+    [ $_killcount -gt 0 ] || {
+	return;
+    }
+    _count=0
+    while netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" > /dev/null; do
+	sleep 1
+	_count=`expr $_count + 1`
+	[ $_count -gt 3 ] && {
+	    echo "Timed out killing tcp connections for IP $_IP"
+	    return;
+	}
+    done
+    echo "killed $_killcount TCP connections to released IP $_IP"
+}
+
+##################################################################
+# tickle any TCP connections with the given IP
+##################################################################
+tickle_tcp_connections() {
+    _IP="$1"
+    _failed=0
+
+    _killcount=0
+    connfile="$CTDB_VARDIR/state/connections.$_IP"
+    netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
+    netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
+
+    while read dest src; do
+	srcip=`echo $src | sed -e "s/:[^:]*$//"`
+	srcport=`echo $src | sed -e "s/^.*://"`
+	destip=`echo $dest | sed -e "s/:[^:]*$//"`
+	destport=`echo $dest | sed -e "s/^.*://"`
+	echo "Tickle TCP connection $srcip:$srcport $destip:$destport"
+	ctdb tickle $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
+	echo "Tickle TCP connection $destip:$destport $srcip:$srcport"
+	ctdb tickle $destip:$destport $srcip:$srcport >/dev/null 2>&1 || _failed=1
+     done < $connfile
+    rm -f $connfile
+
+    [ $_failed = 0 ] || {
+	echo "Failed to send tickle control"
+	return;
+    }
+}
+
+########################################################
+# start/stop the nfs service on different platforms
+########################################################
+startstop_nfs() {
+	PLATFORM="unknown"
+	[ -x $CTDB_ETCDIR/init.d/nfsserver ] && {
+		PLATFORM="sles"
+	}
+	[ -x $CTDB_ETCDIR/init.d/nfslock ] && {
+		PLATFORM="rhel"
+	}
+
+	case $PLATFORM in
+	sles)
+		case $1 in
+		start)
+			service nfsserver start
+			;;
+		stop)
+			service nfsserver stop > /dev/null 2>&1
+			;;
+		restart)
+			set_proc "fs/nfsd/threads" 0
+			service nfsserver stop > /dev/null 2>&1
+			pkill -9 nfsd
+			service nfsserver start
+			;;
+		esac
+		;;
+	rhel)
+		case $1 in
+		start)
+			service nfslock start
+			service nfs start
+			;;
+		stop)
+			service nfs stop
+			service nfslock stop
+			;;
+		restart)
+			set_proc "fs/nfsd/threads" 0
+			service nfs stop > /dev/null 2>&1
+			service nfslock stop > /dev/null 2>&1
+			pkill -9 nfsd
+			service nfslock start
+			service nfs start
+			;;
+		esac
+		;;
+	*)
+		echo "Unknown platform. NFS is not supported with ctdb"
+		exit 1
+		;;
+	esac
+}
+
+########################################################
+# start/stop the nfs lockmanager service on different platforms
+########################################################
+startstop_nfslock() {
+	PLATFORM="unknown"
+	[ -x $CTDB_ETCDIR/init.d/nfsserver ] && {
+		PLATFORM="sles"
+	}
+	[ -x $CTDB_ETCDIR/init.d/nfslock ] && {
+		PLATFORM="rhel"
+	}
+
+	case $PLATFORM in
+	sles)
+		# for sles there is no service for lockmanager
+		# so we instead just shutdown/restart nfs
+		case $1 in
+		start)
+			service nfsserver start
+			;;
+		stop)
+			service nfsserver stop > /dev/null 2>&1
+			;;
+		restart)
+			service nfsserver stop
+			service nfsserver start
+			;;
+		esac
+		;;
+	rhel)
+		case $1 in
+		start)
+			service nfslock start
+			;;
+		stop)
+			service nfslock stop > /dev/null 2>&1
+			;;
+		restart)
+			service nfslock stop
+			service nfslock start
+			;;
+		esac
+		;;
+	*)
+		echo "Unknown platform. NFS locking is not supported with ctdb"
+		exit 1
+		;;
+	esac
+}
+
+add_ip_to_iface()
+{
+	local _iface=$1
+	local _ip=$2
+	local _maskbits=$3
+	local _state_dir="$CTDB_VARDIR/state/interface_modify"
+	local _lockfile="$_state_dir/$_iface.flock"
+	local _readd_base="$_state_dir/$_iface.readd.d"
+
+	mkdir -p $_state_dir || {
+		ret=$?
+		echo "Failed to mkdir -p $_state_dir - $ret"
+		return $ret
+	}
+
+	test -f $_lockfile || {
+		touch $_lockfile
+	}
+
+	flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh add "$_iface" "$_ip" "$_maskbits" "$_readd_base"
+	return $?
+}
+
+delete_ip_from_iface()
+{
+	local _iface=$1
+	local _ip=$2
+	local _maskbits=$3
+	local _state_dir="$CTDB_VARDIR/state/interface_modify"
+	local _lockfile="$_state_dir/$_iface.flock"
+	local _readd_base="$_state_dir/$_iface.readd.d"
+
+	mkdir -p $_state_dir || {
+		ret=$?
+		echo "Failed to mkdir -p $_state_dir - $ret"
+		return $ret
+	}
+
+	test -f $_lockfile || {
+		touch $_lockfile
+	}
+
+	flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh delete "$_iface" "$_ip" "$_maskbits" "$_readd_base"
+	return $?
+}
+
+setup_iface_ip_readd_script()
+{
+	local _iface=$1
+	local _ip=$2
+	local _maskbits=$3
+	local _readd_script=$4
+	local _state_dir="$CTDB_VARDIR/state/interface_modify"
+	local _lockfile="$_state_dir/$_iface.flock"
+	local _readd_base="$_state_dir/$_iface.readd.d"
+
+	mkdir -p $_state_dir || {
+		ret=$?
+		echo "Failed to mkdir -p $_state_dir - $ret"
+		return $ret
+	}
+
+	test -f $_lockfile || {
+		touch $_lockfile
+	}
+
+	flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh readd_script "$_iface" "$_ip" "$_maskbits" "$_readd_base" "$_readd_script"
+	return $?
+}
+
+########################################################
+# some simple logic for counting events - per eventscript
+# usage: ctdb_counter_init
+#        ctdb_counter_incr
+#        ctdb_check_counter_limit <limit>
+# ctdb_check_counter_limit succeeds when count >= <limit>
+########################################################
+_ctdb_counter_common () {
+    _service_name="${1:-${service_name}}"
+    _counter_file="$ctdb_fail_dir/$_service_name"
+    mkdir -p "${_counter_file%/*}" # dirname
+}
+ctdb_counter_init () {
+    _ctdb_counter_common "$1"
+
+    >"$_counter_file"
+}
+ctdb_counter_incr () {
+    _ctdb_counter_common "$1"
+
+    # unary counting!
+    echo -n 1 >> "$_counter_file"
+}
+ctdb_check_counter_limit () {
+    _ctdb_counter_common
+
+    _limit="${1:-${service_fail_limit}}"
+    _quiet="$2"
+
+    # unary counting!
+    _size=$(stat -c "%s" "$_counter_file" 2>/dev/null || echo 0)
+    if [ $_size -ge $_limit ] ; then
+	echo "ERROR: more than $_limit consecutive failures for $service_name, marking cluster unhealthy"
+	exit 1
+    elif [ $_size -gt 0 -a -z "$_quiet" ] ; then
+	echo "WARNING: less than $_limit consecutive failures ($_size) for $service_name, not unhealthy yet"
+    fi
+}
+ctdb_check_counter_equal () {
+    _ctdb_counter_common
+
+    _limit=$1
+
+    # unary counting!
+    _size=$(stat -c "%s" "$_counter_file" 2>/dev/null || echo 0)
+    if [ $_size -eq $_limit ] ; then
+	return 1
+    fi
+    return 0
+}
+ctdb_check_counter () {
+    _msg="${1:-error}"  # "error"  - anything else is silent on fail
+    _op="${2:--ge}"  # an integer operator supported by test
+    _limit="${3:-${service_fail_limit}}"
+    shift 3
+    _ctdb_counter_common "$1"
+
+    # unary counting!
+    _size=$(stat -c "%s" "$_counter_file" 2>/dev/null || echo 0)
+    if [ $_size $_op $_limit ] ; then
+	if [ "$_msg" = "error" ] ; then
+	    echo "ERROR: $_limit consecutive failures for $_service_name, marking node unhealthy"
+	    exit 1		
+	else
+	    return 1
+	fi
+    fi
+}
+
+########################################################
+
+ctdb_status_dir="$CTDB_VARDIR/status"
+ctdb_fail_dir="$CTDB_VARDIR/failcount"
+
+ctdb_setup_service_state_dir ()
+{
+    service_state_dir="$CTDB_VARDIR/state/${1:-${service_name}}"
+    mkdir -p "$service_state_dir" || {
+	echo "Error creating state dir \"$service_state_dir\""
+	exit 1
+    }
+}
+
+########################################################
+# Managed status history, for auto-start/stop
+
+ctdb_managed_dir="$CTDB_VARDIR/managed_history"
+
+_ctdb_managed_common ()
+{
+    _service_name="${1:-${service_name}}"
+    _ctdb_managed_file="$ctdb_managed_dir/$_service_name"
+}
+
+ctdb_service_managed ()
+{
+    _ctdb_managed_common "$@"
+    mkdir -p "$ctdb_managed_dir"
+    touch "$_ctdb_managed_file"
+}
+
+ctdb_service_unmanaged ()
+{
+    _ctdb_managed_common "$@"
+    rm -f "$_ctdb_managed_file"
+}
+
+is_ctdb_previously_managed_service ()
+{
+    _ctdb_managed_common "$@"
+    [ -f "$_ctdb_managed_file" ]
+}
+
+########################################################
+# Check and set status
+
+log_status_cat ()
+{
+    echo "node is \"$1\", \"${script_name}\" reports problem: $(cat $2)"
+}
+
+ctdb_checkstatus ()
+{
+    if [ -r "$ctdb_status_dir/$script_name/unhealthy" ] ; then
+	log_status_cat "unhealthy" "$ctdb_status_dir/$script_name/unhealthy"
+	return 1
+    elif [ -r "$ctdb_status_dir/$script_name/banned" ] ; then
+	log_status_cat "banned" "$ctdb_status_dir/$script_name/banned"
+	return 2
+    else
+	return 0
+    fi
+}
+
+ctdb_setstatus ()
+{
+    d="$ctdb_status_dir/$script_name"
+    case "$1" in
+	unhealthy|banned)
+	    mkdir -p "$d"
+	    cat "$2" >"$d/$1"
+	    ;;
+	*)
+	    for i in "banned" "unhealthy" ; do
+		rm -f "$d/$i"
+	    done
+	    ;;
+    esac
+}
+
+##################################################################
+# Reconfigure a service on demand
+
+_ctdb_service_reconfigure_common ()
+{
+    _d="$ctdb_status_dir/${1:-${service_name}}"
+    mkdir -p "$_d"
+    _ctdb_service_reconfigure_flag="$_d/reconfigure"
+}
+
+ctdb_service_needs_reconfigure ()
+{
+    _ctdb_service_reconfigure_common "$@"
+    [ -e "$_ctdb_service_reconfigure_flag" ]
+}
+
+ctdb_service_set_reconfigure ()
+{
+    _ctdb_service_reconfigure_common "$@"
+    >"$_ctdb_service_reconfigure_flag"
+}
+
+ctdb_service_unset_reconfigure ()
+{
+    _ctdb_service_reconfigure_common "$@"
+    rm -f "$_ctdb_service_reconfigure_flag"
+}
+
+ctdb_service_reconfigure ()
+{
+    echo "Reconfiguring service \"$@\"..."
+    ctdb_service_unset_reconfigure "$@"
+    service_reconfigure "$@" || return $?
+    ctdb_counter_init "$@"
+}
+
+# Default service_reconfigure() function.
+service_reconfigure ()
+{
+    service "${1:-$service_name}" restart
+}
+
+ctdb_reconfigure_try_lock ()
+{
+    
+    _ctdb_service_reconfigure_common "$@"
+    _lock="${_d}/reconfigure_lock"
+    touch "$_lock"
+
+    (
+	flock 0
+	# This is overkill but will work if we need to extend this to
+	# allow certain events to run multiple times in parallel
+	# (e.g. takeip) and write multiple PIDs to the file.
+	read _locker_event 
+	if [ -n "$_locker_event" ] ; then
+	    while read _pid ; do
+		if [ -n "$_pid" -a "$_pid" != $$ ] && \
+		    kill -0 "$_pid" 2>/dev/null ; then
+		    exit 1
+		fi
+	    done
+	fi
+
+	printf "%s\n%s\n" "$event_name" $$ >"$_lock"
+	exit 0
+    ) <"$_lock"
+}
+
+ctdb_replay_monitor_status ()
+{
+    echo "Replaying previous status for this script due to reconfigure..."
+    # Leading colon (':') is missing in some versions...
+    _out=$(ctdb scriptstatus -Y | grep -E "^:?monitor:${script_name}:")
+    # Output looks like this:
+    # :monitor:60.nfs:1:ERROR:1314764004.030861:1314764004.035514:foo bar:
+    # This is the cheapest way of getting fields in the middle.
+    set -- $(IFS=":" ; echo $_out)
+    _code="$3"
+    _status="$4"
+    # The error output field can include colons so we'll try to
+    # preserve them.  The weak checking at the beginning tries to make
+    # this work for both broken (no leading ':') and fixed output.
+    _out="${_out%:}"
+    _err_out="${_out#*monitor:${script_name}:*:*:*:*:}"
+    case "$_status" in
+	OK) : ;;  # Do nothing special.
+	TIMEDOUT)
+	    # Recast this as an error, since we can't exit with the
+	    # correct negative number.
+	    _code=1
+	    _err_out="[Replay of TIMEDOUT scriptstatus - note incorrect return code.] ${_err_out}"
+	    ;;
+	DISABLED)
+	    # Recast this as an OK, since we can't exit with the
+	    # correct negative number.
+	    _code=0
+	    _err_out="[Replay of DISABLED scriptstatus - note incorrect return code.] ${_err_out}"
+	    ;;
+	*) : ;;  # Must be ERROR, do nothing special.
+    esac
+    echo "$_err_out"
+    exit $_code
+}
+
+ctdb_service_check_reconfigure ()
+{
+    [ -n "$1" ] || set -- "$service_name"
+
+    # We only care about some events in this function.  For others we
+    # return now.
+    case "$event_name" in
+	monitor|ipreallocated|reconfigure) : ;;
+	*) return 0 ;;
+    esac
+
+    if ctdb_reconfigure_try_lock "$@" ; then
+	# No events covered by this function are running, so proceed
+	# with gay abandon.
+	case "$event_name" in
+	    reconfigure)
+		(ctdb_service_reconfigure "$@")
+		exit $?
+		;;
+	    ipreallocated)
+		if ctdb_service_needs_reconfigure "$@" ; then
+		    ctdb_service_reconfigure "$@"
+		fi
+		;;
+	    monitor)
+		if ctdb_service_needs_reconfigure "$@" ; then
+		    ctdb_service_reconfigure "$@"
+		    # Given that the reconfigure might not have
+		    # resulted in the service being stable yet, we
+		    # replay the previous status since that's the best
+		    # information we have.
+		    ctdb_replay_monitor_status
+		fi
+		;;
+	esac
+    else
+	# Somebody else is running an event we don't want to collide
+	# with.  We proceed with caution.
+	case "$event_name" in
+	    reconfigure)
+		# Tell whoever called us to retry.
+		exit 2
+		;;
+	    ipreallocated)
+		# Defer any scheduled reconfigure and just run the
+		# rest of the ipreallocated event, as per the
+		# eventscript.  There's an assumption here that the
+		# event doesn't depend on any scheduled reconfigure.
+		# This is true in the current code.
+		return 0
+		;;
+	    monitor)
+		# There is most likely a reconfigure in progress so
+		# the service is possibly unstable.  As above, we
+		# defer any scheduled reconfigured.  We also replay
+		# the previous monitor status since that's the best
+		# information we have.
+		ctdb_replay_monitor_status
+		;;
+	esac
+    fi
+}
+
+##################################################################
+# Does CTDB manage this service? - and associated auto-start/stop
+
+ctdb_compat_managed_service ()
+{
+    if [ "$1" = "yes" -a "$2" = "$_service_name" ] ; then
+	CTDB_MANAGED_SERVICES="$CTDB_MANAGED_SERVICES $2"
+    fi
+}
+
+is_ctdb_managed_service ()
+{
+    _service_name="${1:-${service_name}}"
+
+    # $t is used just for readability and to allow better accurate
+    # matching via leading/trailing spaces
+    t=" $CTDB_MANAGED_SERVICES "
+
+    # Return 0 if "<space>$_service_name<space>" appears in $t
+    if [ "${t#* ${_service_name} }" != "${t}" ] ; then
+	return 0
+    fi
+
+    # If above didn't match then update $CTDB_MANAGED_SERVICES for
+    # backward compatibility and try again.
+    ctdb_compat_managed_service "$CTDB_MANAGES_VSFTPD"   "vsftpd"
+    ctdb_compat_managed_service "$CTDB_MANAGES_SAMBA"    "samba"
+    ctdb_compat_managed_service "$CTDB_MANAGES_SCP"      "scp"
+    ctdb_compat_managed_service "$CTDB_MANAGES_WINBIND"  "winbind"
+    ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD"    "apache2"
+    ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD"    "httpd"
+    ctdb_compat_managed_service "$CTDB_MANAGES_ISCSI"    "iscsi"
+    ctdb_compat_managed_service "$CTDB_MANAGES_CLAMD"    "clamd"
+    ctdb_compat_managed_service "$CTDB_MANAGES_NFS"      "nfs"
+    ctdb_compat_managed_service "$CTDB_MANAGES_NFS"      "nfs-ganesha-gpfs"
+
+    t=" $CTDB_MANAGED_SERVICES "
+
+    # Return 0 if "<space>$_service_name<space>" appears in $t
+    [ "${t#* ${_service_name} }" != "${t}" ]
+}
+
+ctdb_start_stop_service ()
+{
+    # Do nothing unless configured to...
+    [ "$CTDB_SERVICE_AUTOSTARTSTOP" = "yes" ] || return 0
+
+    _service_name="${1:-${service_name}}"
+
+    [ "$event_name" = "monitor" ] || return 0
+
+    if is_ctdb_managed_service "$_service_name" ; then
+	if ! is_ctdb_previously_managed_service "$_service_name" ; then
+	    echo "Starting service \"$_service_name\" - now managed"
+	    ctdb_service_start "$_service_name"
+	    exit $?
+	fi
+    else
+	if is_ctdb_previously_managed_service "$_service_name" ; then
+	    echo "Stopping service \"$_service_name\" - no longer managed"
+	    ctdb_service_stop "$_service_name"
+	    exit $?
+	fi
+    fi
+}
+
+ctdb_service_start ()
+{
+    # The service is marked managed if we've ever tried to start it.
+    ctdb_service_managed "$@"
+
+    # Here we only want $1.  If no argument is passed then
+    # service_start needs to know.
+    service_start "$@" || return $?
+
+    ctdb_counter_init "$@"
+    ctdb_check_tcp_init
+}
+
+ctdb_service_stop ()
+{
+    ctdb_service_unmanaged "$@"
+    service_stop "$@"
+}
+
+# Default service_start() and service_stop() functions.
+ 
+# These may be overridden in an eventscript.  When overriding, the
+# following convention must be followed.  If these functions are
+# called with no arguments then they may use internal logic to
+# determine whether the service is managed and, therefore, whether
+# they should take any action.  However, if the service name is
+# specified as an argument then an attempt must be made to start or
+# stop the service.  This is because the auto-start/stop code calls
+# them with the service name as an argument.
+service_start ()
+{
+    service "${1:-${service_name}}" start
+}
+
+service_stop ()
+{
+    service "${1:-${service_name}}" stop
+}
+
+##################################################################
+
+ctdb_standard_event_handler ()
+{
+    case "$1" in
+	status)
+	    ctdb_checkstatus
+	    exit
+	    ;;
+	setstatus)
+            shift
+	    ctdb_setstatus "$@"
+	    exit
+	    ;;
+    esac
+}
+
+ipv4_host_addr_to_net_addr()
+{
+	local HOST=$1
+	local MASKBITS=$2
+
+	local HOST0=$(echo $HOST | awk -F . '{print $4}')
+	local HOST1=$(echo $HOST | awk -F . '{print $3}')
+	local HOST2=$(echo $HOST | awk -F . '{print $2}')
+	local HOST3=$(echo $HOST | awk -F . '{print $1}')
+
+	local HOST_NUM=$(( $HOST0 + $HOST1 * 256 + $HOST2 * (256 ** 2) + $HOST3 * (256 ** 3) ))
+
+	local MASK_NUM=$(( ( (2**32 - 1) * (2**(32 - $MASKBITS)) ) & (2**32 - 1) ))
+
+	local NET_NUM=$(( $HOST_NUM & $MASK_NUM))
+
+	local NET0=$(( $NET_NUM & 255 ))
+	local NET1=$(( ($NET_NUM & (255 * 256)) / 256 ))
+	local NET2=$(( ($NET_NUM & (255 * 256**2)) / 256**2 ))
+	local NET3=$(( ($NET_NUM & (255 * 256**3)) / 256**3 ))
+
+	echo "$NET3.$NET2.$NET1.$NET0"
+}
+
+ipv4_maskbits_to_net_mask()
+{
+	local MASKBITS=$1
+
+	local MASK_NUM=$(( ( (2**32 - 1) * (2**(32 - $MASKBITS)) ) & (2**32 - 1) ))
+
+	local MASK0=$(( $MASK_NUM & 255 ))
+	local MASK1=$(( ($MASK_NUM & (255 * 256)) / 256 ))
+	local MASK2=$(( ($MASK_NUM & (255 * 256**2)) / 256**2 ))
+	local MASK3=$(( ($MASK_NUM & (255 * 256**3)) / 256**3 ))
+
+	echo "$MASK3.$MASK2.$MASK1.$MASK0"
+}
+
+ipv4_is_valid_addr()
+{
+	local ADDR=$1
+	local fail=0
+
+	local N=`echo $ADDR | sed -e 's/[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*//'`
+	test -n "$N" && fail=1
+
+	local ADDR0=$(echo $ADDR | awk -F . '{print $4}')
+	local ADDR1=$(echo $ADDR | awk -F . '{print $3}')
+	local ADDR2=$(echo $ADDR | awk -F . '{print $2}')
+	local ADDR3=$(echo $ADDR | awk -F . '{print $1}')
+
+	test "$ADDR0" -gt 255 && fail=1
+	test "$ADDR1" -gt 255 && fail=1
+	test "$ADDR2" -gt 255 && fail=1
+	test "$ADDR3" -gt 255 && fail=1
+
+	test x"$fail" != x"0" && {
+		#echo "IPv4: '$ADDR' is not a valid address"
+		return 1;
+	}
+
+	return 0;
+}
+
+# iptables doesn't like being re-entered, so flock-wrap it.
+iptables()
+{
+	flock -w 30 $CTDB_VARDIR/iptables-ctdb.flock /sbin/iptables "$@"
+}
+
+########################################################
+# tickle handling
+########################################################
+
+# Temporary directory for tickles.
+tickledir="$CTDB_VARDIR/state/tickles"
+mkdir -p "$tickledir"
+
+update_tickles ()
+{
+	_port="$1"
+
+	mkdir -p "$tickledir" # Just in case
+
+	# Who am I?
+	_pnn=$(ctdb pnn) ; _pnn=${_pnn#PNN:}
+
+	# What public IPs do I hold?
+	_ips=$(ctdb -Y ip | awk -F: -v pnn=$_pnn '$3 == pnn {print $2}')
+
+	# IPs as a regexp choice
+	_ipschoice="($(echo $_ips | sed -e 's/ /|/g' -e 's/\./\\\\./g'))"
+
+	# Record connections to our public IPs in a temporary file
+	_my_connections="${tickledir}/${_port}.connections"
+	rm -f "$_my_connections"
+	netstat -tn |
+	awk -v destpat="^${_ipschoice}:${_port}\$" \
+	  '$1 == "tcp" && $6 == "ESTABLISHED" && $4 ~ destpat {print $5, $4}' |
+	sort >"$_my_connections"
+
+	# Record our current tickles in a temporary file
+	_my_tickles="${tickledir}/${_port}.tickles"
+	rm -f "$_my_tickles"
+	for _i in $_ips ; do
+		ctdb -Y gettickles $_i $_port | 
+		awk -F: 'NR > 1 { printf "%s:%s %s:%s\n", $2, $3, $4, $5 }'
+	done |
+	sort >"$_my_tickles"
+
+	# Add tickles for connections that we haven't already got tickles for
+	comm -23 "$_my_connections" "$_my_tickles" |
+	while read _src _dst ; do
+		ctdb addtickle $_src $_dst
+	done
+
+	# Remove tickles for connections that are no longer there
+	comm -13 "$_my_connections" "$_my_tickles" |
+	while read _src _dst ; do
+		ctdb deltickle $_src $_dst
+	done
+
+	rm -f "$_my_connections" "$_my_tickles" 
+}
+
+########################################################
+# load a site local config file
+########################################################
+
+[ -n "$CTDB_RC_LOCAL" -a -x "$CTDB_RC_LOCAL" ] && {
+	. "$CTDB_RC_LOCAL"
+}
+
+[ -x $CTDB_BASE/rc.local ] && {
+	. $CTDB_BASE/rc.local
+}
+
+[ -d $CTDB_BASE/rc.local.d ] && {
+	for i in $CTDB_BASE/rc.local.d/* ; do
+		[ -x "$i" ] && . "$i"
+	done
+}
+
+# We'll call this here to ensure $CTDB_CURRENT_DEBUGLEVEL is set.
+# This gives us a chance to override the debug level using a file in
+# $CTDB_BASE/rc.local.d/.
+ctdb_set_current_debuglevel
+
+script_name="${0##*/}"       # basename
+service_name="$script_name"  # default is just the script name
+service_fail_limit=1
+event_name="$1"


Property changes on: branches/ctdb/squeeze-backports/config/functions
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/gdb_backtrace
===================================================================
--- branches/ctdb/squeeze-backports/config/gdb_backtrace	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/gdb_backtrace	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+BASENAME=`basename $0`
+
+if [ -n "$VALGRIND" -o -n "$SMBD_VALGRIND" ]; then
+	echo "${BASENAME}: Not running debugger under valgrind"
+	exit 1
+fi
+
+# we want everything on stderr, so the program is not disturbed
+exec 1>&2
+
+BASENAME=`basename $0`
+UNAME=`uname`
+
+PID=$1
+BINARY=$2
+
+test x"${PID}" = x"" && {
+	echo "Usage: ${BASENAME} <pid> [<binary>]"
+	exit 1
+}
+
+DB_LIST="gdb"
+case "${UNAME}" in
+	#
+	# on Tru64 we need to try ladebug first
+	# because gdb crashes itself...
+	#
+	OSF1)
+		DB_LIST="ladebug ${DB_LIST}"
+	;;
+esac
+
+for DB in ${DB_LIST}; do
+	DB_BIN=`which ${DB} 2>/dev/null | grep '^/'`
+	test x"${DB_BIN}" != x"" && {
+		break
+	}
+done
+
+test x"${DB_BIN}" = x"" && {
+	echo "${BASENAME}: ERROR: No debugger found."
+	exit 1
+}
+
+#
+# we first try to use /proc/${PID}/exe
+# then fallback to the binary from the commandline
+# then we search for the commandline argument with
+# 'which'
+#
+test -f "/proc/${PID}/exe" && BINARY="/proc/${PID}/exe"
+test x"${BINARY}" = x"" && BINARY="/proc/${PID}/exe"
+test -f "${BINARY}" || BINARY=`which ${BINARY}`
+
+test -f "${BINARY}" || {
+	echo "${BASENAME}: ERROR: Cannot find binary '${BINARY}'."
+	exit 1
+}
+
+echo "${BASENAME}: Trying to use ${DB_BIN} on ${BINARY} on PID ${PID}"
+
+BATCHFILE_PRE=/tmp/gdb_backtrace_pre.$$
+BATCHFILE_MAIN=/tmp/gdb_backtrace_main.$$
+case "${DB}" in
+	ladebug)
+cat << EOF  > ${BATCHFILE_PRE}
+set \$stoponattach
+EOF
+
+cat << EOF  > ${BATCHFILE_MAIN}
+where
+quit
+EOF
+	${DB_BIN} -c "${BATCHFILE_MAIN}" -i "${BATCHFILE_PRE}" -pid "${PID}" "${BINARY}"
+	;;
+	gdb)
+cat << EOF  > ${BATCHFILE_MAIN}
+set height 1000
+bt full
+quit
+EOF
+	${DB_BIN} -x "${BATCHFILE_MAIN}" "${BINARY}" "${PID}"
+	;;
+esac
+/bin/rm -f ${BATCHFILE_PRE} ${BATCHFILE_MAIN}


Property changes on: branches/ctdb/squeeze-backports/config/gdb_backtrace
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/interface_modify.sh
===================================================================
--- branches/ctdb/squeeze-backports/config/interface_modify.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/interface_modify.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,142 @@
+#!/bin/sh
+#
+
+OP=$1
+IFACE=$2
+IP=$3
+MASKBITS=$4
+READD_BASE=$5
+READD_SCRIPT=$6
+
+add_ip_to_iface()
+{
+	local _iface=$1
+	local _ip=$2
+	local _maskbits=$3
+	local _readd_base=$4
+	local _script_dir="$_readd_base/$_ip.$_maskbits"
+
+	# we make sure the interface is up first
+	ip link set $_iface up || {
+		echo "Failed to bringup interface $_iface"
+		return 1;
+	}
+	ip addr add $_ip/$_maskbits brd + dev $_iface || {
+		echo "Failed to add $_ip/$_maskbits on dev $_iface"
+		return 1;
+	}
+
+	mkdir -p $_script_dir || {
+		echo "Failed to mkdir -p $_script_dir"
+		return 1;
+	}
+
+	rm -f $_script_dir/*
+
+	return 0;
+}
+
+delete_ip_from_iface()
+{
+	local _iface=$1
+	local _ip=$2
+	local _maskbits=$3
+	local _readd_base=$4
+	local _script_dir="$_readd_base/$_ip.$_maskbits"
+
+	# the ip tool will delete all secondary IPs if this is the primary. To work around
+	# this _very_ annoying behaviour we have to keep a record of the secondaries and re-add
+	# them afterwards. yuck
+	local _secondaries=""
+	if ip addr list dev $_iface primary | grep -q "inet $_ip/$_maskbits " ; then
+	    _secondaries=`ip addr list dev $_iface secondary | grep " inet " | awk '{print $2}'`
+	fi
+	local _failed=0
+	ip addr del $_ip/$_maskbits dev $_iface || _failed=1
+	[ -z "$_secondaries" ] || {
+	    local _i=""
+	    for _i in $_secondaries; do
+		if ip addr list dev $_iface | grep -q "inet $_i" ; then
+		    echo "kept secondary $_i on dev $_iface"
+		else
+		    echo "re-adding secondary address $_i to dev $_iface"
+		    ip addr add $_i brd + dev $_iface || _failed=1
+		fi
+		local _s_ip=`echo "$_i" | cut -d '/' -f1`
+		local _s_maskbits=`echo "$_i" | cut -d '/' -f2`
+		local _s_script_dir="$_readd_base/$_s_ip.$_s_maskbits"
+
+		local _s_script=""
+		for _s_script in $_s_script_dir/*; do
+			test -x "$_s_script" || {
+				continue
+			}
+			echo "call $_s_script '$_iface' '$_s_ip' '$_s_maskbits'"
+			$_s_script "$_iface" "$_s_ip" "$_s_maskbits" || {
+				ret=$?
+				echo "$_s_script '$_iface' '$_s_ip' '$_s_maskbits' - failed - $ret"
+				_failed=1
+			}
+		done
+
+	    done
+	}
+
+	test -d $_script_dir && {
+		rm -f $_script_dir/*
+	}
+
+	[ $_failed = 0 ] || {
+		echo "Failed to del $_ip on dev $_iface"
+		return 1;
+	}
+	return 0;
+}
+
+setup_iface_ip_readd_script()
+{
+	local _iface=$1
+	local _ip=$2
+	local _maskbits=$3
+	local _readd_base=$4
+	local _readd_script=$5
+	local _script_dir="$_readd_base/$_ip.$_maskbits"
+
+	test -x "$_readd_script" || {
+		echo "Script '$_readd_script' isn't executable"
+		return 1;
+	}
+
+	local _readd_basename=`basename $_readd_script`
+	local _readd_final="$_script_dir/$_readd_basename"
+
+	mkdir -p $_script_dir || {
+		echo "Failed to mkdir -p $_script_dir"
+		return 1;
+	}
+
+	cp -a $_readd_script $_readd_final || {
+		echo "Failed to - cp -a $_readd_script $_readd_final"
+		return 1;
+	}
+
+	return 0
+}
+
+case "$OP" in
+	add)
+		add_ip_to_iface $IFACE $IP $MASKBITS $READD_BASE
+		exit $?
+		;;
+	delete)
+		delete_ip_from_iface $IFACE $IP $MASKBITS $READD_BASE
+		exit $?
+		;;
+	readd_script)
+		setup_iface_ip_readd_script $IFACE $IP $MASKBITS $READD_BASE $READD_SCRIPT
+		exit $?
+		;;
+esac
+
+echo "$0: unknown operation[$OP]"
+exit 1


Property changes on: branches/ctdb/squeeze-backports/config/interface_modify.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/notify.sh
===================================================================
--- branches/ctdb/squeeze-backports/config/notify.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/notify.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# This script is activated by setting CTDB_NOTIFY_SCRIPT=/etc/ctdb/notify.sh
+# in /etc/sysconfig/ctdb
+
+# This is script is invoked from ctdb when node UNHEALTHY flag changes.
+# and can be used to send SNMPtraps, email, etc
+# when the status of a node changes
+
+
+event="$1"
+shift
+
+case $event in
+	unhealthy)
+#
+#               Send an snmptrap that the node is unhealthy :
+#		snmptrap -m ALL -v 1 -c public 10.1.1.105 ctdb `hostname` 0 0 `date +"%s"` ctdb.nodeHealth.0 i 1
+#
+#               or send an email :
+#               mail foo at bar -s "`hostname` is UNHEALTHY"   ...
+#
+#               or do something else ...
+		;;
+	healthy)
+#
+#               Send an snmptrap that the node is healthy again :
+#		snmptrap -m ALL -v 1 -c public 10.1.1.105 ctdb `hostname` 0 0 `date +"%s"` ctdb.nodeHealth.0 i 0
+#
+#               or send an email :
+#               mail foo at bar -s "`hostname` is HEALTHY"   ...
+#
+#               or do something else ...
+		;;
+	startup)
+	#		do some extra magic when ctdb has finished the initial
+	#		recovery?
+		;;
+
+	setup)
+	#		do some extra magic when ctdb has setup itself?
+		;;
+
+	init)
+	#		do some extra magic when ctdb has started?
+		;;
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/config/notify.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config/statd-callout
===================================================================
--- branches/ctdb/squeeze-backports/config/statd-callout	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config/statd-callout	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,194 @@
+#!/bin/sh
+
+# this script needs to be installed so that statd points to it with the -H 
+# command line argument. The easiest way to do that is to put something like this in 
+# /etc/sysconfig/nfs:
+#   STATD_HOSTNAME="myhostname -H /etc/ctdb/statd-callout"
+
+[ -z "$CTDB_BASE" ] && {
+    export CTDB_BASE="/etc/ctdb"
+}
+
+. $CTDB_BASE/functions
+loadconfig ctdb
+loadconfig nfs
+
+[ -z $NFS_HOSTNAME ] && {
+	echo NFS_HOSTNAME is not configured. statd-callout failed.
+	exit 0
+}
+
+case "$1" in
+  add-client)
+	# the callout does not tell us to which ip the client connected
+	# so we must add it to all the ips that we serve
+	PNN=`ctdb xpnn | sed -e "s/.*://"`
+	ctdb ip -Y | while read LINE; do
+		NODE=`echo $LINE | cut -f3 -d:`
+		[ "$NODE" = "$PNN" ] || {
+			# not us
+			continue
+		} 
+		IP=`echo $LINE | cut -f2 -d:`
+		mkdir -p $CTDB_VARDIR/state/statd/ip/$IP
+		touch $CTDB_VARDIR/state/statd/ip/$IP/$2
+	done
+	;;
+  del-client)
+	# the callout does not tell us to which ip the client disconnected
+	# so we must remove it from all the ips that we serve
+	PNN=`ctdb xpnn | sed -e "s/.*://"`
+	ctdb ip -Y | while read LINE; do
+		NODE=`echo $LINE | cut -f3 -d:`
+		[ "$NODE" = "$PNN" ] || {
+			# not us
+			continue
+		} 
+		IP=`echo $LINE | cut -f2 -d:`
+		mkdir -p $CTDB_VARDIR/state/statd/ip/$IP
+		rm -f $CTDB_VARDIR/state/statd/ip/$IP/$2
+	done
+	;;
+  updatelocal)
+	# For all IPs we serve, collect info and push to the config database
+	PNN=`ctdb xpnn | sed -e "s/.*://"`
+	ctdb ip -Y | tail -n +2 | while read LINE; do
+		NODE=`echo $LINE | cut -f3 -d:`
+		[ "$NODE" = "$PNN" ] || {
+			continue
+		} 
+		IP=`echo $LINE | cut -f2 -d:`
+
+		mkdir -p $CTDB_VARDIR/state/statd/ip/$IP
+
+		rm -f $CTDB_VARDIR/state/statd/ip/$IP.tar
+		tar cfP $CTDB_VARDIR/state/statd/ip/$IP.tar $CTDB_VARDIR/state/statd/ip/$IP
+
+		rm -f $CTDB_VARDIR/state/statd/ip/$IP.rec
+		ctdb pfetch ctdb.tdb statd-state:$IP $CTDB_VARDIR/state/statd/ip/$IP.rec 2>/dev/null
+		[ "$?" = "0" ] || {
+			# something went wrong,  try storing this data
+			echo No record. Store STATD state data for $IP
+			ctdb pstore ctdb.tdb statd-state:$IP $CTDB_VARDIR/state/statd/ip/$IP.tar 2>/dev/null
+			continue
+		}
+
+		cmp $CTDB_VARDIR/state/statd/ip/$IP.tar $CTDB_VARDIR/state/statd/ip/$IP.rec >/dev/null 2>/dev/null
+		[ "$?" = "0" ] || {
+			# something went wrong,  try storing this data
+			echo Updated record. Store STATD state data for $IP
+			ctdb pstore ctdb.tdb statd-state:$IP $CTDB_VARDIR/state/statd/ip/$IP.tar 2>/dev/null
+			continue
+		}
+	done
+	;;
+
+  updateremote)
+	# For all IPs we dont serve, pull the state from the database
+	PNN=`ctdb xpnn | sed -e "s/.*://"`
+	ctdb ip -Y | tail -n +2 | while read LINE; do
+		NODE=`echo $LINE | cut -f3 -d:`
+		[ "$NODE" = "$PNN" ] && {
+			continue
+		} 
+		IP=`echo $LINE | cut -f2 -d:`
+
+		mkdir -p $CTDB_VARDIR/state/statd/ip/$IP
+
+		rm -f $CTDB_VARDIR/state/statd/ip/$IP.rec
+		ctdb pfetch ctdb.tdb statd-state:$IP $CTDB_VARDIR/state/statd/ip/$IP.rec 2>/dev/null
+		[ "$?" = "0" ] || {
+			continue
+		}
+
+		rm -f $CTDB_VARDIR/state/statd/ip/$IP/*
+		tar xfP $CTDB_VARDIR/state/statd/ip/$IP.rec
+	done
+	;;
+
+  notify)
+	# we must restart the lockmanager (on all nodes) so that we get
+	# a clusterwide grace period (so other clients dont take out
+	# conflicting locks through other nodes before all locks have been
+	# reclaimed)
+
+	# we need these settings to make sure that no tcp connections survive
+	# across a very fast failover/failback
+	#echo 10 > /proc/sys/net/ipv4/tcp_fin_timeout
+	#echo 0 > /proc/sys/net/ipv4/tcp_max_tw_buckets
+	#echo 0 > /proc/sys/net/ipv4/tcp_max_orphans
+
+	# Delete the notification list for statd, we dont want it to 
+	# ping any clients
+	rm -f /var/lib/nfs/statd/sm/*
+	rm -f /var/lib/nfs/statd/sm.bak/*
+
+	# we must keep a monotonically increasing state variable for the entire
+	# cluster  so state always increases when ip addresses fail from one
+	# node to another
+	# We use epoch and hope the nodes are close enough in clock.
+	# Even numbers mean service is shut down, odd numbers mean
+	# service is started.
+	STATE=`date +"%s"`
+	STATE=`expr "$STATE" "/" "2"`
+
+
+	# we must also let some time pass between stopping and restarting the
+	# lockmanager since othervise there is a window where the lockmanager
+	# will respond "strangely" immediately after restarting it, which
+	# causes clients to fail to reclaim the locks.
+	# 
+	startstop_nfslock stop > /dev/null 2>&1
+	sleep 2
+
+	# now start lockmanager again with the new state directory.
+	startstop_nfslock start > /dev/null 2>&1
+
+	# we now need to send out additional statd notifications to ensure
+	# that clients understand that the lockmanager has restarted.
+	# we have three cases:
+	# 1, clients that ignore the ip address the stat notification came from
+	#    and ONLY care about the 'name' in the notify packet.
+	#    these clients ONLY work with lock failover IFF that name
+	#    can be resolved into an ipaddress that matches the one used
+	#    to mount the share.  (==linux clients)
+	#    This is handled when starting lockmanager above,  but those
+	#    packets are sent from the "wrong" ip address, something linux
+	#    clients are ok with, buth other clients will barf at.
+	# 2, Some clients only accept statd packets IFF they come from the
+	#    'correct' ip address.
+	# 2a,Send out the notification using the 'correct' ip address and also
+	#    specify the 'correct' hostname in the statd packet.
+	#    Some clients require both the correct source address and also the
+	#    correct name. (these clients also ONLY work if the ip addresses
+	#    used to map the share can be resolved into the name returned in
+	#    the notify packet.)
+	# 2b,Other clients require that the source ip address of the notify
+	#    packet matches the ip address used to take out the lock.
+	#    I.e. that the correct source address is used.
+	#    These clients also require that the statd notify packet contains
+	#    the name as the ip address used when the lock was taken out.
+	#
+	# Both 2a and 2b are commonly used in lockmanagers since they maximize
+	# probability that the client will accept the statd notify packet and
+	# not just ignore it.
+	# For all IPs we serve, collect info and push to the config database
+	PNN=`ctdb xpnn | sed -e "s/.*://"`
+	ctdb ip -Y | tail -n +2 | while read LINE; do
+		NODE=`echo $LINE | cut -f3 -d:`
+		[ "$NODE" = "$PNN" ] || {
+			continue
+		} 
+		IP=`echo $LINE | cut -f2 -d:`
+
+		ls $CTDB_VARDIR/state/statd/ip/$IP | while read CLIENT; do
+			rm $CTDB_VARDIR/state/statd/ip/$IP/$CLIENT
+			smnotify --client=$CLIENT --ip=$IP --server=$ip --stateval=$STATE
+			smnotify --client=$CLIENT --ip=$IP --server=$NFS_HOSTNAME --stateval=$STATE
+			STATE=`expr "$STATE" "+" "1"`
+			smnotify --client=$CLIENT --ip=$IP --server=$ip --stateval=$STATE
+			smnotify --client=$CLIENT --ip=$IP --server=$NFS_HOSTNAME --stateval=$STATE
+		done
+	done
+	;;
+esac


Property changes on: branches/ctdb/squeeze-backports/config/statd-callout
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config.guess
===================================================================
--- branches/ctdb/squeeze-backports/config.guess	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config.guess	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1533 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-06-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd | genuineintel)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel at ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/config.guess
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/config.h.in
===================================================================
--- branches/ctdb/squeeze-backports/config.h.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config.h.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,932 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Broken RedHat 7.2 system header files */
+#undef BROKEN_REDHAT_7_SYSTEM_HEADERS
+
+/* Broken RHEL5 sys/capability.h */
+#undef BROKEN_RHEL5_SYS_CAP_HEADER
+
+/* Whether strndup is broken */
+#undef BROKEN_STRNDUP
+
+/* Whether strnlen is broken */
+#undef BROKEN_STRNLEN
+
+/* Whether dlopen takes unsigned int flags */
+#undef DLOPEN_TAKES_UNSIGNED_FLAGS
+
+/* Define to 1 if you have the <acl/libacl.h> header file. */
+#undef HAVE_ACL_LIBACL_H
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Define to 1 if you have the `backtrace' function. */
+#undef HAVE_BACKTRACE
+
+/* Whether the bool type is available */
+#undef HAVE_BOOL
+
+/* Define to 1 if you have the `bzero' function. */
+#undef HAVE_BZERO
+
+/* Whether there is a C99 compliant vsnprintf */
+#undef HAVE_C99_VSNPRINTF
+
+/* Define to 1 if you have the `chroot' function. */
+#undef HAVE_CHROOT
+
+/* Define to 1 if you have the `chsize' function. */
+#undef HAVE_CHSIZE
+
+/* Whether or not we have comparison_fn_t */
+#undef HAVE_COMPARISON_FN_T
+
+/* Define to 1 if you have the <compat.h> header file. */
+#undef HAVE_COMPAT_H
+
+/* Define to 1 if you have the <ctype.h> header file. */
+#undef HAVE_CTYPE_H
+
+/* Define to 1 if you have the declaration of `asprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_ASPRINTF
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SNPRINTF
+
+/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VASPRINTF
+
+/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VSNPRINTF
+
+/* Define to 1 if you have the <direct.h> header file. */
+#undef HAVE_DIRECT_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dlclose' function. */
+#undef HAVE_DLCLOSE
+
+/* Define to 1 if you have the `dlerror' function. */
+#undef HAVE_DLERROR
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `dlopen' function. */
+#undef HAVE_DLOPEN
+
+/* Define to 1 if you have the `dlsym' function. */
+#undef HAVE_DLSYM
+
+/* Define to 1 if you have the <dl.h> header file. */
+#undef HAVE_DL_H
+
+/* Whether epoll available */
+#undef HAVE_EPOLL
+
+/* Define to 1 if you have the `epoll_create' function. */
+#undef HAVE_EPOLL_CREATE
+
+/* Whether errno() is available */
+#undef HAVE_ERRNO_DECL
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#undef HAVE_EXECINFO_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <float.h> header file. */
+#undef HAVE_FLOAT_H
+
+/* Define to 1 if you have the <fnmatch.h> header file. */
+#undef HAVE_FNMATCH_H
+
+/* Whether the system has freeaddrinfo */
+#undef HAVE_FREEADDRINFO
+
+/* Whether the system has freeifaddrs */
+#undef HAVE_FREEIFADDRS
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Whether there is a __FUNCTION__ macro */
+#undef HAVE_FUNCTION_MACRO
+
+/* Whether the system has gai_strerror */
+#undef HAVE_GAI_STRERROR
+
+/* Whether the system has getaddrinfo */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getdents' function. */
+#undef HAVE_GETDENTS
+
+/* Define to 1 if you have the `getdirentries' function. */
+#undef HAVE_GETDIRENTRIES
+
+/* Define to 1 if you have the `getgrent_r' function. */
+#undef HAVE_GETGRENT_R
+
+/* Whether getgrent_r() is available */
+#undef HAVE_GETGRENT_R_DECL
+
+/* Define to 1 if you have the `getgrgid_r' function. */
+#undef HAVE_GETGRGID_R
+
+/* Define to 1 if you have the `getgrnam_r' function. */
+#undef HAVE_GETGRNAM_R
+
+/* Whether the system has getifaddrs */
+#undef HAVE_GETIFADDRS
+
+/* Whether the system has getnameinfo */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getpgrp' function. */
+#undef HAVE_GETPGRP
+
+/* Define to 1 if you have the `getpwent_r' function. */
+#undef HAVE_GETPWENT_R
+
+/* Whether getpwent_r() is available */
+#undef HAVE_GETPWENT_R_DECL
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+#undef HAVE_GETPWUID_R
+
+/* Define to 1 if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Whether iface AIX is available */
+#undef HAVE_IFACE_AIX
+
+/* Whether iface getifaddrs is available */
+#undef HAVE_IFACE_GETIFADDRS
+
+/* Whether iface ifconf is available */
+#undef HAVE_IFACE_IFCONF
+
+/* Whether iface ifreq is available */
+#undef HAVE_IFACE_IFREQ
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#undef HAVE_IFADDRS_H
+
+/* Whether the compiler supports immediate structures */
+#undef HAVE_IMMEDIATE_STRUCTURES
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the <infiniband/verbs.h> header file. */
+#undef HAVE_INFINIBAND_VERBS_H
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `isatty' function. */
+#undef HAVE_ISATTY
+
+/* Define to 1 if you have the `ibverbs' library (-libverbs). */
+#undef HAVE_LIBIBVERBS
+
+/* Define to 1 if you have the `rdmacm' library (-lrdmacm). */
+#undef HAVE_LIBRDMACM
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the `memcpy' function. */
+#undef HAVE_MEMCPY
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define if target mkdir supports mode option */
+#undef HAVE_MKDIR_MODE
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#undef HAVE_MKDTEMP
+
+/* Define to 1 if you have the `mktime' function. */
+#undef HAVE_MKTIME
+
+/* Define to 1 if you have the `mlockall' function. */
+#undef HAVE_MLOCKALL
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <mntent.h> header file. */
+#undef HAVE_MNTENT_H
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/in_ip.h> header file. */
+#undef HAVE_NETINET_IN_IP_H
+
+/* Define to 1 if you have the <netinet/in_systm.h> header file. */
+#undef HAVE_NETINET_IN_SYSTM_H
+
+/* Define to 1 if you have the <netinet/ip.h> header file. */
+#undef HAVE_NETINET_IP_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* usability of net/if.h */
+#undef HAVE_NET_IF_H
+
+/* Whether the open(2) accepts O_DIRECT */
+#undef HAVE_OPEN_O_DIRECT
+
+/* Define to 1 if you have the <pcp/impl.h> header file. */
+#undef HAVE_PCP_IMPL_H
+
+/* Define to 1 if you have the <pcp/pmapi.h> header file. */
+#undef HAVE_PCP_PMAPI_H
+
+/* Define to 1 if you have the <pcp/pmda.h> header file. */
+#undef HAVE_PCP_PMDA_H
+
+/* Define to 1 if you have the `pipe' function. */
+#undef HAVE_PIPE
+
+/* Define to 1 if you have the <popt.h> header file. */
+#undef HAVE_POPT_H
+
+/* Define to 1 if you have the `pread' function. */
+#undef HAVE_PREAD
+
+/* Whether pread() is available */
+#undef HAVE_PREAD_DECL
+
+/* Define to 1 if you have the `printf' function. */
+#undef HAVE_PRINTF
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define to 1 if you have the `pwrite' function. */
+#undef HAVE_PWRITE
+
+/* Whether pwrite() is available */
+#undef HAVE_PWRITE_DECL
+
+/* Define to 1 if you have the `rand' function. */
+#undef HAVE_RAND
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have the <rdma/rdma_cma.h> header file. */
+#undef HAVE_RDMA_RDMA_CMA_H
+
+/* Define to 1 if you have the `rename' function. */
+#undef HAVE_RENAME
+
+/* Define to 1 if the system has the type `sa_family_t'. */
+#undef HAVE_SA_FAMILY_T
+
+/* Define to 1 if you have the <sched.h> header file. */
+#undef HAVE_SCHED_H
+
+/* Define to 1 if you have the `sched_setscheduler' function. */
+#undef HAVE_SCHED_SETSCHEDULER
+
+/* Whether mkstemp is secure */
+#undef HAVE_SECURE_MKSTEMP
+
+/* Define to 1 if you have the `setbuffer' function. */
+#undef HAVE_SETBUFFER
+
+/* Define to 1 if you have the `setegid' function. */
+#undef HAVE_SETEGID
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Whether setenv() is available */
+#undef HAVE_SETENV_DECL
+
+/* Define to 1 if you have the `seteuid' function. */
+#undef HAVE_SETEUID
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#undef HAVE_SETJMP_H
+
+/* Define to 1 if you have the `setlinebuf' function. */
+#undef HAVE_SETLINEBUF
+
+/* Define to 1 if you have the `setresgid' function. */
+#undef HAVE_SETRESGID
+
+/* Whether setresgid() is available */
+#undef HAVE_SETRESGID_DECL
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Whether setresuid() is available */
+#undef HAVE_SETRESUID_DECL
+
+/* Define to 1 if you have the <shadow.h> header file. */
+#undef HAVE_SHADOW_H
+
+/* Define to 1 if you have the `shl_findsym' function. */
+#undef HAVE_SHL_FINDSYM
+
+/* Define to 1 if you have the `shl_load' function. */
+#undef HAVE_SHL_LOAD
+
+/* Define to 1 if you have the `shl_unload' function. */
+#undef HAVE_SHL_UNLOAD
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigblock' function. */
+#undef HAVE_SIGBLOCK
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Whether we have the atomic_t variable type */
+#undef HAVE_SIG_ATOMIC_T_TYPE
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Whether struct sockaddr has a sa_len member */
+#undef HAVE_SOCKADDR_SA_LEN
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define to 1 if the system has the type `socklen_t'. */
+#undef HAVE_SOCKLEN_T
+
+/* Whether the sockaddr_in struct has a sin_len property */
+#undef HAVE_SOCK_SIN_LEN
+
+/* Define to 1 if you have the `srand' function. */
+#undef HAVE_SRAND
+
+/* Define to 1 if you have the `srandom' function. */
+#undef HAVE_SRANDOM
+
+/* Defined if struct sockaddr_storage has ss_family field */
+#undef HAVE_SS_FAMILY
+
+/* Define to 1 if you have the <standards.h> header file. */
+#undef HAVE_STANDARDS_H
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasestr' function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
+/* Define to 1 if you have the `strnlen' function. */
+#undef HAVE_STRNLEN
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define to 1 if you have the `strtoq' function. */
+#undef HAVE_STRTOQ
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define to 1 if you have the `strtouq' function. */
+#undef HAVE_STRTOUQ
+
+/* Define to 1 if the system has the type `struct addrinfo'. */
+#undef HAVE_STRUCT_ADDRINFO
+
+/* Whether struct ifaddrs is available */
+#undef HAVE_STRUCT_IFADDRS
+
+/* Define to 1 if the system has the type `struct sockaddr'. */
+#undef HAVE_STRUCT_SOCKADDR
+
+/* Define to 1 if the system has the type `struct sockaddr_in6'. */
+#undef HAVE_STRUCT_SOCKADDR_IN6
+
+/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
+#undef HAVE_STRUCT_SOCKADDR_SA_LEN
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if `st_rdev' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_RDEV
+
+/* Define to 1 if your `struct stat' has `st_rdev'. Deprecated, use
+   `HAVE_STRUCT_STAT_ST_RDEV' instead. */
+#undef HAVE_ST_RDEV
+
+/* Define to 1 if you have the `syslog' function. */
+#undef HAVE_SYSLOG
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/acl.h> header file. */
+#undef HAVE_SYS_ACL_H
+
+/* Define to 1 if you have the <sys/capability.h> header file. */
+#undef HAVE_SYS_CAPABILITY_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#undef HAVE_SYS_EPOLL_H
+
+/* Define to 1 if you have the <sys/fcntl.h> header file. */
+#undef HAVE_SYS_FCNTL_H
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/filsys.h> header file. */
+#undef HAVE_SYS_FILSYS_H
+
+/* Define to 1 if you have the <sys/fs/s5param.h> header file. */
+#undef HAVE_SYS_FS_S5PARAM_H
+
+/* Define to 1 if you have the <sys/id.h> header file. */
+#undef HAVE_SYS_ID_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#undef HAVE_SYS_IPC_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/mode.h> header file. */
+#undef HAVE_SYS_MODE_H
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#undef HAVE_SYS_MOUNT_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/priv.h> header file. */
+#undef HAVE_SYS_PRIV_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/security.h> header file. */
+#undef HAVE_SYS_SECURITY_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+#undef HAVE_SYS_SHM_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syslog.h> header file. */
+#undef HAVE_SYS_SYSLOG_H
+
+/* Define to 1 if you have the <sys/termio.h> header file. */
+#undef HAVE_SYS_TERMIO_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define to 1 if you have the `timegm' function. */
+#undef HAVE_TIMEGM
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define to 1 if you have the `usleep' function. */
+#undef HAVE_USLEEP
+
+/* Define to 1 if you have the `utime' function. */
+#undef HAVE_UTIME
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if you have the <vararg.h> header file. */
+#undef HAVE_VARARG_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Whether va_copy() is available */
+#undef HAVE_VA_COPY
+
+/* Whether the C compiler understands volatile */
+#undef HAVE_VOLATILE
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `vsyslog' function. */
+#undef HAVE_VSYSLOG
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+#undef HAVE_WS2TCPIP_H
+
+/* Whether the _Bool type is available */
+#undef HAVE__Bool
+
+/* Whether the __VA_ARGS__ macro is available */
+#undef HAVE__VA_ARGS__MACRO
+
+/* Defined if struct sockaddr_storage has __ss_family field */
+#undef HAVE___SS_FAMILY
+
+/* Define to 1 if you have the `__strtoll' function. */
+#undef HAVE___STRTOLL
+
+/* Define to 1 if you have the `__strtoull' function. */
+#undef HAVE___STRTOULL
+
+/* Whether __va_copy() is available */
+#undef HAVE___VA_COPY
+
+/* Whether there is a __func__ macro */
+#undef HAVE_func_MACRO
+
+/* Whether MMAP is broken */
+#undef MMAP_BLACKLIST
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Whether getpass should be replaced */
+#undef REPLACE_GETPASS
+
+/* Whether inet_ntoa should be replaced */
+#undef REPLACE_INET_NTOA
+
+/* replace readdir */
+#undef REPLACE_READDIR
+
+/* replace readdir using getdents() */
+#undef REPLACE_READDIR_GETDENTS
+
+/* replace readdir using getdirentries() */
+#undef REPLACE_READDIR_GETDIRENTRIES
+
+/* Whether strptime should be replaced */
+#undef REPLACE_STRPTIME
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Whether seekdir returns an int */
+#undef SEEKDIR_RETURNS_INT
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `off_t', as computed by sizeof. */
+#undef SIZEOF_OFF_T
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of `ssize_t', as computed by sizeof. */
+#undef SIZEOF_SSIZE_T
+
+/* The size of `void *', as computed by sizeof. */
+#undef SIZEOF_VOID_P
+
+/* getgrent_r solaris function prototype */
+#undef SOLARIS_GETGRENT_R
+
+/* getpwent_r solaris function prototype */
+#undef SOLARIS_GETPWENT_R
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Whether telldir takes a const pointer */
+#undef TELLDIR_TAKES_CONST_DIR
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Use infiniband */
+#undef USE_INFINIBAND
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+
+#ifndef _OSF_SOURCE
+# undef _OSF_SOURCE
+#endif
+
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Whether to enable POSIX support */
+#undef _POSIX_C_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Whether to enable System V compatibility */
+#undef _SYSV
+
+
+#ifndef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE
+#endif
+
+
+
+#ifndef _XOPEN_SOURCE_EXTENDED
+# undef _XOPEN_SOURCE_EXTENDED
+#endif
+
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef ino_t
+
+/* Define to `short' if <sys/types.h> does not define. */
+#undef int16_t
+
+/* Define to `long' if <sys/types.h> does not define. */
+#undef int32_t
+
+/* Define to `long long' if <sys/types.h> does not define. */
+#undef int64_t
+
+/* Define to `char' if <sys/types.h> does not define. */
+#undef int8_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef intptr_t
+
+/* Define to `off_t' if <sys/types.h> does not define. */
+#undef loff_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef mode_t
+
+/* Define to `long int' if <sys/types.h> does not define. */
+#undef off_t
+
+/* Define to `loff_t' if <sys/types.h> does not define. */
+#undef offset_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef ptrdiff_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to `unsigned short' if <sys/types.h> does not define. */
+#undef uint16_t
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#undef uint32_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef uint64_t
+
+/* Define to `unsigned char' if <sys/types.h> does not define. */
+#undef uint8_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef uint_t

Added: branches/ctdb/squeeze-backports/config.mk
===================================================================
--- branches/ctdb/squeeze-backports/config.mk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config.mk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,18 @@
+##################
+[SUBSYSTEM::brlock_ctdb]
+OBJ_FILES = brlock_ctdb.o
+
+##################
+[SUBSYSTEM::opendb_ctdb]
+OBJ_FILES = opendb_ctdb.o
+
+##################
+[SUBSYSTEM::ctdb]
+OBJ_FILES = \
+		ctdb_cluster.o \
+		client/ctdb_client.o \
+		common/ctdb_io.o \
+		common/ctdb_ltdb.o \
+		common/ctdb_message.o \
+		common/ctdb_util.o
+PUBLIC_DEPENDENCIES = LIBTDB LIBTALLOC

Added: branches/ctdb/squeeze-backports/config.sub
===================================================================
--- branches/ctdb/squeeze-backports/config.sub	                        (rev 0)
+++ branches/ctdb/squeeze-backports/config.sub	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1693 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-06-11'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray)
+		os=
+		basic_machine=$1
+		;;
+        -bluegene*)
+	        os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/config.sub
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/configure
===================================================================
--- branches/ctdb/squeeze-backports/configure	                        (rev 0)
+++ branches/ctdb/squeeze-backports/configure	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,10813 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.68.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  # We cannot yet assume a decent shell, so we have to provide a
+	# neutralization value for shells without unset; and this also
+	# works around shells that cannot unset nonexistent variables.
+	# Preserve -v and -x to the replacement shell.
+	BASH_ENV=/dev/null
+	ENV=/dev/null
+	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+	export CONFIG_SHELL
+	case $- in # ((((
+	  *v*x* | *x*v* ) as_opts=-vx ;;
+	  *v* ) as_opts=-v ;;
+	  *x* ) as_opts=-x ;;
+	  * ) as_opts= ;;
+	esac
+	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf at gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="ctdb"
+ac_unique_file="server/ctdbd.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+CTDB_PMDA_INSTALL
+CTDB_PMDA
+CTDB_PCAP_LDFLAGS
+CTDB_SCSI_IO
+CTDB_SYSTEM_OBJ
+EXTRA_OBJ
+INFINIBAND_BINS
+INFINIBAND_LIBS
+INFINIBAND_WRAPPER_OBJ
+HAVE_INFINIBAND
+TEVENT_LIBS
+TEVENT_CFLAGS
+TEVENT_OBJ
+teventdir
+TDB_CFLAGS
+TDB_LIBS
+TDB_OBJ
+tdbdir
+EXPORTSFILE
+TALLOC_LIBS
+TALLOC_CFLAGS
+TALLOC_OBJ
+tallocdir
+POPT_OBJ
+poptdir
+POPT_CFLAGS
+POPT_LIBS
+LOGDIR
+LIBDL
+LIBOBJS
+libreplace_cv_immediate_structures
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBREPLACEOBJ
+libreplacedir
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_largefile
+with_logdir
+with_included_popt
+enable___enable_infiniband
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used" >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --disable-largefile     omit support for large files
+  --enable-infiniband         Turn on infiniband support (default=no)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-logdir=DIR       path to log directory [LOCALSTATEDIR/log]
+  --with-included-popt    use bundled popt library, not from system
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.68
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+	 return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+	    return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if test "$cross_compiling" = yes; then
+    # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid; break
+else
+  as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+			if test $ac_lo -le $ac_mid; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=$ac_mid; break
+else
+  as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+			if test $ac_mid -le $ac_hi; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid
+else
+  as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+  else
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (($2) < 0)
+    {
+      long int i = longval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+  ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+  fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+
+# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
+# ----------------------------------------------------
+# Tries to find if the field MEMBER exists in type AGGR, after including
+# INCLUDES, setting cache variable VAR accordingly.
+ac_fn_c_check_member ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if eval \${$4+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (ac_aggr.$3)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (sizeof ac_aggr.$3)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
+else
+  eval "$4=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$4
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_member
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+if test "${libdir}" = '${exec_prefix}/lib'; then
+  case `uname -m` in
+    x86_64|ppc64|powerpc64)
+      libdir='${exec_prefix}/lib64'
+      ;;
+    *)
+      libdir='${exec_prefix}/lib'
+      ;;
+  esac
+fi
+
+case `uname` in
+  Linux*)
+    CTDB_SYSTEM_OBJ=common/system_linux.o
+    CTDB_SCSI_IO=bin/scsi_io
+    CTDB_PCAP_LDFLAGS=
+    ;;
+  AIX*)
+    CTDB_SYSTEM_OBJ=common/system_aix.o
+    CTDB_SCSI_IO=
+    CTDB_PCAP_LDFLAGS=-lpcap
+    ;;
+  *)
+    echo unknown system  cant configure
+    exit
+    ;;
+esac
+
+
+
+#LIBREPLACE_ALL_CHECKS: START"
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if ${ac_cv_target+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$target_alias" = x; then
+  ac_cv_target=$ac_cv_host
+else
+  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+echo "LIBREPLACE_LOCATION_CHECKS: START"
+
+libreplacedir=""
+libreplacepaths="$srcdir $srcdir/lib/replace $srcdir/libreplace $srcdir/../libreplace $srcdir/../replace"
+for d in $libreplacepaths; do
+	if test -f "$d/replace.c"; then
+		libreplacedir="$d"
+
+		break;
+	fi
+done
+if test x"$libreplacedir" = "x"; then
+	as_fn_error $? "cannot find libreplace in $libreplacepaths" "$LINENO" 5
+fi
+LIBREPLACEOBJ="replace.o"
+
+
+
+
+
+
+echo "LIBREPLACE_LOCATION_CHECKS: END"
+
+
+
+echo "LIBREPLACE_CC_CHECKS: START"
+
+
+ac_cv_prog_cc_Ae=no
+
+savedCFLAGS=$CFLAGS
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CFLAGS=$savedCFLAGS
+
+if test x"$GCC" != x"yes" ; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+struct incomplete_array
+{
+  int datasize;
+  double data[];
+};
+
+struct named_init {
+  int number;
+  const wchar_t *name;
+  double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict(ccp restrict text)
+{
+  // See if C++-style comments work.
+  // Iterate through items via the restricted pointer.
+  // Also check for declarations in for loops.
+  for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+    continue;
+  return 0;
+}
+
+// Check varargs and va_copy work.
+static void
+test_varargs(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  va_list args_copy;
+  va_copy(args_copy, args);
+
+  const char *str;
+  int number;
+  float fnumber;
+
+  while (*format)
+    {
+      switch (*format++)
+	{
+	case 's': // string
+	  str = va_arg(args_copy, const char *);
+	  break;
+	case 'd': // int
+	  number = va_arg(args_copy, int);
+	  break;
+	case 'f': // float
+	  fnumber = (float) va_arg(args_copy, double);
+	  break;
+	default:
+	  break;
+	}
+    }
+  va_end(args_copy);
+  va_end(args);
+}
+
+int
+main ()
+{
+
+  // Check bool and long long datatypes.
+  _Bool success = false;
+  long long int bignum = -1234567890LL;
+  unsigned long long int ubignum = 1234567890uLL;
+
+  // Check restrict.
+  if (test_restrict("String literal") != 0)
+    success = true;
+  char *restrict newvar = "Another string";
+
+  // Check varargs.
+  test_varargs("s, d' f .", "string", 65, 34.234);
+
+  // Check incomplete arrays work.
+  struct incomplete_array *ia =
+    malloc(sizeof(struct incomplete_array) + (sizeof(double) * 10));
+  ia->datasize = 10;
+  for (int i = 0; i < ia->datasize; ++i)
+    ia->data[i] = (double) i * 1.234;
+
+  // Check named initialisers.
+  struct named_init ni = {
+    .number = 34,
+    .name = L"Test wide string",
+    .average = 543.34343,
+  };
+
+  ni.number = 58;
+
+  int dynamic_array[ni.number];
+  dynamic_array[43] = 543;
+
+  // work around unused variable warnings
+  return  bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x';
+
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -c99 -qlanglvl=extc99
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c99"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+
+fi
+
+
+fi
+
+if test x"$GCC" = x"yes" ; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for version of gcc" >&5
+$as_echo_n "checking for version of gcc... " >&6; }
+	GCC_VERSION=`$CC -dumpversion`
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${GCC_VERSION}" >&5
+$as_echo "${GCC_VERSION}" >&6; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+  ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = xyes; then :
+  MINIX=yes
+else
+  MINIX=
+fi
+
+
+  if test "$MINIX" = yes; then
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+
+$as_echo "#define _MINIX 1" >>confdefs.h
+
+  fi
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if ${ac_cv_safe_to_define___extensions__+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#	  define __EXTENSIONS__ 1
+	  $ac_includes_default
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_safe_to_define___extensions__=yes
+else
+  ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+  test $ac_cv_safe_to_define___extensions__ = yes &&
+    $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+  $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
+
+  $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+  $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+  $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+	       not a universal capable compiler
+	     #endif
+	     typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+	# Check for potential -arch flags.  It is not universal unless
+	# there are at least two -arch flags with different values.
+	ac_arch=
+	ac_prev=
+	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+	 if test -n "$ac_prev"; then
+	   case $ac_word in
+	     i?86 | x86_64 | ppc | ppc64)
+	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+		 ac_arch=$ac_word
+	       else
+		 ac_cv_c_bigendian=universal
+		 break
+	       fi
+	       ;;
+	   esac
+	   ac_prev=
+	 elif test "x$ac_word" = "x-arch"; then
+	   ac_prev=arch
+	 fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+	     #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+		     && LITTLE_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+		#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+		short int ascii_ii[] =
+		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+		int use_ascii (int i) {
+		  return ascii_mm[i] + ascii_ii[i];
+		}
+		short int ebcdic_ii[] =
+		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+		short int ebcdic_mm[] =
+		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+		int use_ebcdic (int i) {
+		  return ebcdic_mm[i] + ebcdic_ii[i];
+		}
+		extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+	      ac_cv_c_bigendian=yes
+	    fi
+	    if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+	      if test "$ac_cv_c_bigendian" = unknown; then
+		ac_cv_c_bigendian=no
+	      else
+		# finding both strings is unlikely to happen, but who knows?
+		ac_cv_c_bigendian=unknown
+	      fi
+	    fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+	     /* Are we little or big endian?  From Harbison&Steele.  */
+	     union
+	     {
+	       long int l;
+	       char c[sizeof (long int)];
+	     } u;
+	     u.l = 1;
+	     return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+     $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+   no)
+      ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+
+saved_CFLAGS="$CFLAGS";
+c99_init=no
+if test x"$c99_init" = x"no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 designated initializers" >&5
+$as_echo_n "checking for C99 designated initializers... " >&6; }
+    CFLAGS="$saved_CFLAGS";
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; c99_init=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+if test x"$c99_init" = x"no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 designated initializers with -AC99" >&5
+$as_echo_n "checking for C99 designated initializers with -AC99... " >&6; }
+    CFLAGS="$saved_CFLAGS -AC99";
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; c99_init=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+if test x"$c99_init" = x"no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 designated initializers with -qlanglvl=extc99" >&5
+$as_echo_n "checking for C99 designated initializers with -qlanglvl=extc99... " >&6; }
+    CFLAGS="$saved_CFLAGS -qlanglvl=extc99";
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; c99_init=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+if test x"$c99_init" = x"no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 designated initializers with -qlanglvl=stdc99" >&5
+$as_echo_n "checking for C99 designated initializers with -qlanglvl=stdc99... " >&6; }
+    CFLAGS="$saved_CFLAGS -qlanglvl=stdc99";
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; c99_init=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+if test x"$c99_init" = x"no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 designated initializers with -c99" >&5
+$as_echo_n "checking for C99 designated initializers with -c99... " >&6; }
+    CFLAGS="$saved_CFLAGS -c99"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; c99_init=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "`uname`" = "HP-UX"; then
+  if test "$ac_cv_c_compiler_gnu" = no; then
+	# special override for broken HP-UX compiler - I can't find a way to test
+	# this properly (its a compiler bug)
+	CFLAGS="$CFLAGS -AC99";
+	c99_init=yes;
+  fi
+fi
+
+if test x"$c99_init" = x"yes"; then
+    saved_CFLAGS=""
+
+else
+    CFLAGS="$saved_CFLAGS"
+    saved_CFLAGS=""
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: c99 structure initializer are not supported" >&5
+$as_echo "$as_me: WARNING: c99 structure initializer are not supported" >&2;}
+fi
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5
+$as_echo_n "checking for library containing strerror... " >&6; }
+if ${ac_cv_search_strerror+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char strerror ();
+int
+main ()
+{
+return strerror ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' cposix; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_strerror=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_strerror+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_strerror+:} false; then :
+
+else
+  ac_cv_search_strerror=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5
+$as_echo "$ac_cv_search_strerror" >&6; }
+ac_res=$ac_cv_search_strerror
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+
+
+ cat >>confdefs.h <<\EOF
+#ifndef _XOPEN_SOURCE_EXTENDED
+#define _XOPEN_SOURCE_EXTENDED 1
+#endif
+EOF
+
+
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then :
+  enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
+if ${ac_cv_sys_largefile_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_sys_largefile_CC=no
+     if test "$GCC" != yes; then
+       ac_save_CC=$CC
+       while :; do
+	 # IRIX 6.2 and later do not support large files by default,
+	 # so use the C compiler's -n32 option if that helps.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+	 if ac_fn_c_try_compile "$LINENO"; then :
+  break
+fi
+rm -f core conftest.err conftest.$ac_objext
+	 CC="$CC -n32"
+	 if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext
+	 break
+       done
+       CC=$ac_save_CC
+       rm -f conftest.$ac_ext
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+  if test "$ac_cv_sys_largefile_CC" != no; then
+    CC=$CC$ac_cv_sys_largefile_CC
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if ${ac_cv_sys_file_offset_bits+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_file_offset_bits=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  if test $ac_cv_sys_file_offset_bits = unknown; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
+if ${ac_cv_sys_large_files+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_large_files=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+$as_echo "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  fi
+fi
+
+
+case "$host_os" in
+	*irix6*) cat >> confdefs.h <<\EOF
+#include <standards.h>
+EOF
+
+		;;
+	*hpux*)
+		# mmap on HPUX is completely broken...
+
+$as_echo "#define MMAP_BLACKLIST 1" >>confdefs.h
+
+		if test "`uname -r`" = "B.11.00" -o "`uname -r`" = "B.11.11"; then
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Enabling HPUX 11.00/11.11 header bug workaround" >&5
+$as_echo "$as_me: WARNING: Enabling HPUX 11.00/11.11 header bug workaround" >&2;}
+			CFLAGS="$CFLAGS -Dpread=pread64 -Dpwrite=pwrite64"
+		fi
+		if test "`uname -r`" = "B.11.23"; then
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Enabling HPUX 11.23 machine/sys/getppdp.h bug workaround" >&5
+$as_echo "$as_me: WARNING: Enabling HPUX 11.23 machine/sys/getppdp.h bug workaround" >&2;}
+			CFLAGS="$CFLAGS -D_MACHINE_SYS_GETPPDP_INCLUDED"
+		fi
+		;;
+	*aix*)
+
+$as_echo "#define BROKEN_STRNDUP 1" >>confdefs.h
+
+
+$as_echo "#define BROKEN_STRNLEN 1" >>confdefs.h
+
+		if test "${GCC}" != "yes"; then
+			## for funky AIX compiler using strncpy()
+			CFLAGS="$CFLAGS -D_LINUX_SOURCE_COMPAT -qmaxmem=32000"
+		fi
+		;;
+	*osf*)
+		# this brings in socklen_t
+
+
+
+ cat >>confdefs.h <<\EOF
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
+#endif
+EOF
+
+
+
+
+ cat >>confdefs.h <<\EOF
+#ifndef _OSF_SOURCE
+#define _OSF_SOURCE 1
+#endif
+EOF
+
+		;;
+	#
+	# VOS may need to have POSIX support and System V compatibility enabled.
+	#
+	*vos*)
+		case "$CFLAGS" in
+			*-D_POSIX_C_SOURCE*);;
+			*)
+				CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=200112L"
+
+$as_echo "#define _POSIX_C_SOURCE 200112L" >>confdefs.h
+
+				;;
+		esac
+		case "$CFLAGS" in
+			*-D_SYSV*|*-D_SVID_SOURCE*);;
+			*)
+				CFLAGS="$CFLAGS -D_SYSV"
+
+$as_echo "#define _SYSV 1" >>confdefs.h
+
+				;;
+		esac
+		;;
+esac
+
+
+
+for ac_header in standards.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "standards.h" "ac_cv_header_standards_h" "$ac_includes_default"
+if test "x$ac_cv_header_standards_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_STANDARDS_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# Solaris needs HAVE_LONG_LONG defined
+ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default"
+if test "x$ac_cv_type_long_long" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LONG_LONG 1
+_ACEOF
+
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "uint_t" "ac_cv_type_uint_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint_t unsigned int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default"
+if test "x$ac_cv_type_int8_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int8_t char
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "uint8_t" "ac_cv_type_uint8_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint8_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint8_t unsigned char
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int16_t" "ac_cv_type_int16_t" "$ac_includes_default"
+if test "x$ac_cv_type_int16_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int16_t short
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "uint16_t" "ac_cv_type_uint16_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint16_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint16_t unsigned short
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int32_t" "ac_cv_type_int32_t" "$ac_includes_default"
+if test "x$ac_cv_type_int32_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int32_t long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint32_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t unsigned long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int64_t" "ac_cv_type_int64_t" "$ac_includes_default"
+if test "x$ac_cv_type_int64_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int64_t long long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint64_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint64_t unsigned long long
+_ACEOF
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default"
+if test "x$ac_cv_type_ssize_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define ssize_t int
+_ACEOF
+
+fi
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
+$as_echo_n "checking size of int... " >&6; }
+if ${ac_cv_sizeof_int+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_int" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (int)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_int=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5
+$as_echo "$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5
+$as_echo_n "checking size of char... " >&6; }
+if ${ac_cv_sizeof_char+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_char" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (char)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_char=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5
+$as_echo "$ac_cv_sizeof_char" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_CHAR $ac_cv_sizeof_char
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5
+$as_echo_n "checking size of short... " >&6; }
+if ${ac_cv_sizeof_short+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_short" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (short)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_short=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5
+$as_echo "$ac_cv_sizeof_short" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SHORT $ac_cv_sizeof_short
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
+$as_echo_n "checking size of long... " >&6; }
+if ${ac_cv_sizeof_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_long" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (long)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_long=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5
+$as_echo "$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5
+$as_echo_n "checking size of long long... " >&6; }
+if ${ac_cv_sizeof_long_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_long_long" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (long long)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_long_long=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5
+$as_echo "$ac_cv_sizeof_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long
+_ACEOF
+
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5
+$as_echo_n "checking size of off_t... " >&6; }
+if ${ac_cv_sizeof_off_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_off_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (off_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_off_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5
+$as_echo "$ac_cv_sizeof_off_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_OFF_T $ac_cv_sizeof_off_t
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5
+$as_echo_n "checking size of size_t... " >&6; }
+if ${ac_cv_sizeof_size_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_size_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (size_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_size_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5
+$as_echo "$ac_cv_sizeof_size_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of ssize_t" >&5
+$as_echo_n "checking size of ssize_t... " >&6; }
+if ${ac_cv_sizeof_ssize_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (ssize_t))" "ac_cv_sizeof_ssize_t"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_ssize_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (ssize_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_ssize_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_ssize_t" >&5
+$as_echo "$ac_cv_sizeof_ssize_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SSIZE_T $ac_cv_sizeof_ssize_t
+_ACEOF
+
+
+
+ac_fn_c_check_type "$LINENO" "intptr_t" "ac_cv_type_intptr_t" "$ac_includes_default"
+if test "x$ac_cv_type_intptr_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define intptr_t unsigned long long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default"
+if test "x$ac_cv_type_ptrdiff_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define ptrdiff_t unsigned long long
+_ACEOF
+
+fi
+
+
+if test x"$ac_cv_type_long_long" != x"yes";then
+	as_fn_error $? "LIBREPLACE needs type 'long long'" "$LINENO" 5
+fi
+if test $ac_cv_sizeof_long_long -lt 8;then
+	as_fn_error $? "LIBREPLACE needs sizeof(long long) >= 8" "$LINENO" 5
+fi
+
+############################################
+# check if the compiler can do immediate structures
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for immediate structures" >&5
+$as_echo_n "checking for immediate structures... " >&6; }
+if ${libreplace_cv_immediate_structures+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		#include <stdio.h>
+
+int
+main ()
+{
+
+		typedef struct {unsigned x;} FOOBAR;
+		#define X_FOOBAR(x) ((FOOBAR) { x })
+		#define FOO_ONE X_FOOBAR(1)
+		FOOBAR f = FOO_ONE;
+		static const struct {
+			FOOBAR y;
+		} f2[] = {
+			{FOO_ONE}
+		};
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libreplace_cv_immediate_structures=yes
+else
+  libreplace_cv_immediate_structures=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libreplace_cv_immediate_structures" >&5
+$as_echo "$libreplace_cv_immediate_structures" >&6; }
+if test x"$libreplace_cv_immediate_structures" = x"yes"; then
+
+$as_echo "#define HAVE_IMMEDIATE_STRUCTURES 1" >>confdefs.h
+
+fi
+
+
+echo "LIBREPLACE_CC_CHECKS: END"
+
+
+
+echo "LIBREPLACE_BROKEN_CHECKS: START"
+
+libreplacedir=""
+for d in "$srcdir" "$srcdir/lib/replace" "$srcdir/libreplace" "$srcdir/../libreplace" "$srcdir/../replace"; do
+	if test -f "$d/replace.c"; then
+		libreplacedir="$d"
+
+		break;
+	fi
+done
+LIBREPLACEOBJ="replace.o"
+
+
+LIBREPLACEOBJ="${LIBREPLACEOBJ} snprintf.o"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
+$as_echo_n "checking return type of signal handlers... " >&6; }
+if ${ac_cv_type_signal+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+
+int
+main ()
+{
+return *(signal (0, 0)) (0) == 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_type_signal=int
+else
+  ac_cv_type_signal=void
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5
+$as_echo "$ac_cv_type_signal" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
+$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
+if ${ac_cv_type_uid_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uid_t" >/dev/null 2>&1; then :
+  ac_cv_type_uid_t=yes
+else
+  ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5
+$as_echo "$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
+
+$as_echo "#define uid_t int" >>confdefs.h
+
+
+$as_echo "#define gid_t int" >>confdefs.h
+
+fi
+
+ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default"
+if test "x$ac_cv_type_mode_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define mode_t int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
+if test "x$ac_cv_type_off_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define off_t long int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
+if test "x$ac_cv_type_pid_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define pid_t int
+_ACEOF
+
+fi
+
+ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default"
+if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+_ACEOF
+
+
+$as_echo "#define HAVE_ST_RDEV 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "ino_t" "ac_cv_type_ino_t" "$ac_includes_default"
+if test "x$ac_cv_type_ino_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define ino_t unsigned
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "loff_t" "ac_cv_type_loff_t" "$ac_includes_default"
+if test "x$ac_cv_type_loff_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define loff_t off_t
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "offset_t" "ac_cv_type_offset_t" "$ac_includes_default"
+if test "x$ac_cv_type_offset_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define offset_t loff_t
+_ACEOF
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5
+$as_echo_n "checking for working memcmp... " >&6; }
+if ${ac_cv_func_memcmp_working+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_memcmp_working=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+  /* Some versions of memcmp are not 8-bit clean.  */
+  char c0 = '\100', c1 = '\200', c2 = '\201';
+  if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0)
+    return 1;
+
+  /* The Next x86 OpenStep bug shows up only when comparing 16 bytes
+     or more and with at least one buffer not starting on a 4-byte boundary.
+     William Lewis provided this test program.   */
+  {
+    char foo[21];
+    char bar[21];
+    int i;
+    for (i = 0; i < 4; i++)
+      {
+	char *a = foo + i;
+	char *b = bar + i;
+	strcpy (a, "--------01111111");
+	strcpy (b, "--------10000000");
+	if (memcmp (a, b, 16) >= 0)
+	  return 1;
+      }
+    return 0;
+  }
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_memcmp_working=yes
+else
+  ac_cv_func_memcmp_working=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5
+$as_echo "$ac_cv_func_memcmp_working" >&6; }
+test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in
+  *" memcmp.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS memcmp.$ac_objext"
+ ;;
+esac
+
+
+
+for ac_func in pipe strftime srandom random srand rand usleep setbuffer lstat getpgrp
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_header in stdbool.h stdint.h sys/select.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in setjmp.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "setjmp.h" "ac_cv_header_setjmp_h" "$ac_includes_default"
+if test "x$ac_cv_header_setjmp_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SETJMP_H 1
+_ACEOF
+
+fi
+
+done
+
+
+ac_fn_c_check_header_mongrel "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdint_h" = xyes; then :
+   ac_config_commands="$ac_config_commands rm-stdint.h"
+
+else
+   ac_config_commands="$ac_config_commands mk-stdint.h"
+
+
+fi
+
+
+
+ac_fn_c_check_header_mongrel "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdbool_h" = xyes; then :
+   ac_config_commands="$ac_config_commands rm-stdbool.h"
+
+else
+   ac_config_commands="$ac_config_commands mk-stdbool.h"
+
+
+fi
+
+
+
+
+ac_fn_c_check_type "$LINENO" "bool" "ac_cv_type_bool" "
+$ac_includes_default
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+"
+if test "x$ac_cv_type_bool" = xyes; then :
+
+$as_echo "#define HAVE_BOOL 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "
+$ac_includes_default
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+"
+if test "x$ac_cv_type__Bool" = xyes; then :
+
+$as_echo "#define HAVE__Bool 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5
+$as_echo_n "checking for working mmap... " >&6; }
+if ${samba_cv_HAVE_MMAP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test "$cross_compiling" = yes; then :
+  samba_cv_HAVE_MMAP=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include "$libreplacedir/test/shared_mmap.c"
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  samba_cv_HAVE_MMAP=yes
+else
+  samba_cv_HAVE_MMAP=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_MMAP" >&5
+$as_echo "$samba_cv_HAVE_MMAP" >&6; }
+if test x"$samba_cv_HAVE_MMAP" = x"yes"; then
+
+$as_echo "#define HAVE_MMAP 1" >>confdefs.h
+
+fi
+
+
+for ac_header in sys/syslog.h syslog.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/time.h time.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in stdarg.h vararg.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/socket.h netinet/in.h netdb.h arpa/inet.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/sockio.h sys/un.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/mount.h mntent.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for usable net/if.h" >&5
+$as_echo_n "checking for usable net/if.h... " >&6; }
+if ${libreplace_cv_USABLE_NET_IF_H+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		$ac_includes_default
+		#if HAVE_SYS_SOCKET_H
+		# include <sys/socket.h>
+		#endif
+		#include <net/if.h>
+		int main(void) {return 0;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libreplace_cv_USABLE_NET_IF_H=yes
+else
+  libreplace_cv_USABLE_NET_IF_H=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libreplace_cv_USABLE_NET_IF_H" >&5
+$as_echo "$libreplace_cv_USABLE_NET_IF_H" >&6; }
+if test x"$libreplace_cv_USABLE_NET_IF_H" = x"yes";then
+
+$as_echo "#define HAVE_NET_IF_H 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken inet_ntoa" >&5
+$as_echo_n "checking for broken inet_ntoa... " >&6; }
+if ${samba_cv_REPLACE_INET_NTOA+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test "$cross_compiling" = yes; then :
+  samba_cv_REPLACE_INET_NTOA=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+main() { struct in_addr ip; ip.s_addr = 0x12345678;
+if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
+    strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(0); }
+exit(1);}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  samba_cv_REPLACE_INET_NTOA=yes
+else
+  samba_cv_REPLACE_INET_NTOA=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_REPLACE_INET_NTOA" >&5
+$as_echo "$samba_cv_REPLACE_INET_NTOA" >&6; }
+if test x"$samba_cv_REPLACE_INET_NTOA" = x"yes"; then
+
+$as_echo "#define REPLACE_INET_NTOA 1" >>confdefs.h
+
+fi
+
+
+
+cv=`echo "socklen_t" | sed 'y%./+- %__p__%'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5
+$as_echo_n "checking for socklen_t... " >&6; }
+if eval \${ac_cv_type_$cv+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+$ac_includes_default
+#include <sys/socket.h>
+int
+main ()
+{
+socklen_t foo;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "ac_cv_type_$cv=yes"
+else
+  eval "ac_cv_type_$cv=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_foo=`eval echo \\$ac_cv_type_$cv`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5
+$as_echo "$ac_foo" >&6; }
+if test "$ac_foo" = yes; then
+  ac_tr_hdr=HAVE_`echo socklen_t | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
+if false; then
+	ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "$ac_includes_default"
+if test "x$ac_cv_type_socklen_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SOCKLEN_T 1
+_ACEOF
+
+
+fi
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define $ac_tr_hdr 1
+_ACEOF
+
+fi
+
+
+
+cv=`echo "sa_family_t" | sed 'y%./+- %__p__%'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sa_family_t" >&5
+$as_echo_n "checking for sa_family_t... " >&6; }
+if eval \${ac_cv_type_$cv+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+$ac_includes_default
+#include <sys/socket.h>
+int
+main ()
+{
+sa_family_t foo;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "ac_cv_type_$cv=yes"
+else
+  eval "ac_cv_type_$cv=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_foo=`eval echo \\$ac_cv_type_$cv`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5
+$as_echo "$ac_foo" >&6; }
+if test "$ac_foo" = yes; then
+  ac_tr_hdr=HAVE_`echo sa_family_t | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
+if false; then
+	ac_fn_c_check_type "$LINENO" "sa_family_t" "ac_cv_type_sa_family_t" "$ac_includes_default"
+if test "x$ac_cv_type_sa_family_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SA_FAMILY_T 1
+_ACEOF
+
+
+fi
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define $ac_tr_hdr 1
+_ACEOF
+
+fi
+
+
+
+cv=`echo "struct addrinfo" | sed 'y%./+- %__p__%'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct addrinfo" >&5
+$as_echo_n "checking for struct addrinfo... " >&6; }
+if eval \${ac_cv_type_$cv+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+$ac_includes_default
+#include <netdb.h>
+int
+main ()
+{
+struct addrinfo foo;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "ac_cv_type_$cv=yes"
+else
+  eval "ac_cv_type_$cv=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_foo=`eval echo \\$ac_cv_type_$cv`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5
+$as_echo "$ac_foo" >&6; }
+if test "$ac_foo" = yes; then
+  ac_tr_hdr=HAVE_`echo struct addrinfo | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
+if false; then
+	ac_fn_c_check_type "$LINENO" "struct addrinfo" "ac_cv_type_struct_addrinfo" "$ac_includes_default"
+if test "x$ac_cv_type_struct_addrinfo" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_ADDRINFO 1
+_ACEOF
+
+
+fi
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define $ac_tr_hdr 1
+_ACEOF
+
+fi
+
+
+
+cv=`echo "struct sockaddr" | sed 'y%./+- %__p__%'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr" >&5
+$as_echo_n "checking for struct sockaddr... " >&6; }
+if eval \${ac_cv_type_$cv+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+$ac_includes_default
+#include <sys/socket.h>
+int
+main ()
+{
+struct sockaddr foo;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "ac_cv_type_$cv=yes"
+else
+  eval "ac_cv_type_$cv=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_foo=`eval echo \\$ac_cv_type_$cv`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5
+$as_echo "$ac_foo" >&6; }
+if test "$ac_foo" = yes; then
+  ac_tr_hdr=HAVE_`echo struct sockaddr | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
+if false; then
+	ac_fn_c_check_type "$LINENO" "struct sockaddr" "ac_cv_type_struct_sockaddr" "$ac_includes_default"
+if test "x$ac_cv_type_struct_sockaddr" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR 1
+_ACEOF
+
+
+fi
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define $ac_tr_hdr 1
+_ACEOF
+
+fi
+
+
+
+cv=`echo "struct sockaddr_storage" | sed 'y%./+- %__p__%'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_storage" >&5
+$as_echo_n "checking for struct sockaddr_storage... " >&6; }
+if eval \${ac_cv_type_$cv+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+$ac_includes_default
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+struct sockaddr_storage foo;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "ac_cv_type_$cv=yes"
+else
+  eval "ac_cv_type_$cv=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_foo=`eval echo \\$ac_cv_type_$cv`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5
+$as_echo "$ac_foo" >&6; }
+if test "$ac_foo" = yes; then
+  ac_tr_hdr=HAVE_`echo struct sockaddr_storage | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
+if false; then
+	ac_fn_c_check_type "$LINENO" "struct sockaddr_storage" "ac_cv_type_struct_sockaddr_storage" "$ac_includes_default"
+if test "x$ac_cv_type_struct_sockaddr_storage" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+_ACEOF
+
+
+fi
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define $ac_tr_hdr 1
+_ACEOF
+
+fi
+
+
+
+cv=`echo "struct sockaddr_in6" | sed 'y%./+- %__p__%'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_in6" >&5
+$as_echo_n "checking for struct sockaddr_in6... " >&6; }
+if eval \${ac_cv_type_$cv+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+$ac_includes_default
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+struct sockaddr_in6 foo;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "ac_cv_type_$cv=yes"
+else
+  eval "ac_cv_type_$cv=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_foo=`eval echo \\$ac_cv_type_$cv`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5
+$as_echo "$ac_foo" >&6; }
+if test "$ac_foo" = yes; then
+  ac_tr_hdr=HAVE_`echo struct sockaddr_in6 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
+if false; then
+	ac_fn_c_check_type "$LINENO" "struct sockaddr_in6" "ac_cv_type_struct_sockaddr_in6" "$ac_includes_default"
+if test "x$ac_cv_type_struct_sockaddr_in6" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_IN6 1
+_ACEOF
+
+
+fi
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define $ac_tr_hdr 1
+_ACEOF
+
+fi
+
+
+if test x"$ac_cv_type_struct_sockaddr_storage" = x"yes"; then
+ac_fn_c_check_member "$LINENO" "struct sockaddr_storage" "ss_family" "ac_cv_member_struct_sockaddr_storage_ss_family" "
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+"
+if test "x$ac_cv_member_struct_sockaddr_storage_ss_family" = xyes; then :
+
+$as_echo "#define HAVE_SS_FAMILY 1" >>confdefs.h
+
+fi
+
+
+if test x"$ac_cv_member_struct_sockaddr_storage_ss_family" != x"yes"; then
+ac_fn_c_check_member "$LINENO" "struct sockaddr_storage" "__ss_family" "ac_cv_member_struct_sockaddr_storage___ss_family" "
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+"
+if test "x$ac_cv_member_struct_sockaddr_storage___ss_family" = xyes; then :
+
+$as_echo "#define HAVE___SS_FAMILY 1" >>confdefs.h
+
+fi
+
+fi
+fi
+
+for ac_func in seteuid setresuid setegid setresgid chroot bzero strerror
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+for ac_func in vsyslog setlinebuf mktime ftruncate chsize rename
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+for ac_func in waitpid strlcpy strlcat initgroups memmove strdup
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+for ac_func in pread pwrite strndup strcasestr strtok_r mkdtemp socketpair
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+for ac_func in isatty
+do :
+  ac_fn_c_check_func "$LINENO" "isatty" "ac_cv_func_isatty"
+if test "x$ac_cv_func_isatty" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_ISATTY 1
+_ACEOF
+
+fi
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setresuid declaration" >&5
+$as_echo_n "checking for setresuid declaration... " >&6; }
+if ${ac_cv_have_setresuid_decl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+int i = (int)setresuid
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_have_setresuid_decl=yes
+else
+  ac_cv_have_setresuid_decl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_setresuid_decl" >&5
+$as_echo "$ac_cv_have_setresuid_decl" >&6; }
+ if test x"$ac_cv_have_setresuid_decl" = x"yes"; then
+
+$as_echo "#define HAVE_SETRESUID_DECL 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setresgid declaration" >&5
+$as_echo_n "checking for setresgid declaration... " >&6; }
+if ${ac_cv_have_setresgid_decl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+int i = (int)setresgid
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_have_setresgid_decl=yes
+else
+  ac_cv_have_setresgid_decl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_setresgid_decl" >&5
+$as_echo "$ac_cv_have_setresgid_decl" >&6; }
+ if test x"$ac_cv_have_setresgid_decl" = x"yes"; then
+
+$as_echo "#define HAVE_SETRESGID_DECL 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for errno declaration" >&5
+$as_echo_n "checking for errno declaration... " >&6; }
+if ${ac_cv_have_errno_decl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <errno.h>
+int
+main ()
+{
+int i = (int)errno
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_have_errno_decl=yes
+else
+  ac_cv_have_errno_decl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_errno_decl" >&5
+$as_echo "$ac_cv_have_errno_decl" >&6; }
+ if test x"$ac_cv_have_errno_decl" = x"yes"; then
+
+$as_echo "#define HAVE_ERRNO_DECL 1" >>confdefs.h
+
+ fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for secure mkstemp" >&5
+$as_echo_n "checking for secure mkstemp... " >&6; }
+if ${samba_cv_HAVE_SECURE_MKSTEMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test "$cross_compiling" = yes; then :
+  samba_cv_HAVE_SECURE_MKSTEMP=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+main() {
+  struct stat st;
+  char tpl[20]="/tmp/test.XXXXXX";
+  int fd = mkstemp(tpl);
+  if (fd == -1) exit(1);
+  unlink(tpl);
+  if (fstat(fd, &st) != 0) exit(1);
+  if ((st.st_mode & 0777) != 0600) exit(1);
+  exit(0);
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  samba_cv_HAVE_SECURE_MKSTEMP=yes
+else
+  samba_cv_HAVE_SECURE_MKSTEMP=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_SECURE_MKSTEMP" >&5
+$as_echo "$samba_cv_HAVE_SECURE_MKSTEMP" >&6; }
+if test x"$samba_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
+
+$as_echo "#define HAVE_SECURE_MKSTEMP 1" >>confdefs.h
+
+fi
+
+for ac_header in stdio.h strings.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ac_fn_c_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_includes_default"
+if test "x$ac_cv_have_decl_snprintf" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SNPRINTF $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default"
+if test "x$ac_cv_have_decl_vsnprintf" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_VSNPRINTF $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "asprintf" "ac_cv_have_decl_asprintf" "$ac_includes_default"
+if test "x$ac_cv_have_decl_asprintf" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_ASPRINTF $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "vasprintf" "ac_cv_have_decl_vasprintf" "$ac_includes_default"
+if test "x$ac_cv_have_decl_vasprintf" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_VASPRINTF $ac_have_decl
+_ACEOF
+
+for ac_func in snprintf vsnprintf asprintf vasprintf
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 vsnprintf" >&5
+$as_echo_n "checking for C99 vsnprintf... " >&6; }
+if ${samba_cv_HAVE_C99_VSNPRINTF+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test "$cross_compiling" = yes; then :
+  samba_cv_HAVE_C99_VSNPRINTF=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+void foo(const char *format, ...) {
+       va_list ap;
+       int len;
+       char buf[20];
+       long long l = 1234567890;
+       l *= 100;
+
+       va_start(ap, format);
+       len = vsnprintf(buf, 0, format, ap);
+       va_end(ap);
+       if (len != 5) exit(1);
+
+       va_start(ap, format);
+       len = vsnprintf(0, 0, format, ap);
+       va_end(ap);
+       if (len != 5) exit(2);
+
+       if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(3);
+
+       if (snprintf(buf, 20, "%lld", l) != 12 || strcmp(buf, "123456789000") != 0) exit(4);
+       if (snprintf(buf, 20, "%zu", 123456789) != 9 || strcmp(buf, "123456789") != 0) exit(5);
+       if (snprintf(buf, 20, "%2\$d %1\$d", 3, 4) != 3 || strcmp(buf, "4 3") != 0) exit(6);
+       if (snprintf(buf, 20, "%s", 0) < 3) exit(7);
+
+       exit(0);
+}
+main() { foo("hello"); }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  samba_cv_HAVE_C99_VSNPRINTF=yes
+else
+  samba_cv_HAVE_C99_VSNPRINTF=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_C99_VSNPRINTF" >&5
+$as_echo "$samba_cv_HAVE_C99_VSNPRINTF" >&6; }
+if test x"$samba_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
+
+$as_echo "#define HAVE_C99_VSNPRINTF 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for va_copy" >&5
+$as_echo_n "checking for va_copy... " >&6; }
+if ${samba_cv_HAVE_VA_COPY+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+va_list ap1,ap2;
+int
+main ()
+{
+va_copy(ap1,ap2);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  samba_cv_HAVE_VA_COPY=yes
+else
+  samba_cv_HAVE_VA_COPY=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_VA_COPY" >&5
+$as_echo "$samba_cv_HAVE_VA_COPY" >&6; }
+if test x"$samba_cv_HAVE_VA_COPY" = x"yes"; then
+
+$as_echo "#define HAVE_VA_COPY 1" >>confdefs.h
+
+fi
+
+if test x"$samba_cv_HAVE_VA_COPY" != x"yes"; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __va_copy" >&5
+$as_echo_n "checking for __va_copy... " >&6; }
+if ${samba_cv_HAVE___VA_COPY+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+va_list ap1,ap2;
+int
+main ()
+{
+__va_copy(ap1,ap2);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  samba_cv_HAVE___VA_COPY=yes
+else
+  samba_cv_HAVE___VA_COPY=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE___VA_COPY" >&5
+$as_echo "$samba_cv_HAVE___VA_COPY" >&6; }
+if test x"$samba_cv_HAVE___VA_COPY" = x"yes"; then
+
+$as_echo "#define HAVE___VA_COPY 1" >>confdefs.h
+
+fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __FUNCTION__ macro" >&5
+$as_echo_n "checking for __FUNCTION__ macro... " >&6; }
+if ${samba_cv_HAVE_FUNCTION_MACRO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+printf("%s\n", __FUNCTION__);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_HAVE_FUNCTION_MACRO=yes
+else
+  samba_cv_HAVE_FUNCTION_MACRO=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_FUNCTION_MACRO" >&5
+$as_echo "$samba_cv_HAVE_FUNCTION_MACRO" >&6; }
+if test x"$samba_cv_HAVE_FUNCTION_MACRO" = x"yes"; then
+
+$as_echo "#define HAVE_FUNCTION_MACRO 1" >>confdefs.h
+
+else
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __func__ macro" >&5
+$as_echo_n "checking for __func__ macro... " >&6; }
+if ${samba_cv_HAVE_func_MACRO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+printf("%s\n", __func__);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_HAVE_func_MACRO=yes
+else
+  samba_cv_HAVE_func_MACRO=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_func_MACRO" >&5
+$as_echo "$samba_cv_HAVE_func_MACRO" >&6; }
+    if test x"$samba_cv_HAVE_func_MACRO" = x"yes"; then
+
+$as_echo "#define HAVE_func_MACRO 1" >>confdefs.h
+
+    fi
+fi
+
+for ac_header in sys/param.h limits.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ac_fn_c_check_type "$LINENO" "comparison_fn_t" "ac_cv_type_comparison_fn_t" "$ac_includes_default"
+if test "x$ac_cv_type_comparison_fn_t" = xyes; then :
+
+$as_echo "#define HAVE_COMPARISON_FN_T 1" >>confdefs.h
+
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setenv declaration" >&5
+$as_echo_n "checking for setenv declaration... " >&6; }
+if ${ac_cv_have_setenv_decl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+int
+main ()
+{
+int i = (int)setenv
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_have_setenv_decl=yes
+else
+  ac_cv_have_setenv_decl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_setenv_decl" >&5
+$as_echo "$ac_cv_have_setenv_decl" >&6; }
+ if test x"$ac_cv_have_setenv_decl" = x"yes"; then
+
+$as_echo "#define HAVE_SETENV_DECL 1" >>confdefs.h
+
+ fi
+
+for ac_func in setenv unsetenv
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in strnlen
+do :
+  ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen"
+if test "x$ac_cv_func_strnlen" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_STRNLEN 1
+_ACEOF
+
+fi
+done
+
+for ac_func in strtoull __strtoull strtouq strtoll __strtoll strtoq
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+# this test disabled as we don't actually need __VA_ARGS__ yet
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define eprintf(...) fprintf(stderr, __VA_ARGS__)
+eprintf("bla", "bar");
+
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+$as_echo "#define HAVE__VA_ARGS__MACRO 1" >>confdefs.h
+
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sig_atomic_t type" >&5
+$as_echo_n "checking for sig_atomic_t type... " >&6; }
+if ${samba_cv_sig_atomic_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <signal.h>
+int
+main ()
+{
+sig_atomic_t i = 0
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_sig_atomic_t=yes
+else
+  samba_cv_sig_atomic_t=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_sig_atomic_t" >&5
+$as_echo "$samba_cv_sig_atomic_t" >&6; }
+if test x"$samba_cv_sig_atomic_t" = x"yes"; then
+
+$as_echo "#define HAVE_SIG_ATOMIC_T_TYPE 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for O_DIRECT flag to open(2)" >&5
+$as_echo_n "checking for O_DIRECT flag to open(2)... " >&6; }
+if ${samba_cv_HAVE_OPEN_O_DIRECT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <unistd.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+int
+main ()
+{
+int fd = open("/dev/null", O_DIRECT);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_HAVE_OPEN_O_DIRECT=yes
+else
+  samba_cv_HAVE_OPEN_O_DIRECT=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_OPEN_O_DIRECT" >&5
+$as_echo "$samba_cv_HAVE_OPEN_O_DIRECT" >&6; }
+if test x"$samba_cv_HAVE_OPEN_O_DIRECT" = x"yes"; then
+
+$as_echo "#define HAVE_OPEN_O_DIRECT 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that the C compiler understands volatile" >&5
+$as_echo_n "checking that the C compiler understands volatile... " >&6; }
+if ${samba_cv_volatile+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+int
+main ()
+{
+volatile int i = 0
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_volatile=yes
+else
+  samba_cv_volatile=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_volatile" >&5
+$as_echo "$samba_cv_volatile" >&6; }
+if test x"$samba_cv_volatile" = x"yes"; then
+
+$as_echo "#define HAVE_VOLATILE 1" >>confdefs.h
+
+fi
+
+# filesys
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+  as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
+$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
+if eval \${$as_ac_Header+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main ()
+{
+if ((DIR *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$as_ac_Header=yes"
+else
+  eval "$as_ac_Header=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$as_ac_Header
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
+_ACEOF
+
+ac_header_dirent=$ac_hdr; break
+fi
+
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' dir; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_opendir+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_opendir+:} false; then :
+
+else
+  ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' x; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_opendir+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_opendir+:} false; then :
+
+else
+  ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+fi
+
+for ac_header in fcntl.h sys/fcntl.h sys/resource.h sys/ioctl.h sys/mode.h sys/filio.h sys/fs/s5param.h sys/filsys.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/acl.h acl/libacl.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# select
+for ac_header in sys/select.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_select_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_SELECT_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# time
+for ac_header in sys/time.h utime.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if ${ac_cv_header_time+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_time=yes
+else
+  ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+
+# wait
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
+$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if ${ac_cv_header_sys_wait_h+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main ()
+{
+  int s;
+  wait (&s);
+  s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_sys_wait_h=yes
+else
+  ac_cv_header_sys_wait_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
+$as_echo "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+fi
+
+
+# capability
+for ac_header in sys/capability.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_capability_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_CAPABILITY_H 1
+_ACEOF
+
+fi
+
+done
+
+
+case "$host_os" in
+*linux*)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken RedHat 7.2 system header files" >&5
+$as_echo_n "checking for broken RedHat 7.2 system header files... " >&6; }
+if ${samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+	#ifdef HAVE_SYS_VFS_H
+	#include <sys/vfs.h>
+	#endif
+	#ifdef HAVE_SYS_CAPABILITY_H
+	#include <sys/capability.h>
+	#endif
+
+int
+main ()
+{
+
+	int i;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=no
+else
+  samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=yes
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" >&5
+$as_echo "$samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" >&6; }
+if test x"$samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" = x"yes"; then
+
+$as_echo "#define BROKEN_REDHAT_7_SYSTEM_HEADERS 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken RHEL5 sys/capability.h" >&5
+$as_echo_n "checking for broken RHEL5 sys/capability.h... " >&6; }
+if ${samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+	#ifdef HAVE_SYS_CAPABILITY_H
+	#include <sys/capability.h>
+	#endif
+	#include <linux/types.h>
+
+int
+main ()
+{
+
+	__s8 i;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER=no
+else
+  samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER=yes
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER" >&5
+$as_echo "$samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER" >&6; }
+if test x"$samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER" = x"yes"; then
+
+$as_echo "#define BROKEN_RHEL5_SYS_CAP_HEADER 1" >>confdefs.h
+
+fi
+;;
+esac
+
+# passwd
+for ac_header in grp.h sys/id.h compat.h shadow.h sys/priv.h pwd.h sys/security.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in getpwnam_r getpwuid_r getpwent_r
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpwent_r declaration" >&5
+$as_echo_n "checking for getpwent_r declaration... " >&6; }
+if ${ac_cv_have_getpwent_r_decl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+	#include <unistd.h>
+	#include <pwd.h>
+
+int
+main ()
+{
+int i = (int)getpwent_r
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_have_getpwent_r_decl=yes
+else
+  ac_cv_have_getpwent_r_decl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getpwent_r_decl" >&5
+$as_echo "$ac_cv_have_getpwent_r_decl" >&6; }
+ if test x"$ac_cv_have_getpwent_r_decl" = x"yes"; then
+
+$as_echo "#define HAVE_GETPWENT_R_DECL 1" >>confdefs.h
+
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for prototype struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)" >&5
+$as_echo_n "checking for prototype struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)... " >&6; }
+if { as_var=`$as_echo "ac_cv_c_prototype_struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)" | $as_tr_sh`; eval \${$as_var+:} false; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		$ac_includes_default
+
+	#include <unistd.h>
+	#include <pwd.h>
+
+		struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)
+		{
+
+	#ifndef HAVE_GETPWENT_R_DECL
+	#error missing getpwent_r prototype
+	#endif
+	return NULL;
+
+		}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		`$as_echo "ac_cv_c_prototype_struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)" | $as_tr_sh`=yes
+
+else
+
+		`$as_echo "ac_cv_c_prototype_struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)" | $as_tr_sh`=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$`$as_echo "ac_cv_c_prototype_struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)" | $as_tr_sh`
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if test $`$as_echo "ac_cv_c_prototype_struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)" | $as_tr_sh` = yes; then :
+
+
+$as_echo "#define SOLARIS_GETPWENT_R 1" >>confdefs.h
+
+
+fi
+
+for ac_func in getgrnam_r getgrgid_r getgrent_r
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getgrent_r declaration" >&5
+$as_echo_n "checking for getgrent_r declaration... " >&6; }
+if ${ac_cv_have_getgrent_r_decl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+	#include <unistd.h>
+	#include <grp.h>
+
+int
+main ()
+{
+int i = (int)getgrent_r
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_have_getgrent_r_decl=yes
+else
+  ac_cv_have_getgrent_r_decl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getgrent_r_decl" >&5
+$as_echo "$ac_cv_have_getgrent_r_decl" >&6; }
+ if test x"$ac_cv_have_getgrent_r_decl" = x"yes"; then
+
+$as_echo "#define HAVE_GETGRENT_R_DECL 1" >>confdefs.h
+
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for prototype struct group *getgrent_r(struct group *src, char *buf, int buflen)" >&5
+$as_echo_n "checking for prototype struct group *getgrent_r(struct group *src, char *buf, int buflen)... " >&6; }
+if { as_var=`$as_echo "ac_cv_c_prototype_struct group *getgrent_r(struct group *src, char *buf, int buflen)" | $as_tr_sh`; eval \${$as_var+:} false; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		$ac_includes_default
+
+	#include <unistd.h>
+	#include <grp.h>
+
+		struct group *getgrent_r(struct group *src, char *buf, int buflen)
+		{
+
+	#ifndef HAVE_GETGRENT_R_DECL
+	#error missing getgrent_r prototype
+	#endif
+	return NULL;
+
+		}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		`$as_echo "ac_cv_c_prototype_struct group *getgrent_r(struct group *src, char *buf, int buflen)" | $as_tr_sh`=yes
+
+else
+
+		`$as_echo "ac_cv_c_prototype_struct group *getgrent_r(struct group *src, char *buf, int buflen)" | $as_tr_sh`=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$`$as_echo "ac_cv_c_prototype_struct group *getgrent_r(struct group *src, char *buf, int buflen)" | $as_tr_sh`
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if test $`$as_echo "ac_cv_c_prototype_struct group *getgrent_r(struct group *src, char *buf, int buflen)" | $as_tr_sh` = yes; then :
+
+
+$as_echo "#define SOLARIS_GETGRENT_R 1" >>confdefs.h
+
+
+fi
+
+
+# locale
+for ac_header in ctype.h locale.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# glob
+for ac_header in fnmatch.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "fnmatch.h" "ac_cv_header_fnmatch_h" "$ac_includes_default"
+if test "x$ac_cv_header_fnmatch_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_FNMATCH_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# shmem
+for ac_header in sys/ipc.h sys/mman.h sys/shm.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# terminal
+for ac_header in termios.h termio.h sys/termio.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+save_LIBS="$LIBS"
+LIBS=""
+
+libreplace_cv_dlfcn=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
+$as_echo_n "checking for library containing dlopen... " >&6; }
+if ${ac_cv_search_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' dl; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_dlopen=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_dlopen+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_dlopen+:} false; then :
+
+else
+  ac_cv_search_dlopen=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
+$as_echo "$ac_cv_search_dlopen" >&6; }
+ac_res=$ac_cv_search_dlopen
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in dlopen dlsym dlerror dlclose
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  libreplace_cv_dlfcn=yes
+fi
+done
+
+
+libreplace_cv_shl=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing shl_load" >&5
+$as_echo_n "checking for library containing shl_load... " >&6; }
+if ${ac_cv_search_shl_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' sl; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_shl_load=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_shl_load+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_shl_load+:} false; then :
+
+else
+  ac_cv_search_shl_load=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_shl_load" >&5
+$as_echo "$ac_cv_search_shl_load" >&6; }
+ac_res=$ac_cv_search_shl_load
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+for ac_header in dl.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "dl.h" "ac_cv_header_dl_h" "$ac_includes_default"
+if test "x$ac_cv_header_dl_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DL_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in shl_load shl_unload shl_findsym
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  libreplace_cv_shl=yes
+fi
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for prototype void *dlopen(const char* filename, unsigned int flags)" >&5
+$as_echo_n "checking for prototype void *dlopen(const char* filename, unsigned int flags)... " >&6; }
+if { as_var=`$as_echo "ac_cv_c_prototype_void *dlopen(const char* filename, unsigned int flags)" | $as_tr_sh`; eval \${$as_var+:} false; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		$ac_includes_default
+
+	#include <dlfcn.h>
+
+		void *dlopen(const char* filename, unsigned int flags)
+		{
+
+	return 0;
+
+		}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		`$as_echo "ac_cv_c_prototype_void *dlopen(const char* filename, unsigned int flags)" | $as_tr_sh`=yes
+
+else
+
+		`$as_echo "ac_cv_c_prototype_void *dlopen(const char* filename, unsigned int flags)" | $as_tr_sh`=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$`$as_echo "ac_cv_c_prototype_void *dlopen(const char* filename, unsigned int flags)" | $as_tr_sh`
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if test $`$as_echo "ac_cv_c_prototype_void *dlopen(const char* filename, unsigned int flags)" | $as_tr_sh` = yes; then :
+
+
+$as_echo "#define DLOPEN_TAKES_UNSIGNED_FLAGS 1" >>confdefs.h
+
+
+fi
+
+
+if test x"${libreplace_cv_dlfcn}" = x"yes";then
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} dlfcn.o"
+fi
+
+LIBDL="$LIBS"
+
+LIBS="$save_LIBS"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getpass should be replaced" >&5
+$as_echo_n "checking whether getpass should be replaced... " >&6; }
+if ${samba_cv_REPLACE_GETPASS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -I$libreplacedir/"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include "confdefs.h"
+#define NO_CONFIG_H
+#include "$libreplacedir/getpass.c"
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_REPLACE_GETPASS=yes
+else
+  samba_cv_REPLACE_GETPASS=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CPPFLAGS="$SAVE_CPPFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_REPLACE_GETPASS" >&5
+$as_echo "$samba_cv_REPLACE_GETPASS" >&6; }
+if test x"$samba_cv_REPLACE_GETPASS" = x"yes"; then
+
+$as_echo "#define REPLACE_GETPASS 1" >>confdefs.h
+
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} getpass.o"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strptime is available and works" >&5
+$as_echo_n "checking whether strptime is available and works... " >&6; }
+if ${libreplace_cv_STRPTIME_OK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+	if test "$cross_compiling" = yes; then :
+  libreplace_cv_STRPTIME_OK="assuming not"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		#define LIBREPLACE_CONFIGURE_TEST_STRPTIME
+		#include "$libreplacedir/test/strptime.c"
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  libreplace_cv_STRPTIME_OK=yes
+else
+  libreplace_cv_STRPTIME_OK=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libreplace_cv_STRPTIME_OK" >&5
+$as_echo "$libreplace_cv_STRPTIME_OK" >&6; }
+if test x"$libreplace_cv_STRPTIME_OK" != x"yes"; then
+
+$as_echo "#define REPLACE_STRPTIME 1" >>confdefs.h
+
+        LIBREPLACEOBJ="${LIBREPLACEOBJ} strptime.o"
+fi
+
+for ac_header in direct.h windows.h winsock2.h ws2tcpip.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+#######################################
+# Check for mkdir mode
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mkdir supports mode" >&5
+$as_echo_n "checking whether mkdir supports mode... " >&6; }
+if ${ac_cv_mkdir_has_mode+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		#include <stdio.h>
+		#ifdef HAVE_DIRECT_H
+		#include <direct.h>
+		#endif
+int
+main ()
+{
+
+			mkdir("foo",0777);
+			return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_mkdir_has_mode="yes"
+else
+  ac_cv_mkdir_has_mode="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mkdir_has_mode" >&5
+$as_echo "$ac_cv_mkdir_has_mode" >&6; }
+
+if test "$ac_cv_mkdir_has_mode" = "yes"
+then
+
+$as_echo "#define HAVE_MKDIR_MODE 1" >>confdefs.h
+
+fi
+
+for ac_func in timegm
+do :
+  ac_fn_c_check_func "$LINENO" "timegm" "ac_cv_func_timegm"
+if test "x$ac_cv_func_timegm" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_TIMEGM 1
+_ACEOF
+
+else
+  LIBREPLACEOBJ="${LIBREPLACEOBJ} timegm.o"
+fi
+done
+
+
+for ac_func in inet_ntop
+do :
+  ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop"
+if test "x$ac_cv_func_inet_ntop" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_INET_NTOP 1
+_ACEOF
+
+else
+  LIBREPLACEOBJ="${LIBREPLACEOBJ} inet_ntop.o"
+fi
+done
+
+
+for ac_func in inet_pton
+do :
+  ac_fn_c_check_func "$LINENO" "inet_pton" "ac_cv_func_inet_pton"
+if test "x$ac_cv_func_inet_pton" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_INET_PTON 1
+_ACEOF
+
+else
+  LIBREPLACEOBJ="${LIBREPLACEOBJ} inet_pton.o"
+fi
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo" >&5
+$as_echo_n "checking for getaddrinfo... " >&6; }
+if ${libreplace_cv_HAVE_GETADDRINFO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <sys/socket.h>
+#include <netdb.h>
+int
+main ()
+{
+
+struct sockaddr sa;
+struct addrinfo *ai = NULL;
+int ret = getaddrinfo(NULL, NULL, NULL, &ai);
+if (ret != 0) {
+	const char *es = gai_strerror(ret);
+}
+freeaddrinfo(ai);
+ret = getnameinfo(&sa, sizeof(sa),
+		NULL, 0,
+		NULL, 0, 0);
+
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  libreplace_cv_HAVE_GETADDRINFO=yes
+else
+  libreplace_cv_HAVE_GETADDRINFO=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libreplace_cv_HAVE_GETADDRINFO" >&5
+$as_echo "$libreplace_cv_HAVE_GETADDRINFO" >&6; }
+if test x"$libreplace_cv_HAVE_GETADDRINFO" = x"yes"; then
+
+$as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_GETNAMEINFO 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_FREEADDRINFO 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_GAI_STRERROR 1" >>confdefs.h
+
+else
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} getaddrinfo.o"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken readdir" >&5
+$as_echo_n "checking for broken readdir... " >&6; }
+if ${libreplace_cv_READDIR_NEEDED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+	if test "$cross_compiling" = yes; then :
+  libreplace_cv_READDIR_NEEDED="assuming not"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define test_readdir_os2_delete main
+#include "$libreplacedir/tests/os2_delete.c"
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  libreplace_cv_READDIR_NEEDED=no
+else
+  libreplace_cv_READDIR_NEEDED=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libreplace_cv_READDIR_NEEDED" >&5
+$as_echo "$libreplace_cv_READDIR_NEEDED" >&6; }
+
+#
+# try to replace with getdirentries() if needed
+#
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+for ac_func in getdirentries
+do :
+  ac_fn_c_check_func "$LINENO" "getdirentries" "ac_cv_func_getdirentries"
+if test "x$ac_cv_func_getdirentries" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETDIRENTRIES 1
+_ACEOF
+
+fi
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for prototype long telldir(const DIR *dir)" >&5
+$as_echo_n "checking for prototype long telldir(const DIR *dir)... " >&6; }
+if { as_var=`$as_echo "ac_cv_c_prototype_long telldir(const DIR *dir)" | $as_tr_sh`; eval \${$as_var+:} false; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		$ac_includes_default
+
+	#include <dirent.h>
+
+		long telldir(const DIR *dir)
+		{
+
+	return 0;
+
+		}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		`$as_echo "ac_cv_c_prototype_long telldir(const DIR *dir)" | $as_tr_sh`=yes
+
+else
+
+		`$as_echo "ac_cv_c_prototype_long telldir(const DIR *dir)" | $as_tr_sh`=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$`$as_echo "ac_cv_c_prototype_long telldir(const DIR *dir)" | $as_tr_sh`
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if test $`$as_echo "ac_cv_c_prototype_long telldir(const DIR *dir)" | $as_tr_sh` = yes; then :
+
+
+$as_echo "#define TELLDIR_TAKES_CONST_DIR 1" >>confdefs.h
+
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for prototype int seekdir(DIR *dir, long ofs)" >&5
+$as_echo_n "checking for prototype int seekdir(DIR *dir, long ofs)... " >&6; }
+if { as_var=`$as_echo "ac_cv_c_prototype_int seekdir(DIR *dir, long ofs)" | $as_tr_sh`; eval \${$as_var+:} false; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		$ac_includes_default
+
+	#include <dirent.h>
+
+		int seekdir(DIR *dir, long ofs)
+		{
+
+	return 0;
+
+		}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		`$as_echo "ac_cv_c_prototype_int seekdir(DIR *dir, long ofs)" | $as_tr_sh`=yes
+
+else
+
+		`$as_echo "ac_cv_c_prototype_int seekdir(DIR *dir, long ofs)" | $as_tr_sh`=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$`$as_echo "ac_cv_c_prototype_int seekdir(DIR *dir, long ofs)" | $as_tr_sh`
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if test $`$as_echo "ac_cv_c_prototype_int seekdir(DIR *dir, long ofs)" | $as_tr_sh` = yes; then :
+
+
+$as_echo "#define SEEKDIR_RETURNS_INT 1" >>confdefs.h
+
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for replacing readdir using getdirentries()" >&5
+$as_echo_n "checking for replacing readdir using getdirentries()... " >&6; }
+if ${libreplace_cv_READDIR_GETDIRENTRIES+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+	if test "$cross_compiling" = yes; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define _LIBREPLACE_REPLACE_H
+#include "$libreplacedir/repdir_getdirentries.c"
+#define test_readdir_os2_delete main
+#include "$libreplacedir/tests/os2_delete.c"
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  libreplace_cv_READDIR_GETDIRENTRIES=yes
+else
+  libreplace_cv_READDIR_GETDIRENTRIES=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libreplace_cv_READDIR_GETDIRENTRIES" >&5
+$as_echo "$libreplace_cv_READDIR_GETDIRENTRIES" >&6; }
+fi
+if test x"$libreplace_cv_READDIR_GETDIRENTRIES" = x"yes"; then
+
+$as_echo "#define REPLACE_READDIR 1" >>confdefs.h
+
+
+$as_echo "#define REPLACE_READDIR_GETDIRENTRIES 1" >>confdefs.h
+
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} repdir_getdirentries.o"
+	libreplace_cv_READDIR_NEEDED=no
+fi
+
+#
+# try to replace with getdents() if needed
+#
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+for ac_func in getdents
+do :
+  ac_fn_c_check_func "$LINENO" "getdents" "ac_cv_func_getdents"
+if test "x$ac_cv_func_getdents" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETDENTS 1
+_ACEOF
+
+fi
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for replacing readdir using getdents()" >&5
+$as_echo_n "checking for replacing readdir using getdents()... " >&6; }
+if ${libreplace_cv_READDIR_GETDENTS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+	if test "$cross_compiling" = yes; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define _LIBREPLACE_REPLACE_H
+#error _donot_use_getdents_replacement_anymore
+#include "$libreplacedir/repdir_getdents.c"
+#define test_readdir_os2_delete main
+#include "$libreplacedir/tests/os2_delete.c"
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  libreplace_cv_READDIR_GETDENTS=yes
+else
+  libreplace_cv_READDIR_GETDENTS=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libreplace_cv_READDIR_GETDENTS" >&5
+$as_echo "$libreplace_cv_READDIR_GETDENTS" >&6; }
+fi
+if test x"$libreplace_cv_READDIR_GETDENTS" = x"yes"; then
+
+$as_echo "#define REPLACE_READDIR 1" >>confdefs.h
+
+
+$as_echo "#define REPLACE_READDIR_GETDENTS 1" >>confdefs.h
+
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} repdir_getdents.o"
+	libreplace_cv_READDIR_NEEDED=no
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking a usable readdir()" >&5
+$as_echo_n "checking a usable readdir()... " >&6; }
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: the provided readdir() is broken" >&5
+$as_echo "$as_me: WARNING: the provided readdir() is broken" >&2;}
+else
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+for ac_header in ifaddrs.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "$ac_includes_default"
+if test "x$ac_cv_header_ifaddrs_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_IFADDRS_H 1
+_ACEOF
+
+fi
+
+done
+
+
+ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "#include <sys/socket.h>
+"
+if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_SA_LEN 1
+_ACEOF
+
+
+$as_echo "#define HAVE_SOCKADDR_SA_LEN 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getifaddrs and freeifaddrs" >&5
+$as_echo_n "checking for getifaddrs and freeifaddrs... " >&6; }
+if ${samba_cv_HAVE_GETIFADDRS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+int
+main ()
+{
+
+struct ifaddrs *ifp = NULL;
+int ret = getifaddrs (&ifp);
+freeifaddrs(ifp);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  samba_cv_HAVE_GETIFADDRS=yes
+else
+  samba_cv_HAVE_GETIFADDRS=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_GETIFADDRS" >&5
+$as_echo "$samba_cv_HAVE_GETIFADDRS" >&6; }
+if test x"$samba_cv_HAVE_GETIFADDRS" = x"yes"; then
+
+$as_echo "#define HAVE_GETIFADDRS 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_FREEIFADDRS 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_STRUCT_IFADDRS 1" >>confdefs.h
+
+fi
+
+##################
+# look for a method of finding the list of network interfaces
+#
+# This tests need LIBS="$NSL_LIBS $SOCKET_LIBS"
+#
+old_LIBS=$LIBS
+LIBS="$NSL_LIBS $SOCKET_LIBS"
+iface=no;
+##################
+# look for a method of finding the list of network interfaces
+iface=no;
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iface getifaddrs" >&5
+$as_echo_n "checking for iface getifaddrs... " >&6; }
+if ${samba_cv_HAVE_IFACE_GETIFADDRS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS ${SAMBA_CONFIGURE_CPPFLAGS}"
+if test "$cross_compiling" = yes; then :
+  samba_cv_HAVE_IFACE_GETIFADDRS=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define NO_CONFIG_H 1
+#define HAVE_IFACE_GETIFADDRS 1
+#define AUTOCONF_TEST 1
+#include "$libreplacedir/replace.c"
+#include "$libreplacedir/getifaddrs.c"
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  samba_cv_HAVE_IFACE_GETIFADDRS=yes
+else
+  samba_cv_HAVE_IFACE_GETIFADDRS=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_IFACE_GETIFADDRS" >&5
+$as_echo "$samba_cv_HAVE_IFACE_GETIFADDRS" >&6; }
+CPPFLAGS="$SAVE_CPPFLAGS"
+if test x"$samba_cv_HAVE_IFACE_GETIFADDRS" = x"yes"; then
+    iface=yes;
+$as_echo "#define HAVE_IFACE_GETIFADDRS 1" >>confdefs.h
+
+else
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} getifaddrs.o"
+fi
+
+
+if test $iface = no; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iface AIX" >&5
+$as_echo_n "checking for iface AIX... " >&6; }
+if ${samba_cv_HAVE_IFACE_AIX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test "$cross_compiling" = yes; then :
+  samba_cv_HAVE_IFACE_AIX=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define HAVE_IFACE_AIX 1
+#define AUTOCONF_TEST 1
+#undef _XOPEN_SOURCE_EXTENDED
+#include "$libreplacedir/getifaddrs.c"
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  samba_cv_HAVE_IFACE_AIX=yes
+else
+  samba_cv_HAVE_IFACE_AIX=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_IFACE_AIX" >&5
+$as_echo "$samba_cv_HAVE_IFACE_AIX" >&6; }
+if test x"$samba_cv_HAVE_IFACE_AIX" = x"yes"; then
+    iface=yes;
+$as_echo "#define HAVE_IFACE_AIX 1" >>confdefs.h
+
+fi
+fi
+
+
+if test $iface = no; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iface ifconf" >&5
+$as_echo_n "checking for iface ifconf... " >&6; }
+if ${samba_cv_HAVE_IFACE_IFCONF+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test "$cross_compiling" = yes; then :
+  samba_cv_HAVE_IFACE_IFCONF=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define HAVE_IFACE_IFCONF 1
+#define AUTOCONF_TEST 1
+#include "$libreplacedir/getifaddrs.c"
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  samba_cv_HAVE_IFACE_IFCONF=yes
+else
+  samba_cv_HAVE_IFACE_IFCONF=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_IFACE_IFCONF" >&5
+$as_echo "$samba_cv_HAVE_IFACE_IFCONF" >&6; }
+if test x"$samba_cv_HAVE_IFACE_IFCONF" = x"yes"; then
+    iface=yes;
+$as_echo "#define HAVE_IFACE_IFCONF 1" >>confdefs.h
+
+fi
+fi
+
+if test $iface = no; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iface ifreq" >&5
+$as_echo_n "checking for iface ifreq... " >&6; }
+if ${samba_cv_HAVE_IFACE_IFREQ+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test "$cross_compiling" = yes; then :
+  samba_cv_HAVE_IFACE_IFREQ=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define HAVE_IFACE_IFREQ 1
+#define AUTOCONF_TEST 1
+#include "$libreplacedir/getifaddrs.c"
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  samba_cv_HAVE_IFACE_IFREQ=yes
+else
+  samba_cv_HAVE_IFACE_IFREQ=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_IFACE_IFREQ" >&5
+$as_echo "$samba_cv_HAVE_IFACE_IFREQ" >&6; }
+if test x"$samba_cv_HAVE_IFACE_IFREQ" = x"yes"; then
+    iface=yes;
+$as_echo "#define HAVE_IFACE_IFREQ 1" >>confdefs.h
+
+fi
+fi
+
+LIBS=$old_LIBS
+
+
+for ac_func in syslog printf memset memcpy
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  as_fn_error $? "Required function not found" "$LINENO" 5
+fi
+done
+
+
+echo "LIBREPLACE_BROKEN_CHECKS: END"
+
+
+#LIBREPLACE_ALL_CHECKS: END"
+
+CFLAGS="$CFLAGS -I$libreplacedir"
+
+
+if test "$ac_cv_c_compiler_gnu" = yes; then
+   CFLAGS="$CFLAGS -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings"
+fi
+
+LOGDIR='${localstatedir}/log'
+
+# Check whether --with-logdir was given.
+if test "${with_logdir+set}" = set; then :
+  withval=$with_logdir; LOGDIR=$withval
+fi
+
+if test ! -z "$LOGDIR"; then
+  if test "$LOGDIR" = "yes" -o "$LOGDIR" = "no"; then
+    as_fn_error $? "--with-logdir must specify a path" "$LINENO" 5
+  fi
+fi
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+EXTRA_OBJ=""
+
+
+INCLUDED_POPT=auto
+
+# Check whether --with-included-popt was given.
+if test "${with_included_popt+set}" = set; then :
+  withval=$with_included_popt;  INCLUDED_POPT=$withval
+fi
+
+
+
+
+
+if test x"$INCLUDED_POPT" != x"yes"; then
+	for ac_header in popt.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "popt.h" "ac_cv_header_popt_h" "$ac_includes_default"
+if test "x$ac_cv_header_popt_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_POPT_H 1
+_ACEOF
+
+fi
+
+done
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for poptGetContext in -lpopt" >&5
+$as_echo_n "checking for poptGetContext in -lpopt... " >&6; }
+if ${ac_cv_lib_popt_poptGetContext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpopt  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char poptGetContext ();
+int
+main ()
+{
+return poptGetContext ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_popt_poptGetContext=yes
+else
+  ac_cv_lib_popt_poptGetContext=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_popt_poptGetContext" >&5
+$as_echo "$ac_cv_lib_popt_poptGetContext" >&6; }
+if test "x$ac_cv_lib_popt_poptGetContext" = xyes; then :
+   POPT_LIBS="-lpopt"
+fi
+
+	if test x"$ac_cv_header_popt_h" = x"no" -o x"$ac_cv_lib_popt_poptGetContext" = x"no"; then
+		INCLUDED_POPT=yes
+		POPT_CFLAGS=""
+	else
+		INCLUDED_POPT=no
+	fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use included popt" >&5
+$as_echo_n "checking whether to use included popt... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INCLUDED_POPT" >&5
+$as_echo "$INCLUDED_POPT" >&6; }
+if test x"$INCLUDED_POPT" != x"no"; then
+			poptdir=""
+	poptpaths="$srcdir $srcdir/lib/popt $srcdir/popt $srcdir/../popt"
+	for d in $poptpaths; do
+		if test -f "$d/popt.c"; then
+			poptdir="$d"
+			POPT_CFLAGS="-I$d"
+
+			break
+		fi
+	done
+        if test x"$poptdir" = "x"; then
+		as_fn_error $? "cannot find popt source in $poptpaths" "$LINENO" 5
+	fi
+	POPT_OBJ="popt.o findme.o poptconfig.o popthelp.o poptparse.o"
+
+	for ac_header in float.h alloca.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+fi
+
+tallocdir=""
+tallocpaths=". lib/talloc talloc ../talloc ../lib/talloc"
+for d in $tallocpaths; do
+	if test -f "$srcdir/$d/talloc.c"; then
+		tallocdir="$d"
+
+		break;
+	fi
+done
+if test x"$tallocdir" = "x"; then
+   as_fn_error $? "cannot find talloc source in $tallocpaths" "$LINENO" 5
+fi
+TALLOC_OBJ="talloc.o"
+
+
+TALLOC_CFLAGS="-I$srcdir/$tallocdir"
+
+
+TALLOC_LIBS=""
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5
+$as_echo_n "checking size of size_t... " >&6; }
+if ${ac_cv_sizeof_size_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_size_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (size_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_size_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5
+$as_echo "$ac_cv_sizeof_size_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
+$as_echo_n "checking size of void *... " >&6; }
+if ${ac_cv_sizeof_void_p+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_void_p" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (void *)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5
+$as_echo "$ac_cv_sizeof_void_p" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+
+if test $ac_cv_sizeof_size_t -lt $ac_cv_sizeof_void_p; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: size_t cannot represent the amount of used memory of a process" >&5
+$as_echo "$as_me: WARNING: size_t cannot represent the amount of used memory of a process" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: please report this to <samba-technical at samba.org>" >&5
+$as_echo "$as_me: WARNING: please report this to <samba-technical at samba.org>" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: sizeof(size_t) = $ac_cv_sizeof_size_t" >&5
+$as_echo "$as_me: WARNING: sizeof(size_t) = $ac_cv_sizeof_size_t" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: sizeof(void *) = $ac_cv_sizeof_void_p" >&5
+$as_echo "$as_me: WARNING: sizeof(void *) = $ac_cv_sizeof_void_p" >&2;}
+	as_fn_error $? "sizeof(size_t) < sizeof(void *)" "$LINENO" 5
+fi
+
+if test x"$VERSIONSCRIPT" != "x"; then
+    EXPORTSFILE=talloc.exports
+
+fi
+
+tdbdir=""
+tdbpaths=". lib/tdb tdb ../tdb ../lib/tdb"
+for d in $tdbpaths; do
+	if test -f "$srcdir/$d/common/tdb.c"; then
+		tdbdir="$d"
+
+		break;
+	fi
+done
+if test x"$tdbdir" = "x"; then
+   as_fn_error $? "cannot find tdb source in $tdbpaths" "$LINENO" 5
+fi
+TDB_OBJ="common/tdb.o common/dump.o common/transaction.o common/error.o common/traverse.o"
+TDB_OBJ="$TDB_OBJ common/freelist.o common/freelistcheck.o common/io.o common/lock.o common/open.o common/check.o common/hash.o"
+
+
+
+TDB_LIBS=""
+
+
+TDB_CFLAGS="-I$tdbdir/include"
+
+
+for ac_func in mmap pread pwrite getpagesize utime
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+for ac_header in getopt.h sys/select.h sys/time.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pread declaration" >&5
+$as_echo_n "checking for pread declaration... " >&6; }
+if ${ac_cv_have_pread_decl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+int i = (int)pread
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_have_pread_decl=yes
+else
+  ac_cv_have_pread_decl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_pread_decl" >&5
+$as_echo "$ac_cv_have_pread_decl" >&6; }
+ if test x"$ac_cv_have_pread_decl" = x"yes"; then
+
+$as_echo "#define HAVE_PREAD_DECL 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pwrite declaration" >&5
+$as_echo_n "checking for pwrite declaration... " >&6; }
+if ${ac_cv_have_pwrite_decl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+int i = (int)pwrite
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_have_pwrite_decl=yes
+else
+  ac_cv_have_pwrite_decl=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_pwrite_decl" >&5
+$as_echo "$ac_cv_have_pwrite_decl" >&6; }
+ if test x"$ac_cv_have_pwrite_decl" = x"yes"; then
+
+$as_echo "#define HAVE_PWRITE_DECL 1" >>confdefs.h
+
+ fi
+
+
+if test x"$VERSIONSCRIPT" != "x"; then
+    EXPORTSFILE=tdb.exports
+
+fi
+
+
+
+
+if test x"$teventdir" = "x"; then
+	teventdir=""
+	teventpaths="$srcdir $srcdir/lib/tevent $srcdir/tevent $srcdir/../tevent"
+	for d in $teventpaths; do
+		if test -f "$d/tevent.c"; then
+			teventdir="$d"
+			break;
+		fi
+	done
+	if test x"$teventdir" = "x"; then
+	   as_fn_error $? "cannot find libtevent source in $teventpaths" "$LINENO" 5
+	fi
+fi
+
+TEVENT_OBJ=""
+TEVENT_CFLAGS=""
+TEVENT_LIBS=""
+
+
+
+
+TEVENT_CFLAGS="-I$teventdir"
+
+TEVENT_OBJ="tevent.o tevent_debug.o tevent_util.o"
+TEVENT_OBJ="$TEVENT_OBJ tevent_fd.o tevent_timed.o tevent_immediate.o tevent_signal.o"
+TEVENT_OBJ="$TEVENT_OBJ tevent_req.o tevent_wakeup.o tevent_queue.o"
+TEVENT_OBJ="$TEVENT_OBJ tevent_standard.o tevent_select.o"
+
+for ac_header in sys/epoll.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_epoll_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_EPOLL_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in epoll_create
+do :
+  ac_fn_c_check_func "$LINENO" "epoll_create" "ac_cv_func_epoll_create"
+if test "x$ac_cv_func_epoll_create" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_EPOLL_CREATE 1
+_ACEOF
+
+fi
+done
+
+if test x"$ac_cv_header_sys_epoll_h" = x"yes" -a x"$ac_cv_func_epoll_create" = x"yes"; then
+   TEVENT_OBJ="$TEVENT_OBJ tevent_epoll.o"
+
+$as_echo "#define HAVE_EPOLL 1" >>confdefs.h
+
+fi
+
+if test x"$VERSIONSCRIPT" != "x"; then
+    EXPORTSFILE=tevent.exports
+
+fi
+
+# Check whether --enable---enable-infiniband was given.
+if test "${enable___enable_infiniband+set}" = set; then :
+  enableval=$enable___enable_infiniband;
+fi
+
+
+HAVE_INFINIBAND=no
+
+if eval "test x$enable_infiniband = xyes"; then
+
+$as_echo "#define USE_INFINIBAND 1" >>confdefs.h
+
+	HAVE_INFINIBAND=yes
+
+	INFINIBAND_WRAPPER_OBJ="ib/ibwrapper.o ib/ibw_ctdb.o ib/ibw_ctdb_init.o"
+	INFINIBAND_LIBS="-lrdmacm -libverbs"
+	INFINIBAND_BINS="tests/bin/ibwrapper_test"
+
+	for ac_header in infiniband/verbs.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "infiniband/verbs.h" "ac_cv_header_infiniband_verbs_h" "$ac_includes_default"
+if test "x$ac_cv_header_infiniband_verbs_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_INFINIBAND_VERBS_H 1
+_ACEOF
+
+else
+
+		echo "ERROR: you need infiniband/verbs.h when ib enabled!"
+		exit -1
+fi
+
+done
+
+	for ac_header in rdma/rdma_cma.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "rdma/rdma_cma.h" "ac_cv_header_rdma_rdma_cma_h" "$ac_includes_default"
+if test "x$ac_cv_header_rdma_rdma_cma_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_RDMA_RDMA_CMA_H 1
+_ACEOF
+
+else
+
+		echo "ERROR: you need rdma/rdma_cma.h when ib enabled!"
+		exit -1
+fi
+
+done
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ibv_create_qp in -libverbs" >&5
+$as_echo_n "checking for ibv_create_qp in -libverbs... " >&6; }
+if ${ac_cv_lib_ibverbs_ibv_create_qp+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-libverbs  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ibv_create_qp ();
+int
+main ()
+{
+return ibv_create_qp ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_ibverbs_ibv_create_qp=yes
+else
+  ac_cv_lib_ibverbs_ibv_create_qp=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ibverbs_ibv_create_qp" >&5
+$as_echo "$ac_cv_lib_ibverbs_ibv_create_qp" >&6; }
+if test "x$ac_cv_lib_ibverbs_ibv_create_qp" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBIBVERBS 1
+_ACEOF
+
+  LIBS="-libverbs $LIBS"
+
+else
+
+		echo "ERROR: you need libibverbs when ib enabled!"
+		exit -1
+fi
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rdma_connect in -lrdmacm" >&5
+$as_echo_n "checking for rdma_connect in -lrdmacm... " >&6; }
+if ${ac_cv_lib_rdmacm_rdma_connect+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrdmacm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char rdma_connect ();
+int
+main ()
+{
+return rdma_connect ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_rdmacm_rdma_connect=yes
+else
+  ac_cv_lib_rdmacm_rdma_connect=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rdmacm_rdma_connect" >&5
+$as_echo "$ac_cv_lib_rdmacm_rdma_connect" >&6; }
+if test "x$ac_cv_lib_rdmacm_rdma_connect" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRDMACM 1
+_ACEOF
+
+  LIBS="-lrdmacm $LIBS"
+
+else
+
+		echo "ERROR: you need librdmacm when ib enabled!"
+		exit -1
+fi
+
+fi
+
+
+
+
+
+
+for ac_func in sigprocmask sigblock sigaction
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_header in execinfo.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
+if test "x$ac_cv_header_execinfo_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_EXECINFO_H 1
+_ACEOF
+
+fi
+
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5
+$as_echo_n "checking for library containing backtrace... " >&6; }
+if ${ac_cv_search_ext_backtrace+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+ac_func_search_ext_save_LIBS=$LIBS
+ac_cv_search_ext_backtrace=no
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char backtrace ();
+int
+main ()
+{
+return backtrace ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_ext_backtrace="none required"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_ext_backtrace" = no; then
+  for ac_lib in execinfo; do
+    LIBS="-l$ac_lib $EXECINFO_LIBS  $ac_func_search_save_ext_LIBS"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char backtrace ();
+int
+main ()
+{
+return backtrace ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_ext_backtrace="-l$ac_lib"
+break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_ext_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ext_backtrace" >&5
+$as_echo "$ac_cv_search_ext_backtrace" >&6; }
+if test "$ac_cv_search_ext_backtrace" != no; then :
+  test "$ac_cv_search_ext_backtrace" = "none required" || EXECINFO_LIBS="$ac_cv_search_ext_backtrace $EXECINFO_LIBS"
+
+fi
+
+
+    ac_check_func_ext_save_LIBS=$LIBS
+    LIBS="$EXECINFO_LIBS $LIBS"
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace" >&5
+$as_echo_n "checking for backtrace... " >&6; }
+if ${ac_cv_func_ext_backtrace+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define backtrace to an innocuous variant, in case <limits.h> declares backtrace.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define backtrace innocuous_backtrace
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char backtrace (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef backtrace
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char backtrace ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_backtrace || defined __stub___backtrace
+choke me
+#endif
+
+int
+main ()
+{
+return backtrace ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_func_ext_backtrace=yes
+else
+  ac_cv_func_ext_backtrace=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ext_backtrace" >&5
+$as_echo "$ac_cv_func_ext_backtrace" >&6; }
+    LIBS=$ac_check_func_ext_save_LIBS
+    if test $ac_cv_func_ext_backtrace = yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_BACKTRACE 1
+_ACEOF
+
+fi
+
+
+if test x"$ac_cv_header_execinfo_h" = x"yes" -a x"$ac_cv_func_ext_backtrace" = x"yes";then
+	echo -n ""
+	EXECINFO_CFLAGS="$CFLAGS"
+	EXECINFO_CPPFLAGS="$CPPFLAGS"
+	EXECINFO_LDFLAGS="$LDFLAGS"
+else
+	echo -n ""
+fi
+
+echo -n ""
+
+
+for ac_header in sched.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default"
+if test "x$ac_cv_header_sched_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SCHED_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in pcp/pmapi.h pcp/impl.h pcp/pmda.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_PCP_PMAPI_H
+# include <pcp/pmapi.h>
+#endif
+#ifdef HAVE_PCP_IMPL_H
+# include <pcp/impl.h>
+#endif
+
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in sched_setscheduler
+do :
+  ac_fn_c_check_func "$LINENO" "sched_setscheduler" "ac_cv_func_sched_setscheduler"
+if test "x$ac_cv_func_sched_setscheduler" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SCHED_SETSCHEDULER 1
+_ACEOF
+
+fi
+done
+
+for ac_func in mlockall
+do :
+  ac_fn_c_check_func "$LINENO" "mlockall" "ac_cv_func_mlockall"
+if test "x$ac_cv_func_mlockall" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_MLOCKALL 1
+_ACEOF
+
+fi
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin_len in sock" >&5
+$as_echo_n "checking for sin_len in sock... " >&6; }
+if ${ctdb_cv_HAVE_SOCK_SIN_LEN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int
+main ()
+{
+struct sockaddr_in sock; sock.sin_len = sizeof(sock);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ctdb_cv_HAVE_SOCK_SIN_LEN=yes
+else
+  ctdb_cv_HAVE_SOCK_SIN_LEN=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ctdb_cv_HAVE_SOCK_SIN_LEN" >&5
+$as_echo "$ctdb_cv_HAVE_SOCK_SIN_LEN" >&6; }
+if test x"$ctdb_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then
+
+$as_echo "#define HAVE_SOCK_SIN_LEN 1" >>confdefs.h
+
+fi
+
+if test x"$ac_cv_header_pcp_pmda_h" = x"yes"; then
+    CTDB_PMDA=bin/pmdactdb
+    CTDB_PMDA_INSTALL=install_pmda
+else
+    CTDB_PMDA=
+    CTDB_PMDA_INSTALL=
+fi
+
+
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files Makefile ctdb.pc"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.68,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+libreplacedir=$libreplacedir
+libreplacedir=$libreplacedir
+libreplacedir=$libreplacedir
+libreplacedir=$libreplacedir
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "rm-stdint.h") CONFIG_COMMANDS="$CONFIG_COMMANDS rm-stdint.h" ;;
+    "mk-stdint.h") CONFIG_COMMANDS="$CONFIG_COMMANDS mk-stdint.h" ;;
+    "rm-stdbool.h") CONFIG_COMMANDS="$CONFIG_COMMANDS rm-stdbool.h" ;;
+    "mk-stdbool.h") CONFIG_COMMANDS="$CONFIG_COMMANDS mk-stdbool.h" ;;
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "ctdb.pc") CONFIG_FILES="$CONFIG_FILES ctdb.pc" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "rm-stdint.h":C) rm -f $libreplacedir/stdint.h ;;
+    "mk-stdint.h":C) echo "#include \"replace.h\"" > $libreplacedir/stdint.h ;;
+    "rm-stdbool.h":C) rm -f $libreplacedir/stdbool.h ;;
+    "mk-stdbool.h":C) echo "#include \"replace.h\"" > $libreplacedir/stdbool.h ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+


Property changes on: branches/ctdb/squeeze-backports/configure
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/configure.ac
===================================================================
--- branches/ctdb/squeeze-backports/configure.ac	                        (rev 0)
+++ branches/ctdb/squeeze-backports/configure.ac	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,105 @@
+AC_PREREQ(2.50)
+AC_INIT(ctdb, m4_esyscmd([grep 'Version:' ./packaging/RPM/ctdb.spec 2>/dev/null | head -1 | sed -e 's/[ \t]*Version:[ \t]*\([^ \t]*\)[ \t]*.*/\1/' | tr -d '\n']))
+AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
+AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
+AC_DEFUN([SMB_EXT_LIB], [echo -n ""])
+AC_DEFUN([SMB_ENABLE], [echo -n ""])
+AC_CONFIG_SRCDIR([server/ctdbd.c])
+
+if test "${libdir}" = '${exec_prefix}/lib'; then
+  case `uname -m` in
+    x86_64|ppc64|powerpc64)
+      libdir='${exec_prefix}/lib64'
+      ;;
+    *)
+      libdir='${exec_prefix}/lib'
+      ;;
+  esac
+fi
+
+case `uname` in
+  Linux*)
+    CTDB_SYSTEM_OBJ=common/system_linux.o
+    CTDB_SCSI_IO=bin/scsi_io
+    CTDB_PCAP_LDFLAGS=
+    ;;
+  AIX*)
+    CTDB_SYSTEM_OBJ=common/system_aix.o
+    CTDB_SCSI_IO=
+    CTDB_PCAP_LDFLAGS=-lpcap
+    ;;
+  *)
+    echo unknown system  cant configure
+    exit
+    ;;
+esac
+
+AC_LIBREPLACE_ALL_CHECKS
+
+if test "$ac_cv_prog_gcc" = yes; then
+   CFLAGS="$CFLAGS -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings"
+fi
+
+LOGDIR='${localstatedir}/log'
+AC_ARG_WITH([logdir],
+	[  --with-logdir=DIR       path to log directory [[LOCALSTATEDIR/log]]],
+	LOGDIR=$withval)
+if test ! -z "$LOGDIR"; then
+  if test "$LOGDIR" = "yes" -o "$LOGDIR" = "no"; then
+    AC_MSG_ERROR([--with-logdir must specify a path])
+  fi
+fi
+AC_SUBST(LOGDIR)
+
+AC_CONFIG_HEADER(config.h)
+
+EXTRA_OBJ=""
+
+m4_include(libpopt.m4)
+m4_include(libtalloc.m4)
+m4_include(libtdb.m4)
+m4_include(libtevent.m4)
+m4_include(ib/config.m4)
+m4_include(lib/util/signal.m4)
+m4_include(lib/util/fault.m4)
+
+AC_CHECK_HEADERS(sched.h)
+AC_CHECK_HEADERS(pcp/pmapi.h pcp/impl.h pcp/pmda.h, [], [],
+[[#ifdef HAVE_PCP_PMAPI_H
+# include <pcp/pmapi.h>
+#endif
+#ifdef HAVE_PCP_IMPL_H
+# include <pcp/impl.h>
+#endif
+]])
+
+AC_CHECK_FUNCS(sched_setscheduler)
+AC_CHECK_FUNCS(mlockall)
+
+AC_CACHE_CHECK([for sin_len in sock],ctdb_cv_HAVE_SOCK_SIN_LEN,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>],
+[struct sockaddr_in sock; sock.sin_len = sizeof(sock);],
+ctdb_cv_HAVE_SOCK_SIN_LEN=yes,ctdb_cv_HAVE_SOCK_SIN_LEN=no)])
+if test x"$ctdb_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then
+    AC_DEFINE(HAVE_SOCK_SIN_LEN,1,[Whether the sockaddr_in struct has a sin_len property])
+fi
+
+if test x"$ac_cv_header_pcp_pmda_h" = x"yes"; then
+    CTDB_PMDA=bin/pmdactdb
+    CTDB_PMDA_INSTALL=install_pmda
+else
+    CTDB_PMDA=
+    CTDB_PMDA_INSTALL=
+fi
+
+
+AC_SUBST(EXTRA_OBJ)
+AC_SUBST(CTDB_SYSTEM_OBJ)
+AC_SUBST(CTDB_SCSI_IO)
+AC_SUBST(CTDB_PCAP_LDFLAGS)
+AC_SUBST(CTDB_PMDA)
+AC_SUBST(CTDB_PMDA_INSTALL)
+
+AC_OUTPUT(Makefile ctdb.pc)

Added: branches/ctdb/squeeze-backports/configure.rpm
===================================================================
--- branches/ctdb/squeeze-backports/configure.rpm	                        (rev 0)
+++ branches/ctdb/squeeze-backports/configure.rpm	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+
+CFLAGS="-Wall -g -D_GNU_SOURCE" ./configure \
+	--prefix=/usr \
+	--sysconfdir=/etc \
+	--mandir=/usr/man \
+	--localstatedir=/var \
+	$*


Property changes on: branches/ctdb/squeeze-backports/configure.rpm
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/ctdb.pc.in
===================================================================
--- branches/ctdb/squeeze-backports/ctdb.pc.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ctdb.pc.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+datarootdir=@datarootdir@
+includedir=@includedir@
+libdir=@libdir@
+bindir=@bindir@
+sbindir=@sbindir@
+mandir=@mandir@
+localstatedir=@localstatedir@
+srcdir=@srcdir@
+etcdir=@sysconfdir@
+
+Name: ctdb
+Description: A clustered database to store temporary data
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir}
+Cflags: -I${includedir}
+URL: http://ctdb.samba.org/
+

Added: branches/ctdb/squeeze-backports/doc/ctdb.1
===================================================================
--- branches/ctdb/squeeze-backports/doc/ctdb.1	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ctdb.1	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,980 @@
+'\" t
+.\"     Title: ctdb
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: 10/12/2011
+.\"    Manual: CTDB - clustered TDB database
+.\"    Source: ctdb
+.\"  Language: English
+.\"
+.TH "CTDB" "1" "10/12/2011" "ctdb" "CTDB \- clustered TDB database"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+ctdb \- clustered tdb database management utility
+.SH "SYNOPSIS"
+.HP \w'\fBctdb\ [\ OPTIONS\ ]\ COMMAND\ \&.\&.\&.\fR\ 'u
+\fBctdb [ OPTIONS ] COMMAND \&.\&.\&.\fR
+.HP \w'\fBctdb\fR\ 'u
+\fBctdb\fR [\-n\ <node>] [\-Y] [\-t\ <timeout>] [\-T\ <timelimit>] [\-?\ \-\-help] [\-\-usage] [\-d\ \-\-debug=<INTEGER>] [\-\-socket=<filename>]
+.SH "DESCRIPTION"
+.PP
+ctdb is a utility to view and manage a ctdb cluster\&.
+.SH "OPTIONS"
+.PP
+\-n <pnn>
+.RS 4
+This specifies the physical node number on which to execute the command\&. Default is to run the command on the daemon running on the local host\&.
+.sp
+The physical node number is an integer that describes the node in the cluster\&. The first node has physical node number 0\&.
+.RE
+.PP
+\-Y
+.RS 4
+Produce output in machine readable form for easier parsing by scripts\&. Not all commands support this option\&.
+.RE
+.PP
+\-t <timeout>
+.RS 4
+How long should ctdb wait for the local ctdb daemon to respond to a command before timing out\&. Default is 3 seconds\&.
+.RE
+.PP
+\-T <timelimit>
+.RS 4
+A limit on how long the ctdb command will run for before it will be aborted\&. When this timelimit has been exceeded the ctdb command will terminate\&.
+.RE
+.PP
+\-? \-\-help
+.RS 4
+Print some help text to the screen\&.
+.RE
+.PP
+\-\-usage
+.RS 4
+Print useage information to the screen\&.
+.RE
+.PP
+\-d \-\-debug=<debuglevel>
+.RS 4
+Change the debug level for the command\&. Default is 0\&.
+.RE
+.PP
+\-\-socket=<filename>
+.RS 4
+Specify the socketname to use when connecting to the local ctdb daemon\&. The default is /tmp/ctdb\&.socket \&.
+.sp
+You only need to specify this parameter if you run multiple ctdb daemons on the same physical host and thus can not use the default name for the domain socket\&.
+.RE
+.SH "ADMINISTRATIVE COMMANDS"
+.PP
+These are commands used to monitor and administrate a CTDB cluster\&.
+.SS "pnn"
+.PP
+This command displays the pnn of the current node\&.
+.SS "status"
+.PP
+This command shows the current status of the ctdb node\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBnode status\fR
+.RS 4
+.PP
+Node status reflects the current status of the node\&. There are five possible states:
+.PP
+OK \- This node is fully functional\&.
+.PP
+DISCONNECTED \- This node could not be connected through the network and is currently not participating in the cluster\&. If there is a public IP address associated with this node it should have been taken over by a different node\&. No services are running on this node\&.
+.PP
+DISABLED \- This node has been administratively disabled\&. This node is still functional and participates in the CTDB cluster but its IP addresses have been taken over by a different node and no services are currently being hosted\&.
+.PP
+UNHEALTHY \- A service provided by this node is malfunctioning and should be investigated\&. The CTDB daemon itself is operational and participates in the cluster\&. Its public IP address has been taken over by a different node and no services are currnetly being hosted\&. All unhealthy nodes should be investigated and require an administrative action to rectify\&.
+.PP
+BANNED \- This node failed too many recovery attempts and has been banned from participating in the cluster for a period of RecoveryBanPeriod seconds\&. Any public IP address has been taken over by other nodes\&. This node does not provide any services\&. All banned nodes should be investigated and require an administrative action to rectify\&. This node does not perticipate in the CTDB cluster but can still be communicated with\&. I\&.e\&. ctdb commands can be sent to it\&.
+.PP
+STOPPED \- A node that is stopped does not host any public ip addresses, nor is it part of the VNNMAP\&. A stopped node can not become LVSMASTER, RECMASTER or NATGW\&. This node does not perticipate in the CTDB cluster but can still be communicated with\&. I\&.e\&. ctdb commands can be sent to it\&.
+.PP
+PARTIALLYONLINE \- A node that is partially online participates in a cluster like a node that is ok\&. Some interfaces to serve public ip addresses are down, but at least one interface is up\&. See also "ctdb ifaces"\&.
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBgeneration\fR
+.RS 4
+.PP
+The generation id is a number that indicates the current generation of a cluster instance\&. Each time a cluster goes through a reconfiguration or a recovery its generation id will be changed\&.
+.PP
+This number does not have any particular meaning other than to keep track of when a cluster has gone through a recovery\&. It is a random number that represents the current instance of a ctdb cluster and its databases\&. CTDBD uses this number internally to be able to tell when commands to operate on the cluster and the databases was issued in a different generation of the cluster, to ensure that commands that operate on the databases will not survive across a cluster database recovery\&. After a recovery, all old outstanding commands will automatically become invalid\&.
+.PP
+Sometimes this number will be shown as "INVALID"\&. This only means that the ctdbd daemon has started but it has not yet merged with the cluster through a recovery\&. All nodes start with generation "INVALID" and are not assigned a real generation id until they have successfully been merged with a cluster through a recovery\&.
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBVNNMAP\fR
+.RS 4
+.PP
+The list of Virtual Node Numbers\&. This is a list of all nodes that actively participates in the cluster and that share the workload of hosting the Clustered TDB database records\&. Only nodes that are participating in the vnnmap can become lmaster or dmaster for a database record\&.
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBRecovery mode\fR
+.RS 4
+.PP
+This is the current recovery mode of the cluster\&. There are two possible modes:
+.PP
+NORMAL \- The cluster is fully operational\&.
+.PP
+RECOVERY \- The cluster databases have all been frozen, pausing all services while the cluster awaits a recovery process to complete\&. A recovery process should finish within seconds\&. If a cluster is stuck in the RECOVERY state this would indicate a cluster malfunction which needs to be investigated\&.
+.PP
+Once the recovery master detects an inconsistency, for example a node becomes disconnected/connected, the recovery daemon will trigger a cluster recovery process, where all databases are remerged across the cluster\&. When this process starts, the recovery master will first "freeze" all databases to prevent applications such as samba from accessing the databases and it will also mark the recovery mode as RECOVERY\&.
+.PP
+When CTDBD starts up, it will start in RECOVERY mode\&. Once the node has been merged into a cluster and all databases have been recovered, the node mode will change into NORMAL mode and the databases will be "thawed", allowing samba to access the databases again\&.
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBRecovery master\fR
+.RS 4
+.PP
+This is the cluster node that is currently designated as the recovery master\&. This node is responsible of monitoring the consistency of the cluster and to perform the actual recovery process when reqired\&.
+.PP
+Only one node at a time can be the designated recovery master\&. Which node is designated the recovery master is decided by an election process in the recovery daemons running on each node\&.
+.RE
+.PP
+Example: ctdb status
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Number of nodes:4
+pnn:0 11\&.1\&.2\&.200       OK (THIS NODE)
+pnn:1 11\&.1\&.2\&.201       OK
+pnn:2 11\&.1\&.2\&.202       OK
+pnn:3 11\&.1\&.2\&.203       OK
+Generation:1362079228
+Size:4
+hash:0 lmaster:0
+hash:1 lmaster:1
+hash:2 lmaster:2
+hash:3 lmaster:3
+Recovery mode:NORMAL (0)
+Recovery master:0
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "recmaster"
+.PP
+This command shows the pnn of the node which is currently the recmaster\&.
+.SS "uptime"
+.PP
+This command shows the uptime for the ctdb daemon\&. When the last recovery or ip\-failover completed and how long it took\&. If the "duration" is shown as a negative number, this indicates that there is a recovery/failover in progress and it started that many seconds ago\&.
+.PP
+Example: ctdb uptime
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Current time of node          :                Thu Oct 29 10:38:54 2009
+Ctdbd start time              : (000 16:54:28) Wed Oct 28 17:44:26 2009
+Time of last recovery/failover: (000 16:53:31) Wed Oct 28 17:45:23 2009
+Duration of last recovery/failover: 2\&.248552 seconds
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "listnodes"
+.PP
+This command shows lists the ip addresses of all the nodes in the cluster\&.
+.PP
+Example: ctdb listnodes
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+10\&.0\&.0\&.71
+10\&.0\&.0\&.72
+10\&.0\&.0\&.73
+10\&.0\&.0\&.74
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "ping"
+.PP
+This command will "ping" all CTDB daemons in the cluster to verify that they are processing commands correctly\&.
+.PP
+Example: ctdb ping
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+response from 0 time=0\&.000054 sec  (3 clients)
+response from 1 time=0\&.000144 sec  (2 clients)
+response from 2 time=0\&.000105 sec  (2 clients)
+response from 3 time=0\&.000114 sec  (2 clients)
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "ifaces"
+.PP
+This command will display the list of network interfaces, which could host public addresses, along with their status\&.
+.PP
+Example: ctdb ifaces
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Interfaces on node 0
+name:eth5 link:up references:2
+name:eth4 link:down references:0
+name:eth3 link:up references:1
+name:eth2 link:up references:1
+      
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Example: ctdb ifaces \-Y
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+:Name:LinkStatus:References:
+:eth5:1:2
+:eth4:0:0
+:eth3:1:1
+:eth2:1:1
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "setifacelink <iface> <status>"
+.PP
+This command will set the status of a network interface\&. The status needs to be "up" or "down"\&. This is typically used in the 10\&.interfaces script in the "monitor" event\&.
+.PP
+Example: ctdb setifacelink eth0 up
+.SS "ip"
+.PP
+This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip\&. By default this command will ONLY show those public addresses that are known to the node itself\&. To see the full list of all public ips across the cluster you must use "ctdb ip \-n all"\&.
+.PP
+Example: ctdb ip
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Public IPs on node 0
+172\&.31\&.91\&.82 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
+172\&.31\&.91\&.83 node[0] active[eth3] available[eth2,eth3] configured[eth2,eth3]
+172\&.31\&.91\&.84 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
+172\&.31\&.91\&.85 node[0] active[eth2] available[eth2,eth3] configured[eth2,eth3]
+172\&.31\&.92\&.82 node[1] active[] available[eth5] configured[eth4,eth5]
+172\&.31\&.92\&.83 node[0] active[eth5] available[eth5] configured[eth4,eth5]
+172\&.31\&.92\&.84 node[1] active[] available[eth5] configured[eth4,eth5]
+172\&.31\&.92\&.85 node[0] active[eth5] available[eth5] configured[eth4,eth5]
+      
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Example: ctdb ip \-Y
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+:Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:
+:172\&.31\&.91\&.82:1::eth2,eth3:eth2,eth3:
+:172\&.31\&.91\&.83:0:eth3:eth2,eth3:eth2,eth3:
+:172\&.31\&.91\&.84:1::eth2,eth3:eth2,eth3:
+:172\&.31\&.91\&.85:0:eth2:eth2,eth3:eth2,eth3:
+:172\&.31\&.92\&.82:1::eth5:eth4,eth5:
+:172\&.31\&.92\&.83:0:eth5:eth5:eth4,eth5:
+:172\&.31\&.92\&.84:1::eth5:eth4,eth5:
+:172\&.31\&.92\&.85:0:eth5:eth5:eth4,eth5:
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "ipinfo <ip>"
+.PP
+This command will display details about the specified public addresses\&.
+.PP
+Example: ctdb ipinfo 172\&.31\&.92\&.85
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Public IP[172\&.31\&.92\&.85] info on node 0
+IP:172\&.31\&.92\&.85
+CurrentNode:0
+NumInterfaces:2
+Interface[1]: Name:eth4 Link:down References:0
+Interface[2]: Name:eth5 Link:up References:2 (active)
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "scriptstatus"
+.PP
+This command displays which scripts where run in the previous monitoring cycle and the result of each script\&. If a script failed with an error, causing the node to become unhealthy, the output from that script is also shown\&.
+.PP
+Example: ctdb scriptstatus
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+7 scripts were executed last monitoring cycle
+00\&.ctdb              Status:OK    Duration:0\&.056 Tue Mar 24 18:56:57 2009
+10\&.interface         Status:OK    Duration:0\&.077 Tue Mar 24 18:56:57 2009
+11\&.natgw             Status:OK    Duration:0\&.039 Tue Mar 24 18:56:57 2009
+20\&.multipathd        Status:OK    Duration:0\&.038 Tue Mar 24 18:56:57 2009
+31\&.clamd             Status:DISABLED
+40\&.vsftpd            Status:OK    Duration:0\&.045 Tue Mar 24 18:56:57 2009
+41\&.httpd             Status:OK    Duration:0\&.039 Tue Mar 24 18:56:57 2009
+50\&.samba             Status:ERROR    Duration:0\&.082 Tue Mar 24 18:56:57 2009
+   OUTPUT:ERROR: Samba tcp port 445 is not responding
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "disablescript <script>"
+.PP
+This command is used to disable an eventscript\&.
+.PP
+This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in \*(Aqscriptstatus\*(Aq\&.
+.SS "enablescript <script>"
+.PP
+This command is used to enable an eventscript\&.
+.PP
+This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in \*(Aqscriptstatus\*(Aq\&.
+.SS "getvar <name>"
+.PP
+Get the runtime value of a tuneable variable\&.
+.PP
+Example: ctdb getvar MaxRedirectCount
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+MaxRedirectCount    = 3
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "setvar <name> <value>"
+.PP
+Set the runtime value of a tuneable variable\&.
+.PP
+Example: ctdb setvar MaxRedirectCount 5
+.SS "listvars"
+.PP
+List all tuneable variables\&.
+.PP
+Example: ctdb listvars
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+MaxRedirectCount    = 3
+SeqnumInterval      = 1000
+ControlTimeout      = 60
+TraverseTimeout     = 20
+KeepaliveInterval   = 5
+KeepaliveLimit      = 5
+RecoverTimeout      = 20
+RecoverInterval     = 1
+ElectionTimeout     = 3
+TakeoverTimeout     = 9
+MonitorInterval     = 15
+TickleUpdateInterval = 20
+EventScriptTimeout  = 30
+EventScriptTimeoutCount = 1
+EventScriptUnhealthyOnTimeout = 0
+RecoveryGracePeriod = 120
+RecoveryBanPeriod   = 300
+DatabaseHashSize    = 100001
+DatabaseMaxDead     = 5
+RerecoveryTimeout   = 10
+EnableBans          = 1
+DeterministicIPs    = 1
+ReclockPingPeriod   = 60
+NoIPFailback        = 0
+DisableIPFailover   = 0
+VerboseMemoryNames  = 0
+RecdPingTimeout     = 60
+RecdFailCount       = 10
+LogLatencyMs        = 0
+RecLockLatencyMs    = 1000
+RecoveryDropAllIPs  = 120
+VerifyRecoveryLock  = 1
+VacuumDefaultInterval = 10
+VacuumMaxRunTime    = 30
+RepackLimit         = 10000
+VacuumLimit         = 5000
+VacuumMinInterval   = 10
+VacuumMaxInterval   = 10
+VacuumFastPathCount = 60
+MaxQueueDropMsg     = 1000000
+UseStatusEvents     = 0
+AllowUnhealthyDBRead = 0
+StatHistoryInterval = 1
+DeferredAttachTO    = 120
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "lvsmaster"
+.PP
+This command shows which node is currently the LVSMASTER\&. The LVSMASTER is the node in the cluster which drives the LVS system and which receives all incoming traffic from clients\&.
+.PP
+LVS is the mode where the entire CTDB/Samba cluster uses a single ip address for the entire cluster\&. In this mode all clients connect to one specific node which will then multiplex/loadbalance the clients evenly onto the other nodes in the cluster\&. This is an alternative to using public ip addresses\&. See the manpage for ctdbd for more information about LVS\&.
+.SS "lvs"
+.PP
+This command shows which nodes in the cluster are currently active in the LVS configuration\&. I\&.e\&. which nodes we are currently loadbalancing the single ip address across\&.
+.PP
+LVS will by default only loadbalance across those nodes that are both LVS capable and also HEALTHY\&. Except if all nodes are UNHEALTHY in which case LVS will loadbalance across all UNHEALTHY nodes as well\&. LVS will never use nodes that are DISCONNECTED, STOPPED, BANNED or DISABLED\&.
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+2:10\&.0\&.0\&.13
+3:10\&.0\&.0\&.14
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "getcapabilities"
+.PP
+This command shows the capabilities of the current node\&. Please see manpage for ctdbd for a full list of all capabilities and more detailed description\&.
+.PP
+RECMASTER and LMASTER capabilities are primarily used when CTDBD is used to create a cluster spanning across WAN links\&. In which case ctdbd acts as a WAN accelerator\&.
+.PP
+LVS capabile means that the node is participating in LVS, a mode where the entire CTDB cluster uses one single ip address for the entire cluster instead of using public ip address failover\&. This is an alternative to using a loadbalancing layer\-4 switch\&.
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+RECMASTER: YES
+LMASTER: YES
+LVS: NO
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "statistics"
+.PP
+Collect statistics from the CTDB daemon about how many calls it has served\&.
+.PP
+Example: ctdb statistics
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+CTDB version 1
+ num_clients                        3
+ frozen                             0
+ recovering                         0
+ client_packets_sent           360489
+ client_packets_recv           360466
+ node_packets_sent             480931
+ node_packets_recv             240120
+ keepalive_packets_sent             4
+ keepalive_packets_recv             3
+ node
+     req_call                       2
+     reply_call                     2
+     req_dmaster                    0
+     reply_dmaster                  0
+     reply_error                    0
+     req_message                   42
+     req_control               120408
+     reply_control             360439
+ client
+     req_call                       2
+     req_message                   24
+     req_control               360440
+ timeouts
+     call                           0
+     control                        0
+     traverse                       0
+ total_calls                        2
+ pending_calls                      0
+ lockwait_calls                     0
+ pending_lockwait_calls             0
+ memory_used                     5040
+ max_hop_count                      0
+ max_call_latency                   4\&.948321 sec
+ max_lockwait_latency               0\&.000000 sec
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "statisticsreset"
+.PP
+This command is used to clear all statistics counters in a node\&.
+.PP
+Example: ctdb statisticsreset
+.SS "getreclock"
+.PP
+This command is used to show the filename of the reclock file that is used\&.
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Reclock file:/gpfs/\&.ctdb/shared
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "setreclock [filename]"
+.PP
+This command is used to modify, or clear, the file that is used as the reclock file at runtime\&. When this command is used, the reclock file checks are disabled\&. To re\-enable the checks the administrator needs to activate the "VerifyRecoveryLock" tunable using "ctdb setvar"\&.
+.PP
+If run with no parameter this will remove the reclock file completely\&. If run with a parameter the parameter specifies the new filename to use for the recovery lock\&.
+.PP
+This command only affects the runtime settings of a ctdb node and will be lost when ctdb is restarted\&. For persistent changes to the reclock file setting you must edit /etc/sysconfig/ctdb\&.
+.SS "getdebug"
+.PP
+Get the current debug level for the node\&. the debug level controls what information is written to the log file\&.
+.PP
+The debug levels are mapped to the corresponding syslog levels\&. When a debug level is set, only those messages at that level and higher levels will be printed\&.
+.PP
+The list of debug levels from highest to lowest are :
+.PP
+EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG
+.SS "setdebug <debuglevel>"
+.PP
+Set the debug level of a node\&. This controls what information will be logged\&.
+.PP
+The debuglevel is one of EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG
+.SS "getpid"
+.PP
+This command will return the process id of the ctdb daemon\&.
+.SS "disable"
+.PP
+This command is used to administratively disable a node in the cluster\&. A disabled node will still participate in the cluster and host clustered TDB records but its public ip address has been taken over by a different node and it no longer hosts any services\&.
+.SS "enable"
+.PP
+Re\-enable a node that has been administratively disabled\&.
+.SS "stop"
+.PP
+This command is used to administratively STOP a node in the cluster\&. A STOPPED node is connected to the cluster but will not host any public ip addresse, nor does it participate in the VNNMAP\&. The difference between a DISABLED node and a STOPPED node is that a STOPPED node does not host any parts of the database which means that a recovery is required to stop/continue nodes\&.
+.SS "continue"
+.PP
+Re\-start a node that has been administratively stopped\&.
+.SS "addip <public_ip/mask> <iface>"
+.PP
+This command is used to add a new public ip to a node during runtime\&. This allows public addresses to be added to a cluster without having to restart the ctdb daemons\&.
+.PP
+Note that this only updates the runtime instance of ctdb\&. Any changes will be lost next time ctdb is restarted and the public addresses file is re\-read\&. If you want this change to be permanent you must also update the public addresses file manually\&.
+.SS "delip <public_ip>"
+.PP
+This command is used to remove a public ip from a node during runtime\&. If this public ip is currently hosted by the node it being removed from, the ip will first be failed over to another node, if possible, before it is removed\&.
+.PP
+Note that this only updates the runtime instance of ctdb\&. Any changes will be lost next time ctdb is restarted and the public addresses file is re\-read\&. If you want this change to be permanent you must also update the public addresses file manually\&.
+.SS "moveip <public_ip> <node>"
+.PP
+This command can be used to manually fail a public ip address to a specific node\&.
+.PP
+In order to manually override the "automatic" distribution of public ip addresses that ctdb normally provides, this command only works when you have changed the tunables for the daemon to:
+.PP
+DeterministicIPs = 0
+.PP
+NoIPFailback = 1
+.SS "shutdown"
+.PP
+This command will shutdown a specific CTDB daemon\&.
+.SS "recover"
+.PP
+This command will trigger the recovery daemon to do a cluster recovery\&.
+.SS "ipreallocate"
+.PP
+This command will force the recovery master to perform a full ip reallocation process and redistribute all ip addresses\&. This is useful to "reset" the allocations back to its default state if they have been changed using the "moveip" command\&. While a "recover" will also perform this reallocation, a recovery is much more hevyweight since it will also rebuild all the databases\&.
+.SS "setlmasterrole <on|off>"
+.PP
+This command is used ot enable/disable the LMASTER capability for a node at runtime\&. This capability determines whether or not a node can be used as an LMASTER for records in the database\&. A node that does not have the LMASTER capability will not show up in the vnnmap\&.
+.PP
+Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command\&.
+.PP
+Once this setting has been enabled/disabled, you need to perform a recovery for it to take effect\&.
+.PP
+See also "ctdb getcapabilities"
+.SS "setrecmasterrole <on|off>"
+.PP
+This command is used ot enable/disable the RECMASTER capability for a node at runtime\&. This capability determines whether or not a node can be used as an RECMASTER for the cluster\&. A node that does not have the RECMASTER capability can not win a recmaster election\&. A node that already is the recmaster for the cluster when the capability is stripped off the node will remain the recmaster until the next cluster election\&.
+.PP
+Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command\&.
+.PP
+See also "ctdb getcapabilities"
+.SS "killtcp <srcip:port> <dstip:port>"
+.PP
+This command will kill the specified TCP connection by issuing a TCP RST to the srcip:port endpoint\&. This is a command used by the ctdb eventscripts\&.
+.SS "gratiousarp <ip> <interface>"
+.PP
+This command will send out a gratious arp for the specified interface through the specified interface\&. This command is mainly used by the ctdb eventscripts\&.
+.SS "reloadnodes"
+.PP
+This command is used when adding new nodes, or removing existing nodes from an existing cluster\&.
+.PP
+Procedure to add a node:
+.PP
+1, To expand an existing cluster, first ensure with \*(Aqctdb status\*(Aq that all nodes are up and running and that they are all healthy\&. Do not try to expand a cluster unless it is completely healthy!
+.PP
+2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last entry to the file\&. The new node MUST be added to the end of this file!
+.PP
+3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node!
+.PP
+4, Run \*(Aqctdb reloadnodes\*(Aq to force all nodes to reload the nodesfile\&.
+.PP
+5, Use \*(Aqctdb status\*(Aq on all nodes and verify that they now show the additional node\&.
+.PP
+6, Install and configure the new node and bring it online\&.
+.PP
+Procedure to remove a node:
+.PP
+1, To remove a node from an existing cluster, first ensure with \*(Aqctdb status\*(Aq that all nodes, except the node to be deleted, are up and running and that they are all healthy\&. Do not try to remove a node from a cluster unless the cluster is completely healthy!
+.PP
+2, Shutdown and poweroff the node to be removed\&.
+.PP
+3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed\&. Do not delete the line for that node, just comment it out by adding a \*(Aq#\*(Aq at the beginning of the line\&.
+.PP
+4, Run \*(Aqctdb reloadnodes\*(Aq to force all nodes to reload the nodesfile\&.
+.PP
+5, Use \*(Aqctdb status\*(Aq on all nodes and verify that the deleted node no longer shows up in the list\&.\&.
+.PP
+.SS "tickle <srcip:port> <dstip:port>"
+.PP
+This command will will send a TCP tickle to the source host for the specified TCP connection\&. A TCP tickle is a TCP ACK packet with an invalid sequence and acknowledge number and will when received by the source host result in it sending an immediate correct ACK back to the other end\&.
+.PP
+TCP tickles are useful to "tickle" clients after a IP failover has occured since this will make the client immediately recognize the TCP connection has been disrupted and that the client will need to reestablish\&. This greatly speeds up the time it takes for a client to detect and reestablish after an IP failover in the ctdb cluster\&.
+.SS "gettickles <ip>"
+.PP
+This command is used to show which TCP connections are registered with CTDB to be "tickled" if there is a failover\&.
+.SS "repack [max_freelist]"
+.PP
+Over time, when records are created and deleted in a TDB, the TDB list of free space will become fragmented\&. This can lead to a slowdown in accessing TDB records\&. This command is used to defragment a TDB database and pruning the freelist\&.
+.PP
+If [max_freelist] is specified, then a database will only be repacked if it has more than this number of entries in the freelist\&.
+.PP
+During repacking of the database, the entire TDB database will be locked to prevent writes\&. If samba tries to write to a record in the database during a repack operation, samba will block until the repacking has completed\&.
+.PP
+This command can be disruptive and can cause samba to block for the duration of the repack operation\&. In general, a repack operation will take less than one second to complete\&.
+.PP
+A repack operation will only defragment the local TDB copy of the CTDB database\&. You need to run this command on all of the nodes to repack a CTDB database completely\&.
+.PP
+Example: ctdb repack 1000
+.PP
+By default, this operation is issued from the 00\&.ctdb event script every 5 minutes\&.
+.SS "vacuum [max_records]"
+.PP
+Over time CTDB databases will fill up with empty deleted records which will lead to a progressive slow down of CTDB database access\&. This command is used to prune all databases and delete all empty records from the cluster\&.
+.PP
+By default, vacuum will delete all empty records from all databases\&. If [max_records] is specified, the command will only delete the first [max_records] empty records for each database\&.
+.PP
+Vacuum only deletes records where the local node is the lmaster\&. To delete all records from the entire cluster you need to run a vacuum from each node\&. This command is not disruptive\&. Samba is unaffected and will still be able to read/write records normally while the database is being vacuumed\&.
+.PP
+Example: ctdb vacuum
+.PP
+By default, this operation is issued from the 00\&.ctdb event script every 5 minutes\&.
+.SS "backupdb <dbname> <file>"
+.PP
+This command can be used to copy the entire content of a database out to a file\&. This file can later be read back into ctdb using the restoredb command\&. This is mainly useful for backing up persistent databases such as secrets\&.tdb and similar\&.
+.SS "restoredb <file> [<dbname>]"
+.PP
+This command restores a persistent database that was previously backed up using backupdb\&. By default the data will be restored back into the same database as it was created from\&. By specifying dbname you can restore the data into a different database\&.
+.SS "wipedb <dbname>"
+.PP
+This command can be used to remove all content of a database\&.
+.SS "getlog <level>"
+.PP
+In addition to the normal loggign to a log file, CTDBD also keeps a in\-memory ringbuffer containing the most recent log entries for all log levels (except DEBUG)\&.
+.PP
+This is useful since it allows for keeping continuous logs to a file at a reasonable non\-verbose level, but shortly after an incident has occured, a much more detailed log can be pulled from memory\&. This can allow you to avoid having to reproduce an issue due to the on\-disk logs being of insufficient detail\&.
+.PP
+This command extracts all messages of level or lower log level from memory and prints it to the screen\&.
+.SS "clearlog"
+.PP
+This command clears the in\-memory logging ringbuffer\&.
+.SH "DEBUGGING COMMANDS"
+.PP
+These commands are primarily used for CTDB development and testing and should not be used for normal administration\&.
+.SS "process\-exists <pid>"
+.PP
+This command checks if a specific process exists on the CTDB host\&. This is mainly used by Samba to check if remote instances of samba are still running or not\&.
+.SS "getdbmap"
+.PP
+This command lists all clustered TDB databases that the CTDB daemon has attached to\&. Some databases are flagged as PERSISTENT, this means that the database stores data persistently and the data will remain across reboots\&. One example of such a database is secrets\&.tdb where information about how the cluster was joined to the domain is stored\&.
+.PP
+If a PERSISTENT database is not in a healthy state the database is flagged as UNHEALTHY\&. If there\*(Aqs at least one completely healthy node running in the cluster, it\*(Aqs possible that the content is restored by a recovery run automaticly\&. Otherwise an administrator needs to analyze the problem\&.
+.PP
+See also "ctdb getdbstatus", "ctdb backupdb", "ctdb restoredb", "ctdb dumpbackup", "ctdb wipedb", "ctdb setvar AllowUnhealthyDBRead 1" and (if samba or tdb\-utils are installed) "tdbtool check"\&.
+.PP
+Most databases are not persistent and only store the state information that the currently running samba daemons need\&. These databases are always wiped when ctdb/samba starts and when a node is rebooted\&.
+.PP
+Example: ctdb getdbmap
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Number of databases:10
+dbid:0x435d3410 name:notify\&.tdb path:/var/ctdb/notify\&.tdb\&.0 
+dbid:0x42fe72c5 name:locking\&.tdb path:/var/ctdb/locking\&.tdb\&.0
+dbid:0x1421fb78 name:brlock\&.tdb path:/var/ctdb/brlock\&.tdb\&.0 
+dbid:0x17055d90 name:connections\&.tdb path:/var/ctdb/connections\&.tdb\&.0 
+dbid:0xc0bdde6a name:sessionid\&.tdb path:/var/ctdb/sessionid\&.tdb\&.0 
+dbid:0x122224da name:test\&.tdb path:/var/ctdb/test\&.tdb\&.0 
+dbid:0x2672a57f name:idmap2\&.tdb path:/var/ctdb/persistent/idmap2\&.tdb\&.0 PERSISTENT
+dbid:0xb775fff6 name:secrets\&.tdb path:/var/ctdb/persistent/secrets\&.tdb\&.0 PERSISTENT
+dbid:0xe98e08b6 name:group_mapping\&.tdb path:/var/ctdb/persistent/group_mapping\&.tdb\&.0 PERSISTENT
+dbid:0x7bbbd26c name:passdb\&.tdb path:/var/ctdb/persistent/passdb\&.tdb\&.0 PERSISTENT
+      
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Example output for an unhealthy database:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Number of databases:1
+dbid:0xb775fff6 name:secrets\&.tdb path:/var/ctdb/persistent/secrets\&.tdb\&.0 PERSISTENT UNHEALTHY
+      
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Example output for a healthy database as machinereadable output \-Y:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+:ID:Name:Path:Persistent:Unhealthy:
+:0x7bbbd26c:passdb\&.tdb:/var/ctdb/persistent/passdb\&.tdb\&.0:1:0:
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "getdbstatus <dbname>"
+.PP
+This command displays more details about a database\&.
+.PP
+Example: ctdb getdbstatus test\&.tdb\&.0
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+dbid: 0x122224da
+name: test\&.tdb
+path: /var/ctdb/test\&.tdb\&.0
+PERSISTENT: no
+HEALTH: OK
+      
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Example: ctdb getdbstatus registry\&.tdb (with a corrupted TDB)
+.PP
+Example output:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+dbid: 0xf2a58948
+name: registry\&.tdb
+path: /var/ctdb/persistent/registry\&.tdb\&.0
+PERSISTENT: yes
+HEALTH: NO\-HEALTHY\-NODES \- ERROR \- Backup of corrupted TDB in \*(Aq/var/ctdb/persistent/registry\&.tdb\&.0\&.corrupted\&.20091208091949\&.0Z\*(Aq
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "catdb <dbname>"
+.PP
+This command will dump a clustered TDB database to the screen\&. This is a debugging command\&.
+.SS "cattdb <dbname>"
+.PP
+This command will dump the content of the local TDB database to the screen\&. This is a debugging command\&.
+.SS "dumpdbbackup <backup\-file>"
+.PP
+This command will dump the content of database backup to the screen (similar to ctdb catdb)\&. This is a debugging command\&.
+.SS "getmonmode"
+.PP
+This command returns the monutoring mode of a node\&. The monitoring mode is either ACTIVE or DISABLED\&. Normally a node will continuously monitor that all other nodes that are expected are in fact connected and that they respond to commands\&.
+.PP
+ACTIVE \- This is the normal mode\&. The node is actively monitoring all other nodes, both that the transport is connected and also that the node responds to commands\&. If a node becomes unavailable, it will be marked as DISCONNECTED and a recovery is initiated to restore the cluster\&.
+.PP
+DISABLED \- This node is not monitoring that other nodes are available\&. In this mode a node failure will not be detected and no recovery will be performed\&. This mode is useful when for debugging purposes one wants to attach GDB to a ctdb process but wants to prevent the rest of the cluster from marking this node as DISCONNECTED and do a recovery\&.
+.SS "setmonmode <0|1>"
+.PP
+This command can be used to explicitly disable/enable monitoring mode on a node\&. The main purpose is if one wants to attach GDB to a running ctdb daemon but wants to prevent the other nodes from marking it as DISCONNECTED and issuing a recovery\&. To do this, set monitoring mode to 0 on all nodes before attaching with GDB\&. Remember to set monitoring mode back to 1 afterwards\&.
+.SS "attach <dbname> [persistent]"
+.PP
+This is a debugging command\&. This command will make the CTDB daemon create a new CTDB database and attach to it\&.
+.SS "dumpmemory"
+.PP
+This is a debugging command\&. This command will make the ctdb daemon to write a fill memory allocation map to standard output\&.
+.SS "rddumpmemory"
+.PP
+This is a debugging command\&. This command will dump the talloc memory allocation tree for the recovery daemon to standard output\&.
+.SS "thaw"
+.PP
+Thaw a previously frozen node\&.
+.SS "eventscript <arguments>"
+.PP
+This is a debugging command\&. This command can be used to manually invoke and run the eventscritps with arbitrary arguments\&.
+.SS "ban <bantime|0>"
+.PP
+Administratively ban a node for bantime seconds\&. A bantime of 0 means that the node should be permanently banned\&.
+.PP
+A banned node does not participate in the cluster and does not host any records for the clustered TDB\&. Its ip address has been taken over by another node and no services are hosted\&.
+.PP
+Nodes are automatically banned if they are the cause of too many cluster recoveries\&.
+.PP
+This is primarily a testing command\&. Note that the recovery daemon controls the overall ban state and it may automatically unban nodes at will\&. Meaning that a node that has been banned by the administrator can and ofter are unbanned before the admin specifid timeout triggers\&. If wanting to "drop" a node out from the cluster for mainentance or other reasons, use the "stop" / "continue" commands instad of "ban" / "unban"\&.
+.SS "unban"
+.PP
+This command is used to unban a node that has either been administratively banned using the ban command or has been automatically banned by the recovery daemon\&.
+.SH "SEE ALSO"
+.PP
+ctdbd(1), onnode(1)
+\m[blue]\fB\%http://ctdb.samba.org/\fR\m[]
+.SH "COPYRIGHT/LICENSE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Copyright (C) Andrew Tridgell 2007
+Copyright (C) Ronnie sahlberg 2007
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version\&.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&.  See the GNU
+General Public License for more details\&.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www\&.gnu\&.org/licenses/\&.
+.fi
+.if n \{\
+.RE
+.\}

Added: branches/ctdb/squeeze-backports/doc/ctdb.1.html
===================================================================
--- branches/ctdb/squeeze-backports/doc/ctdb.1.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ctdb.1.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,737 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" title="ctdb"><a name="ctdb.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb — clustered tdb database management utility</p></div><div class="refsynopsisdiv" title="Synopsis"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdb [ OPTIONS ] COMMAND ...</code> </p></div><div class="cmdsynopsis"><p><code class="command">ctdb</code>  [-n <node>] [-Y] [-t <timeout>] [-T <timelimit>] [-? --help] [--usage] [-d --debug=<INTEGER>] [--socket=<filename>]</p></div></div><div class="refsect1" title="DESCRIPTION"><a name="id548384"></a><h2>DESCRIPTION</h2><p>
+      ctdb is a utility to view and manage a ctdb cluster.
+    </p></div><div class="refsect1" title="OPTIONS"><a name="id548394"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">-n <pnn></span></dt><dd><p>
+            This specifies the physical node number on which to execute the 
+	    command. Default is to run the command on the daemon running on 
+	    the local host.
+	  </p><p>
+	    The physical node number is an integer that describes the node in the
+	    cluster. The first node has physical node number 0.
+          </p></dd><dt><span class="term">-Y</span></dt><dd><p>
+            Produce output in machine readable form for easier parsing by scripts. Not all commands support this option.
+          </p></dd><dt><span class="term">-t <timeout></span></dt><dd><p>
+            How long should ctdb wait for the local ctdb daemon to respond to a command before timing out. Default is 3 seconds.
+          </p></dd><dt><span class="term">-T <timelimit></span></dt><dd><p>
+            A limit on how long the ctdb command will run for before it will
+	    be aborted. When this timelimit has been exceeded the ctdb command will
+	    terminate.
+          </p></dd><dt><span class="term">-? --help</span></dt><dd><p>
+            Print some help text to the screen.
+          </p></dd><dt><span class="term">--usage</span></dt><dd><p>
+            Print useage information to the screen.
+          </p></dd><dt><span class="term">-d --debug=<debuglevel></span></dt><dd><p>
+            Change the debug level for the command. Default is 0.
+          </p></dd><dt><span class="term">--socket=<filename></span></dt><dd><p>
+            Specify the socketname to use when connecting to the local ctdb 
+            daemon. The default is /tmp/ctdb.socket .
+          </p><p>
+            You only need to specify this parameter if you run multiple ctdb 
+            daemons on the same physical host and thus can not use the default
+            name for the domain socket.
+          </p></dd></dl></div></div><div class="refsect1" title="Administrative Commands"><a name="id548518"></a><h2>Administrative Commands</h2><p>
+      These are commands used to monitor and administrate a CTDB cluster.
+    </p><div class="refsect2" title="pnn"><a name="id548526"></a><h3>pnn</h3><p>
+        This command displays the pnn of the current node.
+      </p></div><div class="refsect2" title="status"><a name="id548535"></a><h3>status</h3><p>
+        This command shows the current status of the ctdb node.
+      </p><div class="refsect3" title="node status"><a name="id548543"></a><h4>node status</h4><p>
+          Node status reflects the current status of the node. There are five possible states:
+        </p><p>
+          OK - This node is fully functional.
+        </p><p>
+          DISCONNECTED - This node could not be connected through the network and is currently not participating in the cluster. If there is a public IP address associated with this node it should have been taken over by a different node. No services are running on this node.
+        </p><p>
+          DISABLED - This node has been administratively disabled. This node is still functional and participates in the CTDB cluster but its IP addresses have been taken over by a different node and no services are currently being hosted.
+        </p><p>
+          UNHEALTHY - A service provided by this node is malfunctioning and should be investigated. The CTDB daemon itself is operational and participates in the cluster. Its public IP address has been taken over by a different node and no services are currnetly being hosted. All unhealthy nodes should be investigated and require an administrative action to rectify.
+        </p><p>
+          BANNED - This node failed too many recovery attempts and has been banned from participating in the cluster for a period of RecoveryBanPeriod seconds. Any public IP address has been taken over by other nodes. This node does not provide any services. All banned nodes should be investigated and require an administrative action to rectify. This node does not perticipate in the CTDB cluster but can still be communicated with. I.e. ctdb commands can be sent to it.
+        </p><p>
+      STOPPED - A node that is stopped does not host any public ip addresses,
+      nor is it part of the VNNMAP. A stopped node can not become LVSMASTER,
+      RECMASTER or NATGW.
+      This node does not perticipate in the CTDB cluster but can still be
+      communicated with. I.e. ctdb commands can be sent to it.
+        </p><p>
+	PARTIALLYONLINE - A node that is partially online participates
+	in a cluster like a node that is ok. Some interfaces to serve
+	public ip addresses are down, but at least one interface is up.
+	See also "ctdb ifaces".
+        </p></div><div class="refsect3" title="generation"><a name="id548592"></a><h4>generation</h4><p>
+          The generation id is a number that indicates the current generation 
+          of a cluster instance. Each time a cluster goes through a 
+          reconfiguration or a recovery its generation id will be changed.
+	  </p><p>
+	  This number does not have any particular meaning other than to keep
+	  track of when a cluster has gone through a recovery. It is a random
+	  number that represents the current instance of a ctdb cluster
+	  and its databases.
+	  CTDBD uses this number internally to be able to tell when commands 
+	  to operate on the cluster and the databases was issued in a different
+	  generation of the cluster, to ensure that commands that operate
+	  on the databases will not survive across a cluster database recovery.
+	  After a recovery, all old outstanding commands will automatically
+	  become invalid. 
+        </p><p>
+	  Sometimes this number will be shown as "INVALID". This only means that
+	  the ctdbd daemon has started but it has not yet merged with the cluster through a recovery.
+	  All nodes start with generation "INVALID" and are not assigned a real
+	  generation id until they have successfully been merged with a cluster
+	  through a recovery.
+        </p></div><div class="refsect3" title="VNNMAP"><a name="id548617"></a><h4>VNNMAP</h4><p>
+          The list of Virtual Node Numbers. This is a list of all nodes that actively participates in the cluster and that share the workload of hosting the Clustered TDB database records.
+          Only nodes that are participating in the vnnmap can become lmaster or dmaster for a database record.
+        </p></div><div class="refsect3" title="Recovery mode"><a name="id548629"></a><h4>Recovery mode</h4><p>
+          This is the current recovery mode of the cluster. There are two possible modes:
+        </p><p>
+          NORMAL - The cluster is fully operational.
+        </p><p>
+          RECOVERY - The cluster databases have all been frozen, pausing all services while the cluster awaits a recovery process to complete. A recovery process should finish within seconds. If a cluster is stuck in the RECOVERY state this would indicate a cluster malfunction which needs to be investigated.
+        </p><p>
+	Once the recovery master detects an inconsistency, for example a node 
+	becomes disconnected/connected, the recovery daemon will trigger a 
+	cluster recovery process, where all databases are remerged across the
+	cluster. When this process starts, the recovery master will first
+	"freeze" all databases to prevent applications such as samba from 
+	accessing the databases and it will also mark the recovery mode as
+	RECOVERY.
+	</p><p>
+	When CTDBD starts up, it will start in RECOVERY mode.
+	Once the node has been merged into a cluster and all databases
+	have been recovered, the node mode will change into NORMAL mode
+	and the databases will be "thawed", allowing samba to access the
+	databases again.
+	</p></div><div class="refsect3" title="Recovery master"><a name="id548660"></a><h4>Recovery master</h4><p>
+          This is the cluster node that is currently designated as the recovery master. This node is responsible of monitoring the consistency of the cluster and to perform the actual recovery process when reqired.
+        </p><p>
+	Only one node at a time can be the designated recovery master. Which
+	node is designated the recovery master is decided by an election
+	process in the recovery daemons running on each node.
+        </p></div><p>
+	Example: ctdb status
+      </p><p>Example output:</p><pre class="screen">
+Number of nodes:4
+pnn:0 11.1.2.200       OK (THIS NODE)
+pnn:1 11.1.2.201       OK
+pnn:2 11.1.2.202       OK
+pnn:3 11.1.2.203       OK
+Generation:1362079228
+Size:4
+hash:0 lmaster:0
+hash:1 lmaster:1
+hash:2 lmaster:2
+hash:3 lmaster:3
+Recovery mode:NORMAL (0)
+Recovery master:0
+      </pre></div><div class="refsect2" title="recmaster"><a name="id548692"></a><h3>recmaster</h3><p>
+        This command shows the pnn of the node which is currently the recmaster.
+      </p></div><div class="refsect2" title="uptime"><a name="id548702"></a><h3>uptime</h3><p>
+        This command shows the uptime for the ctdb daemon. When the last recovery or ip-failover completed and how long it took. If the "duration" is shown as a negative number, this indicates that there is a recovery/failover in progress and it started that many seconds ago.
+      </p><p>
+	Example: ctdb uptime
+      </p><p>Example output:</p><pre class="screen">
+Current time of node          :                Thu Oct 29 10:38:54 2009
+Ctdbd start time              : (000 16:54:28) Wed Oct 28 17:44:26 2009
+Time of last recovery/failover: (000 16:53:31) Wed Oct 28 17:45:23 2009
+Duration of last recovery/failover: 2.248552 seconds
+      </pre></div><div class="refsect2" title="listnodes"><a name="id548728"></a><h3>listnodes</h3><p>
+        This command shows lists the ip addresses of all the nodes in the cluster.
+      </p><p>
+	Example: ctdb listnodes
+      </p><p>Example output:</p><pre class="screen">
+10.0.0.71
+10.0.0.72
+10.0.0.73
+10.0.0.74
+      </pre></div><div class="refsect2" title="ping"><a name="id548751"></a><h3>ping</h3><p>
+        This command will "ping" all CTDB daemons in the cluster to verify that they are processing commands correctly.
+      </p><p>
+	Example: ctdb ping
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+response from 0 time=0.000054 sec  (3 clients)
+response from 1 time=0.000144 sec  (2 clients)
+response from 2 time=0.000105 sec  (2 clients)
+response from 3 time=0.000114 sec  (2 clients)
+      </pre></div><div class="refsect2" title="ifaces"><a name="id548775"></a><h3>ifaces</h3><p>
+	This command will display the list of network interfaces, which could
+	host public addresses, along with their status.
+      </p><p>
+	Example: ctdb ifaces
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+Interfaces on node 0
+name:eth5 link:up references:2
+name:eth4 link:down references:0
+name:eth3 link:up references:1
+name:eth2 link:up references:1
+      </pre><p>
+	Example: ctdb ifaces -Y
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+:Name:LinkStatus:References:
+:eth5:1:2
+:eth4:0:0
+:eth3:1:1
+:eth2:1:1
+      </pre></div><div class="refsect2" title="setifacelink <iface> <status>"><a name="id548812"></a><h3>setifacelink <iface> <status></h3><p>
+	This command will set the status of a network interface.
+	The status needs to be "up" or "down". This is typically
+	used in the 10.interfaces script in the "monitor" event.
+      </p><p>
+	Example: ctdb setifacelink eth0 up
+      </p></div><div class="refsect2" title="ip"><a name="id548826"></a><h3>ip</h3><p>
+        This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip. By default this command will ONLY show those public addresses that are known to the node itself. To see the full list of all public ips across the cluster you must use "ctdb ip -n all".
+      </p><p>
+	Example: ctdb ip
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+Public IPs on node 0
+172.31.91.82 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
+172.31.91.83 node[0] active[eth3] available[eth2,eth3] configured[eth2,eth3]
+172.31.91.84 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
+172.31.91.85 node[0] active[eth2] available[eth2,eth3] configured[eth2,eth3]
+172.31.92.82 node[1] active[] available[eth5] configured[eth4,eth5]
+172.31.92.83 node[0] active[eth5] available[eth5] configured[eth4,eth5]
+172.31.92.84 node[1] active[] available[eth5] configured[eth4,eth5]
+172.31.92.85 node[0] active[eth5] available[eth5] configured[eth4,eth5]
+      </pre><p>
+	Example: ctdb ip -Y
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+:Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:
+:172.31.91.82:1::eth2,eth3:eth2,eth3:
+:172.31.91.83:0:eth3:eth2,eth3:eth2,eth3:
+:172.31.91.84:1::eth2,eth3:eth2,eth3:
+:172.31.91.85:0:eth2:eth2,eth3:eth2,eth3:
+:172.31.92.82:1::eth5:eth4,eth5:
+:172.31.92.83:0:eth5:eth5:eth4,eth5:
+:172.31.92.84:1::eth5:eth4,eth5:
+:172.31.92.85:0:eth5:eth5:eth4,eth5:
+      </pre></div><div class="refsect2" title="ipinfo <ip>"><a name="id505513"></a><h3>ipinfo <ip></h3><p>
+        This command will display details about the specified public addresses.
+      </p><p>
+	Example: ctdb ipinfo 172.31.92.85
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+Public IP[172.31.92.85] info on node 0
+IP:172.31.92.85
+CurrentNode:0
+NumInterfaces:2
+Interface[1]: Name:eth4 Link:down References:0
+Interface[2]: Name:eth5 Link:up References:2 (active)
+      </pre></div><div class="refsect2" title="scriptstatus"><a name="id505536"></a><h3>scriptstatus</h3><p>
+        This command displays which scripts where run in the previous monitoring cycle and the result of each script. If a script failed with an error, causing the node to become unhealthy, the output from that script is also shown.
+      </p><p>
+	Example: ctdb scriptstatus
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+7 scripts were executed last monitoring cycle
+00.ctdb              Status:OK    Duration:0.056 Tue Mar 24 18:56:57 2009
+10.interface         Status:OK    Duration:0.077 Tue Mar 24 18:56:57 2009
+11.natgw             Status:OK    Duration:0.039 Tue Mar 24 18:56:57 2009
+20.multipathd        Status:OK    Duration:0.038 Tue Mar 24 18:56:57 2009
+31.clamd             Status:DISABLED
+40.vsftpd            Status:OK    Duration:0.045 Tue Mar 24 18:56:57 2009
+41.httpd             Status:OK    Duration:0.039 Tue Mar 24 18:56:57 2009
+50.samba             Status:ERROR    Duration:0.082 Tue Mar 24 18:56:57 2009
+   OUTPUT:ERROR: Samba tcp port 445 is not responding
+      </pre></div><div class="refsect2" title="disablescript <script>"><a name="id505566"></a><h3>disablescript <script></h3><p>
+	This command is used to disable an eventscript.
+      </p><p>
+	This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'.
+      </p></div><div class="refsect2" title="enablescript <script>"><a name="id505578"></a><h3>enablescript <script></h3><p>
+	This command is used to enable an eventscript.
+      </p><p>
+	This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'.
+      </p></div><div class="refsect2" title="getvar <name>"><a name="id505592"></a><h3>getvar <name></h3><p>
+        Get the runtime value of a tuneable variable.
+      </p><p>
+	Example: ctdb getvar MaxRedirectCount
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+MaxRedirectCount    = 3
+      </pre></div><div class="refsect2" title="setvar <name> <value>"><a name="id505613"></a><h3>setvar <name> <value></h3><p>
+        Set the runtime value of a tuneable variable.
+      </p><p>
+	Example: ctdb setvar MaxRedirectCount 5
+      </p></div><div class="refsect2" title="listvars"><a name="id505625"></a><h3>listvars</h3><p>
+        List all tuneable variables.
+      </p><p>
+	Example: ctdb listvars
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+MaxRedirectCount    = 3
+SeqnumInterval      = 1000
+ControlTimeout      = 60
+TraverseTimeout     = 20
+KeepaliveInterval   = 5
+KeepaliveLimit      = 5
+RecoverTimeout      = 20
+RecoverInterval     = 1
+ElectionTimeout     = 3
+TakeoverTimeout     = 9
+MonitorInterval     = 15
+TickleUpdateInterval = 20
+EventScriptTimeout  = 30
+EventScriptTimeoutCount = 1
+EventScriptUnhealthyOnTimeout = 0
+RecoveryGracePeriod = 120
+RecoveryBanPeriod   = 300
+DatabaseHashSize    = 100001
+DatabaseMaxDead     = 5
+RerecoveryTimeout   = 10
+EnableBans          = 1
+DeterministicIPs    = 1
+ReclockPingPeriod   = 60
+NoIPFailback        = 0
+DisableIPFailover   = 0
+VerboseMemoryNames  = 0
+RecdPingTimeout     = 60
+RecdFailCount       = 10
+LogLatencyMs        = 0
+RecLockLatencyMs    = 1000
+RecoveryDropAllIPs  = 120
+VerifyRecoveryLock  = 1
+VacuumDefaultInterval = 10
+VacuumMaxRunTime    = 30
+RepackLimit         = 10000
+VacuumLimit         = 5000
+VacuumMinInterval   = 10
+VacuumMaxInterval   = 10
+VacuumFastPathCount = 60
+MaxQueueDropMsg     = 1000000
+UseStatusEvents     = 0
+AllowUnhealthyDBRead = 0
+StatHistoryInterval = 1
+DeferredAttachTO    = 120
+      </pre></div><div class="refsect2" title="lvsmaster"><a name="id505656"></a><h3>lvsmaster</h3><p>
+      This command shows which node is currently the LVSMASTER. The
+      LVSMASTER is the node in the cluster which drives the LVS system and
+      which receives all incoming traffic from clients.
+      </p><p>
+      LVS is the mode where the entire CTDB/Samba cluster uses a single
+      ip address for the entire cluster. In this mode all clients connect to
+      one specific node which will then multiplex/loadbalance the clients
+      evenly onto the other nodes in the cluster. This is an alternative to using
+      public ip addresses. See the manpage for ctdbd for more information
+      about LVS.
+      </p></div><div class="refsect2" title="lvs"><a name="id505674"></a><h3>lvs</h3><p>
+      This command shows which nodes in the cluster are currently active in the
+      LVS configuration. I.e. which nodes we are currently loadbalancing
+      the single ip address across.
+      </p><p>
+      LVS will by default only loadbalance across those nodes that are both
+      LVS capable and also HEALTHY. Except if all nodes are UNHEALTHY in which
+      case LVS will loadbalance across all UNHEALTHY nodes as well.
+      LVS will never use nodes that are DISCONNECTED, STOPPED, BANNED or
+      DISABLED.
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+2:10.0.0.13
+3:10.0.0.14
+      </pre></div><div class="refsect2" title="getcapabilities"><a name="id505700"></a><h3>getcapabilities</h3><p>
+      This command shows the capabilities of the current node.
+      Please see manpage for ctdbd for a full list of all capabilities and
+      more detailed description.
+      </p><p>
+      RECMASTER and LMASTER capabilities are primarily used when CTDBD
+      is used to create a cluster spanning across WAN links. In which case
+      ctdbd acts as a WAN accelerator.
+      </p><p>
+      LVS capabile means that the node is participating in LVS, a mode
+      where the entire CTDB cluster uses one single ip address for the
+      entire cluster instead of using public ip address failover.
+      This is an alternative to using a loadbalancing layer-4 switch.
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+RECMASTER: YES
+LMASTER: YES
+LVS: NO
+      </pre></div><div class="refsect2" title="statistics"><a name="id505730"></a><h3>statistics</h3><p>
+        Collect statistics from the CTDB daemon about how many calls it has served.
+      </p><p>
+	Example: ctdb statistics
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+CTDB version 1
+ num_clients                        3
+ frozen                             0
+ recovering                         0
+ client_packets_sent           360489
+ client_packets_recv           360466
+ node_packets_sent             480931
+ node_packets_recv             240120
+ keepalive_packets_sent             4
+ keepalive_packets_recv             3
+ node
+     req_call                       2
+     reply_call                     2
+     req_dmaster                    0
+     reply_dmaster                  0
+     reply_error                    0
+     req_message                   42
+     req_control               120408
+     reply_control             360439
+ client
+     req_call                       2
+     req_message                   24
+     req_control               360440
+ timeouts
+     call                           0
+     control                        0
+     traverse                       0
+ total_calls                        2
+ pending_calls                      0
+ lockwait_calls                     0
+ pending_lockwait_calls             0
+ memory_used                     5040
+ max_hop_count                      0
+ max_call_latency                   4.948321 sec
+ max_lockwait_latency               0.000000 sec
+      </pre></div><div class="refsect2" title="statisticsreset"><a name="id505763"></a><h3>statisticsreset</h3><p>
+        This command is used to clear all statistics counters in a node.
+      </p><p>
+	Example: ctdb statisticsreset
+      </p></div><div class="refsect2" title="getreclock"><a name="id505775"></a><h3>getreclock</h3><p>
+	This command is used to show the filename of the reclock file that is used.
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+Reclock file:/gpfs/.ctdb/shared
+      </pre></div><div class="refsect2" title="setreclock [filename]"><a name="id505794"></a><h3>setreclock [filename]</h3><p>
+	This command is used to modify, or clear, the file that is used as the reclock file at runtime. When this command is used, the reclock file checks are disabled. To re-enable the checks the administrator needs to activate the "VerifyRecoveryLock" tunable using "ctdb setvar".
+      </p><p>
+	If run with no parameter this will remove the reclock file completely. If run with a parameter the parameter specifies the new filename to use for the recovery lock.
+      </p><p>
+	This command only affects the runtime settings of a ctdb node and will be lost when ctdb is restarted. For persistent changes to the reclock file setting you must edit /etc/sysconfig/ctdb.
+      </p></div><div class="refsect2" title="getdebug"><a name="id505817"></a><h3>getdebug</h3><p>
+        Get the current debug level for the node. the debug level controls what information is written to the log file.
+      </p><p>
+	The debug levels are mapped to the corresponding syslog levels.
+	When a debug level is set, only those messages at that level and higher
+	levels will be printed.
+      </p><p>
+	The list of debug levels from highest to lowest are :
+      </p><p>
+	EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG
+      </p></div><div class="refsect2" title="setdebug <debuglevel>"><a name="id505838"></a><h3>setdebug <debuglevel></h3><p>
+        Set the debug level of a node. This controls what information will be logged.
+      </p><p>
+	The debuglevel is one of EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG
+      </p></div><div class="refsect2" title="getpid"><a name="id505851"></a><h3>getpid</h3><p>
+        This command will return the process id of the ctdb daemon.
+      </p></div><div class="refsect2" title="disable"><a name="id505860"></a><h3>disable</h3><p>
+        This command is used to administratively disable a node in the cluster.
+        A disabled node will still participate in the cluster and host
+        clustered TDB records but its public ip address has been taken over by
+        a different node and it no longer hosts any services.
+      </p></div><div class="refsect2" title="enable"><a name="id505871"></a><h3>enable</h3><p>
+        Re-enable a node that has been administratively disabled.
+      </p></div><div class="refsect2" title="stop"><a name="id505880"></a><h3>stop</h3><p>
+        This command is used to administratively STOP a node in the cluster.
+        A STOPPED node is connected to the cluster but will not host any
+	public ip addresse, nor does it participate in the VNNMAP.
+	The difference between a DISABLED node and a STOPPED node is that
+	a STOPPED node does not host any parts of the database which means
+	that a recovery is required to stop/continue nodes.
+      </p></div><div class="refsect2" title="continue"><a name="id505892"></a><h3>continue</h3><p>
+        Re-start a node that has been administratively stopped.
+      </p></div><div class="refsect2" title="addip <public_ip/mask> <iface>"><a name="id505901"></a><h3>addip <public_ip/mask> <iface></h3><p>
+	This command is used to add a new public ip to a node during runtime.
+	This allows public addresses to be added to a cluster without having
+	to restart the ctdb daemons.
+      </p><p>
+	Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read.
+ If you want this change to be permanent you must also update the public addresses file manually.
+      </p></div><div class="refsect2" title="delip <public_ip>"><a name="id505918"></a><h3>delip <public_ip></h3><p>
+	This command is used to remove a public ip from a node during runtime.
+	If this public ip is currently hosted by the node it being removed from, the ip will first be failed over to another node, if possible, before it is removed.
+      </p><p>
+	Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read.
+ If you want this change to be permanent you must also update the public addresses file manually.
+      </p></div><div class="refsect2" title="moveip <public_ip> <node>"><a name="id505934"></a><h3>moveip <public_ip> <node></h3><p>
+      This command can be used to manually fail a public ip address to a
+      specific node.
+      </p><p>
+      In order to manually override the "automatic" distribution of public 
+      ip addresses that ctdb normally provides, this command only works
+      when you have changed the tunables for the daemon to:
+      </p><p>
+      DeterministicIPs = 0
+      </p><p>
+      NoIPFailback = 1
+      </p></div><div class="refsect2" title="shutdown"><a name="id505956"></a><h3>shutdown</h3><p>
+        This command will shutdown a specific CTDB daemon.
+      </p></div><div class="refsect2" title="recover"><a name="id505965"></a><h3>recover</h3><p>
+        This command will trigger the recovery daemon to do a cluster
+        recovery.
+      </p></div><div class="refsect2" title="ipreallocate"><a name="id505975"></a><h3>ipreallocate</h3><p>
+        This command will force the recovery master to perform a full ip reallocation process and redistribute all ip addresses. This is useful to "reset" the allocations back to its default state if they have been changed using the "moveip" command. While a "recover" will also perform this reallocation, a recovery is much more hevyweight since it will also rebuild all the databases.
+      </p></div><div class="refsect2" title="setlmasterrole <on|off>"><a name="id505987"></a><h3>setlmasterrole <on|off></h3><p>
+	This command is used ot enable/disable the LMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an LMASTER for records in the database. A node that does not have the LMASTER capability will not show up in the vnnmap.
+      </p><p>
+	Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command.
+      </p><p>
+	Once this setting has been enabled/disabled, you need to perform a recovery for it to take effect.
+      </p><p>
+	See also "ctdb getcapabilities"
+      </p></div><div class="refsect2" title="setrecmasterrole <on|off>"><a name="id506010"></a><h3>setrecmasterrole <on|off></h3><p>
+	This command is used ot enable/disable the RECMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an RECMASTER for the cluster. A node that does not have the RECMASTER capability can not win a recmaster election. A node that already is the recmaster for the cluster when the capability is stripped off the node will remain the recmaster until the next cluster election.
+      </p><p>
+	Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command.
+      </p><p>
+	See also "ctdb getcapabilities"
+      </p></div><div class="refsect2" title="killtcp <srcip:port> <dstip:port>"><a name="id506031"></a><h3>killtcp <srcip:port> <dstip:port></h3><p>
+        This command will kill the specified TCP connection by issuing a
+        TCP RST to the srcip:port endpoint. This is a command used by the 
+	ctdb eventscripts.
+      </p></div><div class="refsect2" title="gratiousarp <ip> <interface>"><a name="id506042"></a><h3>gratiousarp <ip> <interface></h3><p>
+	This command will send out a gratious arp for the specified interface
+	through the specified interface. This command is mainly used by the
+	ctdb eventscripts.
+      </p></div><div class="refsect2" title="reloadnodes"><a name="id506052"></a><h3>reloadnodes</h3><p>
+      This command is used when adding new nodes, or removing existing nodes from an existing cluster.
+      </p><p>
+      Procedure to add a node:
+      </p><p>
+      1, To expand an existing cluster, first ensure with 'ctdb status' that
+      all nodes are up and running and that they are all healthy.
+      Do not try to expand a cluster unless it is completely healthy!
+      </p><p>
+      2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last
+      entry to the file. The new node MUST be added to the end of this file!
+      </p><p>
+      3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node!
+      </p><p>
+      4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.
+      </p><p>
+      5, Use 'ctdb status' on all nodes and verify that they now show the additional node.
+      </p><p>
+      6, Install and configure the new node and bring it online.
+      </p><p>
+      Procedure to remove a node:
+      </p><p>
+      1, To remove a node from an existing cluster, first ensure with 'ctdb status' that
+      all nodes, except the node to be deleted, are up and running and that they are all healthy.
+      Do not try to remove a node from a cluster unless the cluster is completely healthy!
+      </p><p>
+      2, Shutdown and poweroff the node to be removed.
+      </p><p>
+      3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed. Do not delete the line for that node, just comment it out by adding a '#' at the beginning of the line.
+      </p><p>
+      4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.
+      </p><p>
+      5, Use 'ctdb status' on all nodes and verify that the deleted node no longer shows up in the list..
+      </p><p>
+      </p></div><div class="refsect2" title="tickle <srcip:port> <dstip:port>"><a name="id549687"></a><h3>tickle <srcip:port> <dstip:port></h3><p>
+        This command will will send a TCP tickle to the source host for the
+        specified TCP connection.
+	A TCP tickle is a TCP ACK packet with an invalid sequence and 
+	acknowledge number and will when received by the source host result
+        in it sending an immediate correct ACK back to the other end.
+      </p><p>
+        TCP tickles are useful to "tickle" clients after a IP failover has 
+        occured since this will make the client immediately recognize the 
+        TCP connection has been disrupted and that the client will need
+        to reestablish. This greatly speeds up the time it takes for a client
+        to detect and reestablish after an IP failover in the ctdb cluster.
+      </p></div><div class="refsect2" title="gettickles <ip>"><a name="id549705"></a><h3>gettickles <ip></h3><p>
+	This command is used to show which TCP connections are registered with
+	CTDB to be "tickled" if there is a failover.
+      </p></div><div class="refsect2" title="repack [max_freelist]"><a name="id549715"></a><h3>repack [max_freelist]</h3><p>
+	Over time, when records are created and deleted in a TDB, the TDB list of free space will become fragmented. This can lead to a slowdown in accessing TDB records.
+	This command is used to defragment a TDB database and pruning the freelist.
+      </p><p>
+	If [max_freelist] is specified, then a database will only be repacked if it has more than this number of entries in the freelist.
+	</p><p>
+	During repacking of the database, the entire TDB database will be locked to prevent writes. If samba tries to write to a record in the database during a repack operation, samba will block until the repacking has completed.
+      </p><p>
+	This command can be disruptive and can cause samba to block for the duration of the repack operation. In general, a repack operation will take less than one second to complete.
+      </p><p>
+	A repack operation will only defragment the local TDB copy of the CTDB database. You need to run this command on all of the nodes to repack a CTDB database completely.
+	</p><p>
+	Example: ctdb repack 1000
+      </p><p>
+	 By default, this operation is issued from the 00.ctdb event script every 5 minutes.
+      </p></div><div class="refsect2" title="vacuum [max_records]"><a name="id549752"></a><h3>vacuum [max_records]</h3><p>
+	Over time CTDB databases will fill up with empty deleted records which will lead to a progressive slow down of CTDB database access.
+	This command is used to prune all databases and delete all empty records from the cluster.
+      </p><p>
+	 By default, vacuum will delete all empty records from all databases.
+	 If [max_records] is specified, the command will only delete the first
+	 [max_records] empty records for each database.
+      </p><p>
+	 Vacuum only deletes records where the local node is the lmaster.
+	 To delete all records from the entire cluster you need to run a vacuum from each node.
+
+	 This command is not disruptive. Samba is unaffected and will still be able to read/write records normally while the database is being vacuumed.
+      </p><p>
+	Example: ctdb vacuum
+      </p><p>
+	 By default, this operation is issued from the 00.ctdb event script every 5 minutes.
+      </p></div><div class="refsect2" title="backupdb <dbname> <file>"><a name="id549781"></a><h3>backupdb <dbname> <file></h3><p>
+        This command can be used to copy the entire content of a database out to a file. This file can later be read back into ctdb using the restoredb command.
+This is mainly useful for backing up persistent databases such as secrets.tdb and similar.
+      </p></div><div class="refsect2" title="restoredb <file> [<dbname>]"><a name="id549792"></a><h3>restoredb <file> [<dbname>]</h3><p>
+        This command restores a persistent database that was previously backed up using backupdb.
+	By default the data will be restored back into the same database as
+	it was created from. By specifying dbname you can restore the data
+	into a different database.
+      </p></div><div class="refsect2" title="wipedb <dbname>"><a name="id549803"></a><h3>wipedb <dbname></h3><p>
+        This command can be used to remove all content of a database.
+      </p></div></div><div class="refsect2" title="getlog <level>"><a name="id549813"></a><h3>getlog <level></h3><p>
+	In addition to the normal loggign to a log file,
+	CTDBD also keeps a in-memory ringbuffer containing the most recent
+	log entries for all log levels (except DEBUG).
+      </p><p>
+	This is useful since it allows for keeping continuous logs to a file
+	at a reasonable non-verbose level, but shortly after an incident has
+	occured, a much more detailed log can be pulled from memory. This
+	can allow you to avoid having to reproduce an issue due to the
+	on-disk logs being of insufficient detail.
+      </p><p>
+	This command extracts all messages of level or lower log level from
+	memory and prints it to the screen.
+      </p></div><div class="refsect2" title="clearlog"><a name="id549831"></a><h3>clearlog</h3><p>
+	This command clears the in-memory logging ringbuffer.
+      </p></div><div class="refsect1" title="Debugging Commands"><a name="id549839"></a><h2>Debugging Commands</h2><p>
+      These commands are primarily used for CTDB development and testing and
+      should not be used for normal administration.
+    </p><div class="refsect2" title="process-exists <pid>"><a name="id549848"></a><h3>process-exists <pid></h3><p>
+        This command checks if a specific process exists on the CTDB host. This is mainly used by Samba to check if remote instances of samba are still running or not.
+      </p></div><div class="refsect2" title="getdbmap"><a name="id549858"></a><h3>getdbmap</h3><p>
+        This command lists all clustered TDB databases that the CTDB daemon has attached to. Some databases are flagged as PERSISTENT, this means that the database stores data persistently and the data will remain across reboots. One example of such a database is secrets.tdb where information about how the cluster was joined to the domain is stored.
+      </p><p>
+	If a PERSISTENT database is not in a healthy state the database is
+	flagged as UNHEALTHY. If there's at least one completely healthy node running in
+	the cluster, it's possible that the content is restored by a recovery
+	run automaticly. Otherwise an administrator needs to analyze the
+	problem.
+      </p><p>
+	See also "ctdb getdbstatus", "ctdb backupdb", "ctdb restoredb",
+	"ctdb dumpbackup", "ctdb wipedb", "ctdb setvar AllowUnhealthyDBRead 1"
+	and (if samba or tdb-utils are installed) "tdbtool check".
+	</p><p>
+	Most databases are not persistent and only store the state information that the currently running samba daemons need. These databases are always wiped when ctdb/samba starts and when a node is rebooted.
+      </p><p>
+	Example: ctdb getdbmap
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+Number of databases:10
+dbid:0x435d3410 name:notify.tdb path:/var/ctdb/notify.tdb.0 
+dbid:0x42fe72c5 name:locking.tdb path:/var/ctdb/locking.tdb.0
+dbid:0x1421fb78 name:brlock.tdb path:/var/ctdb/brlock.tdb.0 
+dbid:0x17055d90 name:connections.tdb path:/var/ctdb/connections.tdb.0 
+dbid:0xc0bdde6a name:sessionid.tdb path:/var/ctdb/sessionid.tdb.0 
+dbid:0x122224da name:test.tdb path:/var/ctdb/test.tdb.0 
+dbid:0x2672a57f name:idmap2.tdb path:/var/ctdb/persistent/idmap2.tdb.0 PERSISTENT
+dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT
+dbid:0xe98e08b6 name:group_mapping.tdb path:/var/ctdb/persistent/group_mapping.tdb.0 PERSISTENT
+dbid:0x7bbbd26c name:passdb.tdb path:/var/ctdb/persistent/passdb.tdb.0 PERSISTENT
+      </pre><p>
+	Example output for an unhealthy database:
+      </p><pre class="screen">
+Number of databases:1
+dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT UNHEALTHY
+      </pre><p>
+	Example output for a healthy database as machinereadable output -Y:
+      </p><pre class="screen">
+:ID:Name:Path:Persistent:Unhealthy:
+:0x7bbbd26c:passdb.tdb:/var/ctdb/persistent/passdb.tdb.0:1:0:
+      </pre></div><div class="refsect2" title="getdbstatus <dbname>"><a name="id549923"></a><h3>getdbstatus <dbname></h3><p>
+	This command displays more details about a database.
+      </p><p>
+	Example: ctdb getdbstatus test.tdb.0
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+dbid: 0x122224da
+name: test.tdb
+path: /var/ctdb/test.tdb.0
+PERSISTENT: no
+HEALTH: OK
+      </pre><p>
+	Example: ctdb getdbstatus registry.tdb (with a corrupted TDB)
+      </p><p>
+	Example output:
+      </p><pre class="screen">
+dbid: 0xf2a58948
+name: registry.tdb
+path: /var/ctdb/persistent/registry.tdb.0
+PERSISTENT: yes
+HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persistent/registry.tdb.0.corrupted.20091208091949.0Z'
+      </pre></div><div class="refsect2" title="catdb <dbname>"><a name="id549957"></a><h3>catdb <dbname></h3><p>
+        This command will dump a clustered TDB database to the screen. This is a debugging command.
+      </p></div><div class="refsect2" title="cattdb <dbname>"><a name="id549967"></a><h3>cattdb <dbname></h3><p>
+        This command will dump the content of the local TDB database to the screen. This is a debugging command.
+      </p></div><div class="refsect2" title="dumpdbbackup <backup-file>"><a name="id549977"></a><h3>dumpdbbackup <backup-file></h3><p>
+	This command will dump the content of database backup to the screen
+	(similar to ctdb catdb). This is a debugging command.
+      </p></div><div class="refsect2" title="getmonmode"><a name="id549986"></a><h3>getmonmode</h3><p>
+        This command returns the monutoring mode of a node. The monitoring mode is either ACTIVE or DISABLED. Normally a node will continuously monitor that all other nodes that are expected are in fact connected and that they respond to commands.
+      </p><p>
+        ACTIVE - This is the normal mode. The node is actively monitoring all other nodes, both that the transport is connected and also that the node responds to commands. If a node becomes unavailable, it will be marked as DISCONNECTED and a recovery is initiated to restore the cluster.
+      </p><p>
+        DISABLED - This node is not monitoring that other nodes are available. In this mode a node failure will not be detected and no recovery will be performed. This mode is useful when for debugging purposes one wants to attach GDB to a ctdb process but wants to prevent the rest of the cluster from marking this node as DISCONNECTED and do a recovery.
+      </p></div><div class="refsect2" title="setmonmode <0|1>"><a name="id550010"></a><h3>setmonmode <0|1></h3><p>
+        This command can be used to explicitly disable/enable monitoring mode on a node. The main purpose is if one wants to attach GDB to a running ctdb daemon but wants to prevent the other nodes from marking it as DISCONNECTED and issuing a recovery. To do this, set monitoring mode to 0 on all nodes before attaching with GDB. Remember to set monitoring mode back to 1 afterwards.
+      </p></div><div class="refsect2" title="attach <dbname> [persistent]"><a name="id550022"></a><h3>attach <dbname> [persistent]</h3><p>
+        This is a debugging command. This command will make the CTDB daemon create a new CTDB database and attach to it.
+      </p></div><div class="refsect2" title="dumpmemory"><a name="id550031"></a><h3>dumpmemory</h3><p>
+        This is a debugging command. This command will make the ctdb
+        daemon to write a fill memory allocation map to standard output.
+      </p></div><div class="refsect2" title="rddumpmemory"><a name="id550041"></a><h3>rddumpmemory</h3><p>
+        This is a debugging command. This command will dump the talloc memory
+	allocation tree for the recovery daemon to standard output.
+      </p></div><div class="refsect2" title="thaw"><a name="id550051"></a><h3>thaw</h3><p>
+        Thaw a previously frozen node.
+      </p></div><div class="refsect2" title="eventscript <arguments>"><a name="id550060"></a><h3>eventscript <arguments></h3><p>
+        This is a debugging command. This command can be used to manually
+	invoke and run the eventscritps with arbitrary arguments.
+      </p></div><div class="refsect2" title="ban <bantime|0>"><a name="id550069"></a><h3>ban <bantime|0></h3><p>
+        Administratively ban a node for bantime seconds. A bantime of 0 means that the node should be permanently banned. 
+      </p><p>
+        A banned node does not participate in the cluster and does not host any records for the clustered TDB. Its ip address has been taken over by another node and no services are hosted.
+      </p><p>
+        Nodes are automatically banned if they are the cause of too many
+        cluster recoveries.
+      </p><p>
+	This is primarily a testing command. Note that the recovery daemon controls the overall ban state and it may automatically unban nodes at will. Meaning that a node that has been banned by the administrator can and ofter are unbanned before the admin specifid timeout triggers. If wanting to "drop" a node out from the cluster for mainentance or other reasons, use the "stop" / "continue" commands instad of "ban" / "unban". 
+      </p></div><div class="refsect2" title="unban"><a name="id550095"></a><h3>unban</h3><p>
+        This command is used to unban a node that has either been 
+        administratively banned using the ban command or has been automatically
+        banned by the recovery daemon.
+      </p></div></div><div class="refsect1" title="SEE ALSO"><a name="id550107"></a><h2>SEE ALSO</h2><p>
+      ctdbd(1), onnode(1)
+      <a class="ulink" href="http://ctdb.samba.org/" target="_top">http://ctdb.samba.org/</a>
+    </p></div><div class="refsect1" title="COPYRIGHT/LICENSE"><a name="id550119"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
+Copyright (C) Andrew Tridgell 2007<br>
+Copyright (C) Ronnie sahlberg 2007<br>
+<br>
+This program is free software; you can redistribute it and/or modify<br>
+it under the terms of the GNU General Public License as published by<br>
+the Free Software Foundation; either version 3 of the License, or (at<br>
+your option) any later version.<br>
+<br>
+This program is distributed in the hope that it will be useful, but<br>
+WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
+General Public License for more details.<br>
+<br>
+You should have received a copy of the GNU General Public License<br>
+along with this program; if not, see http://www.gnu.org/licenses/.<br>
+</p></div></div></div></body></html>

Added: branches/ctdb/squeeze-backports/doc/ctdb.1.xml
===================================================================
--- branches/ctdb/squeeze-backports/doc/ctdb.1.xml	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ctdb.1.xml	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1295 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="ctdb.1">
+
+<refmeta>
+	<refentrytitle>ctdb</refentrytitle>
+	<manvolnum>1</manvolnum>
+	<refmiscinfo class="source">ctdb</refmiscinfo>
+	<refmiscinfo class="manual">CTDB - clustered TDB database</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+	<refname>ctdb</refname>
+        <refpurpose>clustered tdb database management utility</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+	<cmdsynopsis>
+		<command>ctdb [ OPTIONS ] COMMAND ...</command>
+	</cmdsynopsis>
+	
+	<cmdsynopsis>
+		<command>ctdb</command>
+		<arg choice="opt">-n <node></arg>
+		<arg choice="opt">-Y</arg>
+		<arg choice="opt">-t <timeout></arg>
+		<arg choice="opt">-T <timelimit></arg>
+		<arg choice="opt">-? --help</arg>
+		<arg choice="opt">--usage</arg>
+		<arg choice="opt">-d --debug=<INTEGER></arg>
+		<arg choice="opt">--socket=<filename></arg>
+	</cmdsynopsis>
+	
+</refsynopsisdiv>
+
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      ctdb is a utility to view and manage a ctdb cluster.
+    </para>
+  </refsect1>
+
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist>
+      <varlistentry><term>-n <pnn></term>
+        <listitem>
+          <para>
+            This specifies the physical node number on which to execute the 
+	    command. Default is to run the command on the daemon running on 
+	    the local host.
+	  </para>
+	  <para>
+	    The physical node number is an integer that describes the node in the
+	    cluster. The first node has physical node number 0.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-Y</term>
+        <listitem>
+          <para>
+            Produce output in machine readable form for easier parsing by scripts. Not all commands support this option.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-t <timeout></term>
+        <listitem>
+          <para>
+            How long should ctdb wait for the local ctdb daemon to respond to a command before timing out. Default is 3 seconds.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-T <timelimit></term>
+        <listitem>
+          <para>
+            A limit on how long the ctdb command will run for before it will
+	    be aborted. When this timelimit has been exceeded the ctdb command will
+	    terminate.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-? --help</term>
+        <listitem>
+          <para>
+            Print some help text to the screen.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--usage</term>
+        <listitem>
+          <para>
+            Print useage information to the screen.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-d --debug=<debuglevel></term>
+        <listitem>
+          <para>
+            Change the debug level for the command. Default is 0.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--socket=<filename></term>
+        <listitem>
+          <para>
+            Specify the socketname to use when connecting to the local ctdb 
+            daemon. The default is /tmp/ctdb.socket .
+          </para>
+          <para>
+            You only need to specify this parameter if you run multiple ctdb 
+            daemons on the same physical host and thus can not use the default
+            name for the domain socket.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+
+  <refsect1><title>Administrative Commands</title>
+    <para>
+      These are commands used to monitor and administrate a CTDB cluster.
+    </para>
+
+    <refsect2><title>pnn</title>
+      <para>
+        This command displays the pnn of the current node.
+      </para>
+    </refsect2>
+
+    <refsect2><title>status</title>
+      <para>
+        This command shows the current status of the ctdb node.
+      </para>
+
+      <refsect3><title>node status</title>
+        <para>
+          Node status reflects the current status of the node. There are five possible states:
+        </para>
+        <para>
+          OK - This node is fully functional.
+        </para>
+        <para>
+          DISCONNECTED - This node could not be connected through the network and is currently not participating in the cluster. If there is a public IP address associated with this node it should have been taken over by a different node. No services are running on this node.
+        </para>
+        <para>
+          DISABLED - This node has been administratively disabled. This node is still functional and participates in the CTDB cluster but its IP addresses have been taken over by a different node and no services are currently being hosted.
+        </para>
+        <para>
+          UNHEALTHY - A service provided by this node is malfunctioning and should be investigated. The CTDB daemon itself is operational and participates in the cluster. Its public IP address has been taken over by a different node and no services are currnetly being hosted. All unhealthy nodes should be investigated and require an administrative action to rectify.
+        </para>
+        <para>
+          BANNED - This node failed too many recovery attempts and has been banned from participating in the cluster for a period of RecoveryBanPeriod seconds. Any public IP address has been taken over by other nodes. This node does not provide any services. All banned nodes should be investigated and require an administrative action to rectify. This node does not perticipate in the CTDB cluster but can still be communicated with. I.e. ctdb commands can be sent to it.
+        </para>
+        <para>
+      STOPPED - A node that is stopped does not host any public ip addresses,
+      nor is it part of the VNNMAP. A stopped node can not become LVSMASTER,
+      RECMASTER or NATGW.
+      This node does not perticipate in the CTDB cluster but can still be
+      communicated with. I.e. ctdb commands can be sent to it.
+        </para>
+        <para>
+	PARTIALLYONLINE - A node that is partially online participates
+	in a cluster like a node that is ok. Some interfaces to serve
+	public ip addresses are down, but at least one interface is up.
+	See also "ctdb ifaces".
+        </para>
+      </refsect3>
+
+      <refsect3><title>generation</title>
+        <para>
+          The generation id is a number that indicates the current generation 
+          of a cluster instance. Each time a cluster goes through a 
+          reconfiguration or a recovery its generation id will be changed.
+	  </para>
+	  <para>
+	  This number does not have any particular meaning other than to keep
+	  track of when a cluster has gone through a recovery. It is a random
+	  number that represents the current instance of a ctdb cluster
+	  and its databases.
+	  CTDBD uses this number internally to be able to tell when commands 
+	  to operate on the cluster and the databases was issued in a different
+	  generation of the cluster, to ensure that commands that operate
+	  on the databases will not survive across a cluster database recovery.
+	  After a recovery, all old outstanding commands will automatically
+	  become invalid. 
+        </para>
+        <para>
+	  Sometimes this number will be shown as "INVALID". This only means that
+	  the ctdbd daemon has started but it has not yet merged with the cluster through a recovery.
+	  All nodes start with generation "INVALID" and are not assigned a real
+	  generation id until they have successfully been merged with a cluster
+	  through a recovery.
+        </para>
+      </refsect3>
+
+      <refsect3><title>VNNMAP</title>
+        <para>
+          The list of Virtual Node Numbers. This is a list of all nodes that actively participates in the cluster and that share the workload of hosting the Clustered TDB database records.
+          Only nodes that are participating in the vnnmap can become lmaster or dmaster for a database record.
+        </para>
+      </refsect3>
+
+      <refsect3><title>Recovery mode</title>
+        <para>
+          This is the current recovery mode of the cluster. There are two possible modes:
+        </para>
+        <para>
+          NORMAL - The cluster is fully operational.
+        </para>
+        <para>
+          RECOVERY - The cluster databases have all been frozen, pausing all services while the cluster awaits a recovery process to complete. A recovery process should finish within seconds. If a cluster is stuck in the RECOVERY state this would indicate a cluster malfunction which needs to be investigated.
+        </para>
+	<para>
+	Once the recovery master detects an inconsistency, for example a node 
+	becomes disconnected/connected, the recovery daemon will trigger a 
+	cluster recovery process, where all databases are remerged across the
+	cluster. When this process starts, the recovery master will first
+	"freeze" all databases to prevent applications such as samba from 
+	accessing the databases and it will also mark the recovery mode as
+	RECOVERY.
+	</para>
+	<para>
+	When CTDBD starts up, it will start in RECOVERY mode.
+	Once the node has been merged into a cluster and all databases
+	have been recovered, the node mode will change into NORMAL mode
+	and the databases will be "thawed", allowing samba to access the
+	databases again.
+	</para>
+      </refsect3>
+
+      <refsect3><title>Recovery master</title>
+        <para>
+          This is the cluster node that is currently designated as the recovery master. This node is responsible of monitoring the consistency of the cluster and to perform the actual recovery process when reqired.
+        </para>
+        <para>
+	Only one node at a time can be the designated recovery master. Which
+	node is designated the recovery master is decided by an election
+	process in the recovery daemons running on each node.
+        </para>
+      </refsect3>
+
+      <para>
+	Example: ctdb status
+      </para>
+      <para>Example output:</para>
+      <screen format="linespecific">
+Number of nodes:4
+pnn:0 11.1.2.200       OK (THIS NODE)
+pnn:1 11.1.2.201       OK
+pnn:2 11.1.2.202       OK
+pnn:3 11.1.2.203       OK
+Generation:1362079228
+Size:4
+hash:0 lmaster:0
+hash:1 lmaster:1
+hash:2 lmaster:2
+hash:3 lmaster:3
+Recovery mode:NORMAL (0)
+Recovery master:0
+      </screen>
+    </refsect2>
+
+    <refsect2><title>recmaster</title>
+      <para>
+        This command shows the pnn of the node which is currently the recmaster.
+      </para>
+    </refsect2>
+
+    <refsect2><title>uptime</title>
+      <para>
+        This command shows the uptime for the ctdb daemon. When the last recovery or ip-failover completed and how long it took. If the "duration" is shown as a negative number, this indicates that there is a recovery/failover in progress and it started that many seconds ago.
+      </para>
+
+      <para>
+	Example: ctdb uptime
+      </para>
+      <para>Example output:</para>
+      <screen format="linespecific">
+Current time of node          :                Thu Oct 29 10:38:54 2009
+Ctdbd start time              : (000 16:54:28) Wed Oct 28 17:44:26 2009
+Time of last recovery/failover: (000 16:53:31) Wed Oct 28 17:45:23 2009
+Duration of last recovery/failover: 2.248552 seconds
+      </screen>
+    </refsect2>
+
+    <refsect2><title>listnodes</title>
+      <para>
+        This command shows lists the ip addresses of all the nodes in the cluster.
+      </para>
+
+      <para>
+	Example: ctdb listnodes
+      </para>
+      <para>Example output:</para>
+      <screen format="linespecific">
+10.0.0.71
+10.0.0.72
+10.0.0.73
+10.0.0.74
+      </screen>
+    </refsect2>
+
+    <refsect2><title>ping</title>
+      <para>
+        This command will "ping" all CTDB daemons in the cluster to verify that they are processing commands correctly.
+      </para>
+      <para>
+	Example: ctdb ping
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+response from 0 time=0.000054 sec  (3 clients)
+response from 1 time=0.000144 sec  (2 clients)
+response from 2 time=0.000105 sec  (2 clients)
+response from 3 time=0.000114 sec  (2 clients)
+      </screen>
+    </refsect2>
+
+    <refsect2><title>ifaces</title>
+      <para>
+	This command will display the list of network interfaces, which could
+	host public addresses, along with their status.
+      </para>
+      <para>
+	Example: ctdb ifaces
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+Interfaces on node 0
+name:eth5 link:up references:2
+name:eth4 link:down references:0
+name:eth3 link:up references:1
+name:eth2 link:up references:1
+      </screen>
+      <para>
+	Example: ctdb ifaces -Y
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+:Name:LinkStatus:References:
+:eth5:1:2
+:eth4:0:0
+:eth3:1:1
+:eth2:1:1
+      </screen>
+    </refsect2>
+
+    <refsect2><title>setifacelink <iface> <status></title>
+      <para>
+	This command will set the status of a network interface.
+	The status needs to be "up" or "down". This is typically
+	used in the 10.interfaces script in the "monitor" event.
+      </para>
+      <para>
+	Example: ctdb setifacelink eth0 up
+      </para>
+    </refsect2>
+
+    <refsect2><title>ip</title>
+      <para>
+        This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip. By default this command will ONLY show those public addresses that are known to the node itself. To see the full list of all public ips across the cluster you must use "ctdb ip -n all".
+      </para>
+      <para>
+	Example: ctdb ip
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+Public IPs on node 0
+172.31.91.82 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
+172.31.91.83 node[0] active[eth3] available[eth2,eth3] configured[eth2,eth3]
+172.31.91.84 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
+172.31.91.85 node[0] active[eth2] available[eth2,eth3] configured[eth2,eth3]
+172.31.92.82 node[1] active[] available[eth5] configured[eth4,eth5]
+172.31.92.83 node[0] active[eth5] available[eth5] configured[eth4,eth5]
+172.31.92.84 node[1] active[] available[eth5] configured[eth4,eth5]
+172.31.92.85 node[0] active[eth5] available[eth5] configured[eth4,eth5]
+      </screen>
+      <para>
+	Example: ctdb ip -Y
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+:Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:
+:172.31.91.82:1::eth2,eth3:eth2,eth3:
+:172.31.91.83:0:eth3:eth2,eth3:eth2,eth3:
+:172.31.91.84:1::eth2,eth3:eth2,eth3:
+:172.31.91.85:0:eth2:eth2,eth3:eth2,eth3:
+:172.31.92.82:1::eth5:eth4,eth5:
+:172.31.92.83:0:eth5:eth5:eth4,eth5:
+:172.31.92.84:1::eth5:eth4,eth5:
+:172.31.92.85:0:eth5:eth5:eth4,eth5:
+      </screen>
+    </refsect2>
+
+    <refsect2><title>ipinfo <ip></title>
+      <para>
+        This command will display details about the specified public addresses.
+      </para>
+      <para>
+	Example: ctdb ipinfo 172.31.92.85
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+Public IP[172.31.92.85] info on node 0
+IP:172.31.92.85
+CurrentNode:0
+NumInterfaces:2
+Interface[1]: Name:eth4 Link:down References:0
+Interface[2]: Name:eth5 Link:up References:2 (active)
+      </screen>
+    </refsect2>
+
+    <refsect2><title>scriptstatus</title>
+      <para>
+        This command displays which scripts where run in the previous monitoring cycle and the result of each script. If a script failed with an error, causing the node to become unhealthy, the output from that script is also shown.
+      </para>
+      <para>
+	Example: ctdb scriptstatus
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+7 scripts were executed last monitoring cycle
+00.ctdb              Status:OK    Duration:0.056 Tue Mar 24 18:56:57 2009
+10.interface         Status:OK    Duration:0.077 Tue Mar 24 18:56:57 2009
+11.natgw             Status:OK    Duration:0.039 Tue Mar 24 18:56:57 2009
+20.multipathd        Status:OK    Duration:0.038 Tue Mar 24 18:56:57 2009
+31.clamd             Status:DISABLED
+40.vsftpd            Status:OK    Duration:0.045 Tue Mar 24 18:56:57 2009
+41.httpd             Status:OK    Duration:0.039 Tue Mar 24 18:56:57 2009
+50.samba             Status:ERROR    Duration:0.082 Tue Mar 24 18:56:57 2009
+   OUTPUT:ERROR: Samba tcp port 445 is not responding
+      </screen>
+    </refsect2>
+
+    <refsect2><title>disablescript <script></title>
+      <para>
+	This command is used to disable an eventscript.
+      </para>
+      <para>
+	This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'.
+      </para>
+    </refsect2>
+
+    <refsect2><title>enablescript <script></title>
+      <para>
+	This command is used to enable an eventscript.
+      </para>
+      <para>
+	This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'.
+      </para>
+    </refsect2>
+
+    <refsect2><title>getvar <name></title>
+      <para>
+        Get the runtime value of a tuneable variable.
+      </para>
+      <para>
+	Example: ctdb getvar MaxRedirectCount
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+MaxRedirectCount    = 3
+      </screen>
+    </refsect2>
+
+    <refsect2><title>setvar <name> <value></title>
+      <para>
+        Set the runtime value of a tuneable variable.
+      </para>
+      <para>
+	Example: ctdb setvar MaxRedirectCount 5
+      </para>
+    </refsect2>
+
+    <refsect2><title>listvars</title>
+      <para>
+        List all tuneable variables.
+      </para>
+      <para>
+	Example: ctdb listvars
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+MaxRedirectCount    = 3
+SeqnumInterval      = 1000
+ControlTimeout      = 60
+TraverseTimeout     = 20
+KeepaliveInterval   = 5
+KeepaliveLimit      = 5
+RecoverTimeout      = 20
+RecoverInterval     = 1
+ElectionTimeout     = 3
+TakeoverTimeout     = 9
+MonitorInterval     = 15
+TickleUpdateInterval = 20
+EventScriptTimeout  = 30
+EventScriptTimeoutCount = 1
+EventScriptUnhealthyOnTimeout = 0
+RecoveryGracePeriod = 120
+RecoveryBanPeriod   = 300
+DatabaseHashSize    = 100001
+DatabaseMaxDead     = 5
+RerecoveryTimeout   = 10
+EnableBans          = 1
+DeterministicIPs    = 1
+ReclockPingPeriod   = 60
+NoIPFailback        = 0
+DisableIPFailover   = 0
+VerboseMemoryNames  = 0
+RecdPingTimeout     = 60
+RecdFailCount       = 10
+LogLatencyMs        = 0
+RecLockLatencyMs    = 1000
+RecoveryDropAllIPs  = 120
+VerifyRecoveryLock  = 1
+VacuumDefaultInterval = 10
+VacuumMaxRunTime    = 30
+RepackLimit         = 10000
+VacuumLimit         = 5000
+VacuumMinInterval   = 10
+VacuumMaxInterval   = 10
+VacuumFastPathCount = 60
+MaxQueueDropMsg     = 1000000
+UseStatusEvents     = 0
+AllowUnhealthyDBRead = 0
+StatHistoryInterval = 1
+DeferredAttachTO    = 120
+      </screen>
+    </refsect2>
+
+    <refsect2><title>lvsmaster</title>
+      <para>
+      This command shows which node is currently the LVSMASTER. The
+      LVSMASTER is the node in the cluster which drives the LVS system and
+      which receives all incoming traffic from clients.
+      </para>
+      <para>
+      LVS is the mode where the entire CTDB/Samba cluster uses a single
+      ip address for the entire cluster. In this mode all clients connect to
+      one specific node which will then multiplex/loadbalance the clients
+      evenly onto the other nodes in the cluster. This is an alternative to using
+      public ip addresses. See the manpage for ctdbd for more information
+      about LVS.
+      </para>
+    </refsect2>
+
+    <refsect2><title>lvs</title>
+      <para>
+      This command shows which nodes in the cluster are currently active in the
+      LVS configuration. I.e. which nodes we are currently loadbalancing
+      the single ip address across.
+      </para>
+
+      <para>
+      LVS will by default only loadbalance across those nodes that are both
+      LVS capable and also HEALTHY. Except if all nodes are UNHEALTHY in which
+      case LVS will loadbalance across all UNHEALTHY nodes as well.
+      LVS will never use nodes that are DISCONNECTED, STOPPED, BANNED or
+      DISABLED.
+      </para>
+
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+2:10.0.0.13
+3:10.0.0.14
+      </screen>
+
+    </refsect2>
+
+
+    <refsect2><title>getcapabilities</title>
+      <para>
+      This command shows the capabilities of the current node.
+      Please see manpage for ctdbd for a full list of all capabilities and
+      more detailed description.
+      </para>
+
+      <para>
+      RECMASTER and LMASTER capabilities are primarily used when CTDBD
+      is used to create a cluster spanning across WAN links. In which case
+      ctdbd acts as a WAN accelerator.
+      </para>
+
+      <para>
+      LVS capabile means that the node is participating in LVS, a mode
+      where the entire CTDB cluster uses one single ip address for the
+      entire cluster instead of using public ip address failover.
+      This is an alternative to using a loadbalancing layer-4 switch.
+      </para>
+
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+RECMASTER: YES
+LMASTER: YES
+LVS: NO
+      </screen>
+
+    </refsect2>
+
+    <refsect2><title>statistics</title>
+      <para>
+        Collect statistics from the CTDB daemon about how many calls it has served.
+      </para>
+      <para>
+	Example: ctdb statistics
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+CTDB version 1
+ num_clients                        3
+ frozen                             0
+ recovering                         0
+ client_packets_sent           360489
+ client_packets_recv           360466
+ node_packets_sent             480931
+ node_packets_recv             240120
+ keepalive_packets_sent             4
+ keepalive_packets_recv             3
+ node
+     req_call                       2
+     reply_call                     2
+     req_dmaster                    0
+     reply_dmaster                  0
+     reply_error                    0
+     req_message                   42
+     req_control               120408
+     reply_control             360439
+ client
+     req_call                       2
+     req_message                   24
+     req_control               360440
+ timeouts
+     call                           0
+     control                        0
+     traverse                       0
+ total_calls                        2
+ pending_calls                      0
+ lockwait_calls                     0
+ pending_lockwait_calls             0
+ memory_used                     5040
+ max_hop_count                      0
+ max_call_latency                   4.948321 sec
+ max_lockwait_latency               0.000000 sec
+      </screen>
+    </refsect2>
+
+    <refsect2><title>statisticsreset</title>
+      <para>
+        This command is used to clear all statistics counters in a node.
+      </para>
+      <para>
+	Example: ctdb statisticsreset
+      </para>
+    </refsect2>
+
+    <refsect2><title>getreclock</title>
+      <para>
+	This command is used to show the filename of the reclock file that is used.
+      </para>
+
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+Reclock file:/gpfs/.ctdb/shared
+      </screen>
+
+    </refsect2>
+
+    <refsect2><title>setreclock [filename]</title>
+      <para>
+	This command is used to modify, or clear, the file that is used as the reclock file at runtime. When this command is used, the reclock file checks are disabled. To re-enable the checks the administrator needs to activate the "VerifyRecoveryLock" tunable using "ctdb setvar".
+      </para>
+
+      <para>
+	If run with no parameter this will remove the reclock file completely. If run with a parameter the parameter specifies the new filename to use for the recovery lock.
+      </para>
+
+      <para>
+	This command only affects the runtime settings of a ctdb node and will be lost when ctdb is restarted. For persistent changes to the reclock file setting you must edit /etc/sysconfig/ctdb.
+      </para>
+    </refsect2>
+
+
+
+    <refsect2><title>getdebug</title>
+      <para>
+        Get the current debug level for the node. the debug level controls what information is written to the log file.
+      </para>
+      <para>
+	The debug levels are mapped to the corresponding syslog levels.
+	When a debug level is set, only those messages at that level and higher
+	levels will be printed.
+      </para>
+      <para>
+	The list of debug levels from highest to lowest are :
+      </para>
+      <para>
+	EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG
+      </para>
+    </refsect2>
+
+    <refsect2><title>setdebug <debuglevel></title>
+      <para>
+        Set the debug level of a node. This controls what information will be logged.
+      </para>
+      <para>
+	The debuglevel is one of EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG
+      </para>
+    </refsect2>
+
+    <refsect2><title>getpid</title>
+      <para>
+        This command will return the process id of the ctdb daemon.
+      </para>
+    </refsect2>
+
+    <refsect2><title>disable</title>
+      <para>
+        This command is used to administratively disable a node in the cluster.
+        A disabled node will still participate in the cluster and host
+        clustered TDB records but its public ip address has been taken over by
+        a different node and it no longer hosts any services.
+      </para>
+    </refsect2>
+
+    <refsect2><title>enable</title>
+      <para>
+        Re-enable a node that has been administratively disabled.
+      </para>
+    </refsect2>
+
+    <refsect2><title>stop</title>
+      <para>
+        This command is used to administratively STOP a node in the cluster.
+        A STOPPED node is connected to the cluster but will not host any
+	public ip addresse, nor does it participate in the VNNMAP.
+	The difference between a DISABLED node and a STOPPED node is that
+	a STOPPED node does not host any parts of the database which means
+	that a recovery is required to stop/continue nodes.
+      </para>
+    </refsect2>
+
+    <refsect2><title>continue</title>
+      <para>
+        Re-start a node that has been administratively stopped.
+      </para>
+    </refsect2>
+
+    <refsect2><title>addip <public_ip/mask> <iface></title>
+      <para>
+	This command is used to add a new public ip to a node during runtime.
+	This allows public addresses to be added to a cluster without having
+	to restart the ctdb daemons.
+      </para>
+      <para>
+	Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read.
+ If you want this change to be permanent you must also update the public addresses file manually.
+      </para>
+    </refsect2>
+
+    <refsect2><title>delip <public_ip></title>
+      <para>
+	This command is used to remove a public ip from a node during runtime.
+	If this public ip is currently hosted by the node it being removed from, the ip will first be failed over to another node, if possible, before it is removed.
+      </para>
+      <para>
+	Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read.
+ If you want this change to be permanent you must also update the public addresses file manually.
+      </para>
+    </refsect2>
+
+    <refsect2><title>moveip <public_ip> <node></title>
+      <para>
+      This command can be used to manually fail a public ip address to a
+      specific node.
+      </para>
+      <para>
+      In order to manually override the "automatic" distribution of public 
+      ip addresses that ctdb normally provides, this command only works
+      when you have changed the tunables for the daemon to:
+      </para>
+      <para>
+      DeterministicIPs = 0
+      </para>
+      <para>
+      NoIPFailback = 1
+      </para>
+    </refsect2>
+
+    <refsect2><title>shutdown</title>
+      <para>
+        This command will shutdown a specific CTDB daemon.
+      </para>
+    </refsect2>
+
+    <refsect2><title>recover</title>
+      <para>
+        This command will trigger the recovery daemon to do a cluster
+        recovery.
+      </para>
+    </refsect2>
+
+    <refsect2><title>ipreallocate</title>
+      <para>
+        This command will force the recovery master to perform a full ip reallocation process and redistribute all ip addresses. This is useful to "reset" the allocations back to its default state if they have been changed using the "moveip" command. While a "recover" will also perform this reallocation, a recovery is much more hevyweight since it will also rebuild all the databases.
+      </para>
+    </refsect2>
+
+    <refsect2><title>setlmasterrole <on|off></title>
+      <para>
+	This command is used ot enable/disable the LMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an LMASTER for records in the database. A node that does not have the LMASTER capability will not show up in the vnnmap.
+      </para>
+
+      <para>
+	Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command.
+      </para>
+      <para>
+	Once this setting has been enabled/disabled, you need to perform a recovery for it to take effect.
+      </para>
+      <para>
+	See also "ctdb getcapabilities"
+      </para>
+    </refsect2>
+
+    <refsect2><title>setrecmasterrole <on|off></title>
+      <para>
+	This command is used ot enable/disable the RECMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an RECMASTER for the cluster. A node that does not have the RECMASTER capability can not win a recmaster election. A node that already is the recmaster for the cluster when the capability is stripped off the node will remain the recmaster until the next cluster election.
+      </para>
+
+      <para>
+	Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command.
+      </para>
+      <para>
+	See also "ctdb getcapabilities"
+      </para>
+    </refsect2>
+
+    <refsect2><title>killtcp <srcip:port> <dstip:port></title>
+      <para>
+        This command will kill the specified TCP connection by issuing a
+        TCP RST to the srcip:port endpoint. This is a command used by the 
+	ctdb eventscripts.
+      </para>
+    </refsect2>
+
+    <refsect2><title>gratiousarp <ip> <interface></title>
+      <para>
+	This command will send out a gratious arp for the specified interface
+	through the specified interface. This command is mainly used by the
+	ctdb eventscripts.
+      </para>
+    </refsect2>
+
+    <refsect2><title>reloadnodes</title>
+      <para>
+      This command is used when adding new nodes, or removing existing nodes from an existing cluster.
+      </para>
+      <para>
+      Procedure to add a node:
+      </para>
+      <para>
+      1, To expand an existing cluster, first ensure with 'ctdb status' that
+      all nodes are up and running and that they are all healthy.
+      Do not try to expand a cluster unless it is completely healthy!
+      </para>
+      <para>
+      2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last
+      entry to the file. The new node MUST be added to the end of this file!
+      </para>
+      <para>
+      3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node!
+      </para>
+      <para>
+      4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.
+      </para>
+      <para>
+      5, Use 'ctdb status' on all nodes and verify that they now show the additional node.
+      </para>
+      <para>
+      6, Install and configure the new node and bring it online.
+      </para>
+      <para>
+      Procedure to remove a node:
+      </para>
+      <para>
+      1, To remove a node from an existing cluster, first ensure with 'ctdb status' that
+      all nodes, except the node to be deleted, are up and running and that they are all healthy.
+      Do not try to remove a node from a cluster unless the cluster is completely healthy!
+      </para>
+      <para>
+      2, Shutdown and poweroff the node to be removed.
+      </para>
+      <para>
+      3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed. Do not delete the line for that node, just comment it out by adding a '#' at the beginning of the line.
+      </para>
+      <para>
+      4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.
+      </para>
+      <para>
+      5, Use 'ctdb status' on all nodes and verify that the deleted node no longer shows up in the list..
+      </para>
+      <para>
+      </para>
+      
+    </refsect2>
+
+    <refsect2><title>tickle <srcip:port> <dstip:port></title>
+      <para>
+        This command will will send a TCP tickle to the source host for the
+        specified TCP connection.
+	A TCP tickle is a TCP ACK packet with an invalid sequence and 
+	acknowledge number and will when received by the source host result
+        in it sending an immediate correct ACK back to the other end.
+      </para>
+      <para>
+        TCP tickles are useful to "tickle" clients after a IP failover has 
+        occured since this will make the client immediately recognize the 
+        TCP connection has been disrupted and that the client will need
+        to reestablish. This greatly speeds up the time it takes for a client
+        to detect and reestablish after an IP failover in the ctdb cluster.
+      </para>
+    </refsect2>
+
+    <refsect2><title>gettickles <ip></title>
+      <para>
+	This command is used to show which TCP connections are registered with
+	CTDB to be "tickled" if there is a failover.
+      </para>
+    </refsect2>
+    <refsect2><title>repack [max_freelist]</title>
+      <para>
+	Over time, when records are created and deleted in a TDB, the TDB list of free space will become fragmented. This can lead to a slowdown in accessing TDB records.
+	This command is used to defragment a TDB database and pruning the freelist.
+      </para>
+ 
+	<para>
+	If [max_freelist] is specified, then a database will only be repacked if it has more than this number of entries in the freelist.
+	</para>
+      <para>
+	During repacking of the database, the entire TDB database will be locked to prevent writes. If samba tries to write to a record in the database during a repack operation, samba will block until the repacking has completed.
+      </para>
+ 
+      <para>
+	This command can be disruptive and can cause samba to block for the duration of the repack operation. In general, a repack operation will take less than one second to complete.
+      </para>
+ 
+      <para>
+	A repack operation will only defragment the local TDB copy of the CTDB database. You need to run this command on all of the nodes to repack a CTDB database completely.
+	</para>
+
+      <para>
+	Example: ctdb repack 1000
+      </para>
+
+      <para>
+	 By default, this operation is issued from the 00.ctdb event script every 5 minutes.
+      </para>
+ 
+    </refsect2>
+
+    <refsect2><title>vacuum [max_records]</title>
+      <para>
+	Over time CTDB databases will fill up with empty deleted records which will lead to a progressive slow down of CTDB database access.
+	This command is used to prune all databases and delete all empty records from the cluster.
+      </para>
+ 
+      <para>
+	 By default, vacuum will delete all empty records from all databases.
+	 If [max_records] is specified, the command will only delete the first
+	 [max_records] empty records for each database.
+      </para>
+ 
+      <para>
+	 Vacuum only deletes records where the local node is the lmaster.
+	 To delete all records from the entire cluster you need to run a vacuum from each node.
+
+	 This command is not disruptive. Samba is unaffected and will still be able to read/write records normally while the database is being vacuumed.
+      </para>
+
+      <para>
+	Example: ctdb vacuum
+      </para>
+ 
+      <para>
+	 By default, this operation is issued from the 00.ctdb event script every 5 minutes.
+      </para>
+    </refsect2>
+
+    <refsect2><title>backupdb <dbname> <file></title>
+      <para>
+        This command can be used to copy the entire content of a database out to a file. This file can later be read back into ctdb using the restoredb command.
+This is mainly useful for backing up persistent databases such as secrets.tdb and similar.
+      </para>
+    </refsect2>
+
+    <refsect2><title>restoredb <file> [<dbname>]</title>
+      <para>
+        This command restores a persistent database that was previously backed up using backupdb.
+	By default the data will be restored back into the same database as
+	it was created from. By specifying dbname you can restore the data
+	into a different database.
+      </para>
+    </refsect2>
+
+    <refsect2><title>wipedb <dbname></title>
+      <para>
+        This command can be used to remove all content of a database.
+      </para>
+    </refsect2>
+  </refsect1>
+
+
+    <refsect2><title>getlog <level></title>
+      <para>
+	In addition to the normal loggign to a log file,
+	CTDBD also keeps a in-memory ringbuffer containing the most recent
+	log entries for all log levels (except DEBUG).
+      </para><para>
+	This is useful since it allows for keeping continuous logs to a file
+	at a reasonable non-verbose level, but shortly after an incident has
+	occured, a much more detailed log can be pulled from memory. This
+	can allow you to avoid having to reproduce an issue due to the
+	on-disk logs being of insufficient detail.
+      </para><para>
+	This command extracts all messages of level or lower log level from
+	memory and prints it to the screen.
+      </para>
+    </refsect2>
+
+    <refsect2><title>clearlog</title>
+      <para>
+	This command clears the in-memory logging ringbuffer.
+      </para>
+    </refsect2>
+
+
+  <refsect1><title>Debugging Commands</title>
+    <para>
+      These commands are primarily used for CTDB development and testing and
+      should not be used for normal administration.
+    </para>
+    <refsect2><title>process-exists <pid></title>
+      <para>
+        This command checks if a specific process exists on the CTDB host. This is mainly used by Samba to check if remote instances of samba are still running or not.
+      </para>
+    </refsect2>
+
+    <refsect2><title>getdbmap</title>
+      <para>
+        This command lists all clustered TDB databases that the CTDB daemon has attached to. Some databases are flagged as PERSISTENT, this means that the database stores data persistently and the data will remain across reboots. One example of such a database is secrets.tdb where information about how the cluster was joined to the domain is stored.
+      </para>
+      <para>
+	If a PERSISTENT database is not in a healthy state the database is
+	flagged as UNHEALTHY. If there's at least one completely healthy node running in
+	the cluster, it's possible that the content is restored by a recovery
+	run automaticly. Otherwise an administrator needs to analyze the
+	problem.
+      </para>
+      <para>
+	See also "ctdb getdbstatus", "ctdb backupdb", "ctdb restoredb",
+	"ctdb dumpbackup", "ctdb wipedb", "ctdb setvar AllowUnhealthyDBRead 1"
+	and (if samba or tdb-utils are installed) "tdbtool check".
+	</para>
+	<para>
+	Most databases are not persistent and only store the state information that the currently running samba daemons need. These databases are always wiped when ctdb/samba starts and when a node is rebooted.
+      </para>
+      <para>
+	Example: ctdb getdbmap
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+Number of databases:10
+dbid:0x435d3410 name:notify.tdb path:/var/ctdb/notify.tdb.0 
+dbid:0x42fe72c5 name:locking.tdb path:/var/ctdb/locking.tdb.0
+dbid:0x1421fb78 name:brlock.tdb path:/var/ctdb/brlock.tdb.0 
+dbid:0x17055d90 name:connections.tdb path:/var/ctdb/connections.tdb.0 
+dbid:0xc0bdde6a name:sessionid.tdb path:/var/ctdb/sessionid.tdb.0 
+dbid:0x122224da name:test.tdb path:/var/ctdb/test.tdb.0 
+dbid:0x2672a57f name:idmap2.tdb path:/var/ctdb/persistent/idmap2.tdb.0 PERSISTENT
+dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT
+dbid:0xe98e08b6 name:group_mapping.tdb path:/var/ctdb/persistent/group_mapping.tdb.0 PERSISTENT
+dbid:0x7bbbd26c name:passdb.tdb path:/var/ctdb/persistent/passdb.tdb.0 PERSISTENT
+      </screen>
+      <para>
+	Example output for an unhealthy database:
+      </para>
+      <screen format="linespecific">
+Number of databases:1
+dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT UNHEALTHY
+      </screen>
+
+      <para>
+	Example output for a healthy database as machinereadable output -Y:
+      </para>
+      <screen format="linespecific">
+:ID:Name:Path:Persistent:Unhealthy:
+:0x7bbbd26c:passdb.tdb:/var/ctdb/persistent/passdb.tdb.0:1:0:
+      </screen>
+    </refsect2>
+
+    <refsect2><title>getdbstatus <dbname></title>
+      <para>
+	This command displays more details about a database.
+      </para>
+      <para>
+	Example: ctdb getdbstatus test.tdb.0
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+dbid: 0x122224da
+name: test.tdb
+path: /var/ctdb/test.tdb.0
+PERSISTENT: no
+HEALTH: OK
+      </screen>
+      <para>
+	Example: ctdb getdbstatus registry.tdb (with a corrupted TDB)
+      </para>
+      <para>
+	Example output:
+      </para>
+      <screen format="linespecific">
+dbid: 0xf2a58948
+name: registry.tdb
+path: /var/ctdb/persistent/registry.tdb.0
+PERSISTENT: yes
+HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persistent/registry.tdb.0.corrupted.20091208091949.0Z'
+      </screen>
+    </refsect2>
+
+    <refsect2><title>catdb <dbname></title>
+      <para>
+        This command will dump a clustered TDB database to the screen. This is a debugging command.
+      </para>
+    </refsect2>
+
+    <refsect2><title>cattdb <dbname></title>
+      <para>
+        This command will dump the content of the local TDB database to the screen. This is a debugging command.
+      </para>
+    </refsect2>
+
+    <refsect2><title>dumpdbbackup <backup-file></title>
+      <para>
+	This command will dump the content of database backup to the screen
+	(similar to ctdb catdb). This is a debugging command.
+      </para>
+    </refsect2>
+
+    <refsect2><title>getmonmode</title>
+      <para>
+        This command returns the monutoring mode of a node. The monitoring mode is either ACTIVE or DISABLED. Normally a node will continuously monitor that all other nodes that are expected are in fact connected and that they respond to commands.
+      </para>
+      <para>
+        ACTIVE - This is the normal mode. The node is actively monitoring all other nodes, both that the transport is connected and also that the node responds to commands. If a node becomes unavailable, it will be marked as DISCONNECTED and a recovery is initiated to restore the cluster.
+      </para>
+      <para>
+        DISABLED - This node is not monitoring that other nodes are available. In this mode a node failure will not be detected and no recovery will be performed. This mode is useful when for debugging purposes one wants to attach GDB to a ctdb process but wants to prevent the rest of the cluster from marking this node as DISCONNECTED and do a recovery.
+      </para>
+    </refsect2>
+
+
+    <refsect2><title>setmonmode <0|1></title>
+      <para>
+        This command can be used to explicitly disable/enable monitoring mode on a node. The main purpose is if one wants to attach GDB to a running ctdb daemon but wants to prevent the other nodes from marking it as DISCONNECTED and issuing a recovery. To do this, set monitoring mode to 0 on all nodes before attaching with GDB. Remember to set monitoring mode back to 1 afterwards.
+      </para>
+    </refsect2>
+
+    <refsect2><title>attach <dbname> [persistent]</title>
+      <para>
+        This is a debugging command. This command will make the CTDB daemon create a new CTDB database and attach to it.
+      </para>
+    </refsect2>
+
+    <refsect2><title>dumpmemory</title>
+      <para>
+        This is a debugging command. This command will make the ctdb
+        daemon to write a fill memory allocation map to standard output.
+      </para>
+    </refsect2>
+
+    <refsect2><title>rddumpmemory</title>
+      <para>
+        This is a debugging command. This command will dump the talloc memory
+	allocation tree for the recovery daemon to standard output.
+      </para>
+    </refsect2>
+
+    <refsect2><title>thaw</title>
+      <para>
+        Thaw a previously frozen node.
+      </para>
+    </refsect2>
+
+
+    <refsect2><title>eventscript <arguments></title>
+      <para>
+        This is a debugging command. This command can be used to manually
+	invoke and run the eventscritps with arbitrary arguments.
+      </para>
+    </refsect2>
+
+    <refsect2><title>ban <bantime|0></title>
+      <para>
+        Administratively ban a node for bantime seconds. A bantime of 0 means that the node should be permanently banned. 
+      </para>
+      <para>
+        A banned node does not participate in the cluster and does not host any records for the clustered TDB. Its ip address has been taken over by another node and no services are hosted.
+      </para>
+      <para>
+        Nodes are automatically banned if they are the cause of too many
+        cluster recoveries.
+      </para>
+      <para>
+	This is primarily a testing command. Note that the recovery daemon controls the overall ban state and it may automatically unban nodes at will. Meaning that a node that has been banned by the administrator can and ofter are unbanned before the admin specifid timeout triggers. If wanting to "drop" a node out from the cluster for mainentance or other reasons, use the "stop" / "continue" commands instad of "ban" / "unban". 
+      </para>
+    </refsect2>
+
+    <refsect2><title>unban</title>
+      <para>
+        This command is used to unban a node that has either been 
+        administratively banned using the ban command or has been automatically
+        banned by the recovery daemon.
+      </para>
+    </refsect2>
+
+
+  </refsect1>
+
+  <refsect1><title>SEE ALSO</title>
+    <para>
+      ctdbd(1), onnode(1)
+      <ulink url="http://ctdb.samba.org/"/>
+    </para>
+  </refsect1>
+  <refsect1><title>COPYRIGHT/LICENSE</title>
+<literallayout>
+Copyright (C) Andrew Tridgell 2007
+Copyright (C) Ronnie sahlberg 2007
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www.gnu.org/licenses/.
+</literallayout>
+  </refsect1>
+</refentry>

Added: branches/ctdb/squeeze-backports/doc/ctdbd.1
===================================================================
--- branches/ctdb/squeeze-backports/doc/ctdbd.1	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ctdbd.1	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,711 @@
+'\" t
+.\"     Title: ctdbd
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: 09/08/2010
+.\"    Manual: CTDB - clustered TDB database
+.\"    Source: ctdb
+.\"  Language: English
+.\"
+.TH "CTDBD" "1" "09/08/2010" "ctdb" "CTDB \- clustered TDB database"
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+ctdbd \- The CTDB cluster daemon
+.SH "SYNOPSIS"
+.HP \w'\fBctdbd\fR\ 'u
+\fBctdbd\fR
+.HP \w'\fBctdbd\fR\ 'u
+\fBctdbd\fR [\-?\ \-\-help] [\-d\ \-\-debug=<INTEGER>] {\-\-dbdir=<directory>} {\-\-dbdir\-persistent=<directory>} [\-\-event\-script\-dir=<directory>] [\-i\ \-\-interactive] [\-\-listen=<address>] [\-\-logfile=<filename>] [\-\-lvs] {\-\-nlist=<filename>} [\-\-no\-lmaster] [\-\-no\-recmaster] [\-\-nosetsched] {\-\-notification\-script=<filename>} [\-\-public\-addresses=<filename>] [\-\-public\-interface=<interface>] {\-\-reclock=<filename>} [\-\-single\-public\-ip=<address>] [\-\-socket=<filename>] [\-\-start\-as\-disabled] [\-\-start\-as\-stopped] [\-\-syslog] [\-\-log\-ringbuf\-size=<num\-entries>] [\-\-torture] [\-\-transport=<STRING>] [\-\-usage]
+.SH "DESCRIPTION"
+.PP
+ctdbd is the main ctdb daemon\&.
+.PP
+ctdbd provides a clustered version of the TDB database with automatic rebuild/recovery of the databases upon nodefailures\&.
+.PP
+Combined with a cluster filesystem ctdbd provides a full HA environment for services such as clustered Samba and NFS as well as other services\&.
+.PP
+ctdbd provides monitoring of all nodes in the cluster and automatically reconfigures the cluster and recovers upon node failures\&.
+.PP
+ctdbd is the main component in clustered Samba that provides a high\-availability load\-sharing CIFS server cluster\&.
+.SH "OPTIONS"
+.PP
+\-? \-\-help
+.RS 4
+Print some help text to the screen\&.
+.RE
+.PP
+\-d \-\-debug=<DEBUGLEVEL>
+.RS 4
+This option sets the debuglevel on the ctdbd daemon which controls what will be written to the logfile\&. The default is 0 which will only log important events and errors\&. A larger number will provide additional logging\&.
+.RE
+.PP
+\-\-dbdir=<directory>
+.RS 4
+This is the directory on local storage where ctdbd keeps the local copy of the TDB databases\&. This directory is local for each node and should not be stored on the shared cluster filesystem\&.
+.sp
+This directory would usually be /var/ctdb \&.
+.RE
+.PP
+\-\-dbdir\-persistent=<directory>
+.RS 4
+This is the directory on local storage where ctdbd keeps the local copy of the persistent TDB databases\&. This directory is local for each node and should not be stored on the shared cluster filesystem\&.
+.sp
+This directory would usually be /etc/ctdb/persistent \&.
+.RE
+.PP
+\-\-event\-script\-dir=<directory>
+.RS 4
+This option is used to specify the directory where the CTDB event scripts are stored\&.
+.sp
+This will normally be /etc/ctdb/events\&.d which is part of the ctdb distribution\&.
+.RE
+.PP
+\-i \-\-interactive
+.RS 4
+By default ctdbd will detach itself from the shell and run in the background as a daemon\&. This option makes ctdbd to start in interactive mode\&.
+.RE
+.PP
+\-\-listen=<address>
+.RS 4
+This specifies which ip address ctdb will bind to\&. By default ctdbd will bind to the first address it finds in the /etc/ctdb/nodes file and which is also present on the local system in which case you do not need to provide this option\&.
+.sp
+This option is only required when you want to run multiple ctdbd daemons/nodes on the same physical host in which case there would be multiple entries in /etc/ctdb/nodes what would match a local interface\&.
+.RE
+.PP
+\-\-logfile=<filename>
+.RS 4
+This is the file where ctdbd will write its log\&. This is usually /var/log/log\&.ctdb \&.
+.RE
+.PP
+\-\-lvs
+.RS 4
+This option is used to activate the LVS capability on a CTDB node\&. Please see the LVS section\&.
+.RE
+.PP
+\-\-nlist=<filename>
+.RS 4
+This file contains a list of the private ip addresses of every node in the cluster\&. There is one line/ip address for each node\&. This file must be the same for all nodes in the cluster\&.
+.sp
+This file is usually /etc/ctdb/nodes \&.
+.RE
+.PP
+\-\-no\-lmaster
+.RS 4
+This argument specifies that this node can NOT become an lmaster for records in the database\&. This means that it will never show up in the vnnmap\&. This feature is primarily used for making a cluster span across a WAN link and use CTDB as a WAN\-accelerator\&.
+.sp
+Please see the "remote cluster nodes" section for more information\&.
+.RE
+.PP
+\-\-no\-recmaster
+.RS 4
+This argument specifies that this node can NOT become a recmaster for the database\&. This feature is primarily used for making a cluster span across a WAN link and use CTDB as a WAN\-accelerator\&.
+.sp
+Please see the "remote cluster nodes" section for more information\&.
+.RE
+.PP
+\-\-nosetsched
+.RS 4
+This is a ctdbd debugging option\&. this option is only used when debugging ctdbd\&.
+.sp
+Normally ctdb will change its scheduler to run as a real\-time process\&. This is the default mode for a normal ctdbd operation to gurarantee that ctdbd always gets the cpu cycles that it needs\&.
+.sp
+This option is used to tell ctdbd to NOT run as a real\-time process and instead run ctdbd as a normal userspace process\&. This is useful for debugging and when you want to run ctdbd under valgrind or gdb\&. (You don\'t want to attach valgrind or gdb to a real\-time process\&.)
+.RE
+.PP
+\-\-notification\-script=<filename>
+.RS 4
+This specifies a script which will be invoked by ctdb when certain state changes occur in ctdbd and when you may want to trigger this to run certain scripts\&.
+.sp
+This file is usually /etc/ctdb/notify\&.sh \&.
+.sp
+See the NOTIFICATION SCRIPT section below for more information\&.
+.RE
+.PP
+\-\-public_addresses=<filename>
+.RS 4
+When used with IP takeover this specifies a file containing the public ip addresses to use on the cluster\&. This file contains a list of ip addresses netmasks and interfaces\&. When ctdb is operational it will distribute these public ip addresses evenly across the available nodes\&.
+.sp
+This is usually the file /etc/ctdb/public_addresses
+.RE
+.PP
+\-\-public\-interface=<interface>
+.RS 4
+This option tells ctdb which interface to attach public\-addresses to and also where to attach the single\-public\-ip when used\&.
+.sp
+This is only required when using public ip addresses and only when you don\'t specify the interface explicitly in /etc/ctdb/public_addresses or when you are using \-\-single\-public\-ip\&.
+.sp
+If you omit this argument when using public addresses or single public ip, ctdb will not be able to send out Gratious ARPs correctly or be able to kill tcp connections correctly which will lead to application failures\&.
+.RE
+.PP
+\-\-reclock=<filename>
+.RS 4
+This is the name of the lock file stored of the shared cluster filesystem that ctdbd uses to prevent split brains from occuring\&. This file must be stored on shared storage\&.
+.sp
+It is possible to run CTDB without a reclock file, but then there will be no protection against split brain if the network becomes partitioned\&. Using CTDB without a reclock file is strongly discouraged\&.
+.RE
+.PP
+\-\-socket=<filename>
+.RS 4
+This specifies the name of the domain socket that ctdbd will create\&. This socket is used for local clients to attach to and communicate with the ctdbd daemon\&.
+.sp
+The default is /tmp/ctdb\&.socket \&. You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host\&.
+.RE
+.PP
+\-\-start\-as\-disabled
+.RS 4
+This makes the ctdb daemon to be DISABLED when it starts up\&.
+.sp
+As it is DISABLED it will not get any of the public ip addresses allocated to it, and thus this allow you to start ctdb on a node without causing any ip address to failover from other nodes onto the new node\&.
+.sp
+When used, the administrator must keep track of when nodes start and manually enable them again using the "ctdb enable" command, or else the node will not host any services\&.
+.sp
+A node that is DISABLED will not host any services and will not be reachable/used by any clients\&.
+.RE
+.PP
+\-\-start\-as\-stopped
+.RS 4
+This makes the ctdb daemon to be STOPPED when it starts up\&.
+.sp
+A node that is STOPPED does not host any public addresses\&. It is not part of the VNNMAP so it does act as an LMASTER\&. It also has all databases locked in recovery mode until restarted\&.
+.sp
+To restart and activate a STOPPED node, the command "ctdb continue" is used\&.
+.sp
+A node that is STOPPED will not host any services and will not be reachable/used by any clients\&.
+.RE
+.PP
+\-\-syslog
+.RS 4
+Send all log messages to syslog instead of to the ctdb logfile\&.
+.RE
+.PP
+\-\-log\-ringbuf\-size=<num\-entries>
+.RS 4
+In addition to the normal loggign to a log file, CTDBD also keeps a in\-memory ringbuffer containing the most recent log entries for all log levels (except DEBUG)\&.
+.sp
+This is useful since it allows for keeping continuous logs to a file at a reasonable non\-verbose level, but shortly after an incident has occured, a much more detailed log can be pulled from memory\&. This can allow you to avoid having to reproduce an issue due to the on\-disk logs being of insufficient detail\&.
+.sp
+This in\-memory ringbuffer contains a fixed number of the most recent entries\&. This is settable at startup either through the \-\-log\-ringbuf\-size argument, or preferably by using CTDB_LOG_RINGBUF_SIZE in the sysconfig file\&.
+.sp
+Use the "ctdb getlog" command to access this log\&.
+.RE
+.PP
+\-\-torture
+.RS 4
+This option is only used for development and testing of ctdbd\&. It adds artificial errors and failures to the common codepaths in ctdbd to verify that ctdbd can recover correctly for failures\&.
+.sp
+You do NOT want to use this option unless you are developing and testing new functionality in ctdbd\&.
+.RE
+.PP
+\-\-transport=<STRING>
+.RS 4
+This option specifies which transport to use for ctdbd internode communications\&. The default is "tcp"\&.
+.sp
+Currently only "tcp" is supported but "infiniband" might be implemented in the future\&.
+.RE
+.PP
+\-\-usage
+.RS 4
+Print useage information to the screen\&.
+.RE
+.SH "PRIVATE VS PUBLIC ADDRESSES"
+.PP
+When used for ip takeover in a HA environment, each node in a ctdb cluster has multiple ip addresses assigned to it\&. One private and one or more public\&.
+.SS "Private address"
+.PP
+This is the physical ip address of the node which is configured in linux and attached to a physical interface\&. This address uniquely identifies a physical node in the cluster and is the ip addresses that ctdbd will use to communicate with the ctdbd daemons on the other nodes in the cluster\&.
+.PP
+The private addresses are configured in /etc/ctdb/nodes (unless the \-\-nlist option is used) and contain one line for each node in the cluster\&. Each line contains the private ip address for one node in the cluster\&. This file must be the same on all nodes in the cluster\&.
+.PP
+Since the private addresses are only available to the network when the corresponding node is up and running you should not use these addresses for clients to connect to services provided by the cluster\&. Instead client applications should only attach to the public addresses since these are guaranteed to always be available\&.
+.PP
+When using ip takeover, it is strongly recommended that the private addresses are configured on a private network physically separated from the rest of the network and that this private network is dedicated to CTDB traffic\&.
+
+      Example /etc/ctdb/nodes for a four node cluster:
+      
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+        10\&.1\&.1\&.1
+        10\&.1\&.1\&.2
+        10\&.1\&.1\&.3
+        10\&.1\&.1\&.4
+      
+.fi
+.if n \{\
+.RE
+.\}
+.SS "Public address"
+.PP
+A public address on the other hand is not attached to an interface\&. This address is managed by ctdbd itself and is attached/detached to a physical node at runtime\&.
+.PP
+The ctdb cluster will assign/reassign these public addresses across the available healthy nodes in the cluster\&. When one node fails, its public address will be migrated to and taken over by a different node in the cluster to ensure that all public addresses are always available to clients as long as there are still nodes available capable of hosting this address\&.
+.PP
+These addresses are not physically attached to a specific node\&. The \'ctdb ip\' command can be used to view the current assignment of public addresses and which physical node is currently serving it\&.
+.PP
+On each node this file contains a list of the public addresses that this node is capable of hosting\&. The list also contain the netmask and the interface where this address should be attached for the case where you may want to serve data out through multiple different interfaces\&.
+
+      Example /etc/ctdb/public_addresses for a node that can host 4 public addresses:
+      
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+        11\&.1\&.1\&.1/24 eth0
+        11\&.1\&.1\&.2/24 eth0
+        11\&.1\&.2\&.1/24 eth1
+        11\&.1\&.2\&.2/24 eth1
+      
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+In most cases this file would be the same on all nodes in a cluster but there are exceptions when one may want to use different files on different nodes\&.
+
+	Example: 4 nodes partitioned into two subgroups :
+	
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+	Node 0:/etc/ctdb/public_addresses
+		10\&.1\&.1\&.1/24 eth0
+		10\&.1\&.1\&.2/24 eth0
+
+	Node 1:/etc/ctdb/public_addresses
+		10\&.1\&.1\&.1/24 eth0
+		10\&.1\&.1\&.2/24 eth0
+
+	Node 2:/etc/ctdb/public_addresses
+		10\&.2\&.1\&.1/24 eth0
+		10\&.2\&.1\&.2/24 eth0
+
+	Node 3:/etc/ctdb/public_addresses
+		10\&.2\&.1\&.1/24 eth0
+		10\&.2\&.1\&.2/24 eth0
+	
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+In this example nodes 0 and 1 host two public addresses on the 10\&.1\&.1\&.x network while nodes 2 and 3 host two public addresses for the 10\&.2\&.1\&.x network\&.
+.PP
+Ip address 10\&.1\&.1\&.1 can be hosted by either of nodes 0 or 1 and will be available to clients as long as at least one of these two nodes are available\&. If both nodes 0 and node 1 become unavailable 10\&.1\&.1\&.1 also becomes unavailable\&. 10\&.1\&.1\&.1 can not be failed over to node 2 or node 3 since these nodes do not have this ip address listed in their public addresses file\&.
+.SH "NODE STATUS"
+.PP
+The current status of each node in the cluster can be viewed by the \'ctdb status\' command\&.
+.PP
+There are five possible states for a node\&.
+.PP
+OK \- This node is fully functional\&.
+.PP
+DISCONNECTED \- This node could not be connected through the network and is currently not particpating in the cluster\&. If there is a public IP address associated with this node it should have been taken over by a different node\&. No services are running on this node\&.
+.PP
+DISABLED \- This node has been administratively disabled\&. This node is still functional and participates in the CTDB cluster but its IP addresses have been taken over by a different node and no services are currently being hosted\&.
+.PP
+UNHEALTHY \- A service provided by this node is malfunctioning and should be investigated\&. The CTDB daemon itself is operational and participates in the cluster\&. Its public IP address has been taken over by a different node and no services are currently being hosted\&. All unhealthy nodes should be investigated and require an administrative action to rectify\&.
+.PP
+BANNED \- This node failed too many recovery attempts and has been banned from participating in the cluster for a period of RecoveryBanPeriod seconds\&. Any public IP address has been taken over by other nodes\&. This node does not provide any services\&. All banned nodes should be investigated and require an administrative action to rectify\&. This node does not perticipate in the CTDB cluster but can still be communicated with\&. I\&.e\&. ctdb commands can be sent to it\&.
+.PP
+STOPPED \- A node that is stopped does not host any public ip addresses, nor is it part of the VNNMAP\&. A stopped node can not become LVSMASTER, RECMASTER or NATGW\&. This node does not perticipate in the CTDB cluster but can still be communicated with\&. I\&.e\&. ctdb commands can be sent to it\&.
+.SH "PUBLIC TUNABLES"
+.PP
+These are the public tuneables that can be used to control how ctdb behaves\&.
+.SS "KeepaliveInterval"
+.PP
+Default: 1
+.PP
+How often should the nodes send keepalives to eachother\&.
+.SS "KeepaliveLimit"
+.PP
+Default: 5
+.PP
+After how many keepalive intervals without any traffic should a node wait until marking the peer as DISCONNECTED\&.
+.SS "MonitorInterval"
+.PP
+Default: 15
+.PP
+How often should ctdb run the event scripts to check for a nodes health\&.
+.SS "TickleUpdateInterval"
+.PP
+Default: 20
+.PP
+How often will ctdb record and store the "tickle" information used to kickstart stalled tcp connections after a recovery\&.
+.SS "EventScriptTimeout"
+.PP
+Default: 20
+.PP
+How long should ctdb let an event script run before aborting it and marking the node unhealthy\&.
+.SS "RecoveryBanPeriod"
+.PP
+Default: 300
+.PP
+If a node becomes banned causing repetitive recovery failures\&. The node will eventually become banned from the cluster\&. This controls how long the culprit node will be banned from the cluster before it is allowed to try to join the cluster again\&. Don\'t set to small\&. A node gets banned for a reason and it is usually due to real problems with the node\&.
+.SS "DatabaseHashSize"
+.PP
+Default: 100000
+.PP
+Size of the hash chains for the local store of the tdbs that ctdb manages\&.
+.SS "RerecoveryTimeout"
+.PP
+Default: 10
+.PP
+Once a recovery has completed, no additional recoveries are permitted until this timeout has expired\&.
+.SS "EnableBans"
+.PP
+Default: 1
+.PP
+When set to 0, this disables BANNING completely in the cluster and thus nodes can not get banned, even it they break\&. Don\'t set to 0\&.
+.SS "DeterministicIPs"
+.PP
+Default: 1
+.PP
+When enabled, this tunable makes ctdb try to keep public IP addresses locked to specific nodes as far as possible\&. This makes it easier for debugging since you can know that as long as all nodes are healthy public IP X will always be hosted by node Y\&.
+.PP
+The cost of using deterministic IP address assignment is that it disables part of the logic where ctdb tries to reduce the number of public IP assignment changes in the cluster\&. This tunable may increase the number of IP failover/failbacks that are performed on the cluster by a small margin\&.
+.SS "DisableWhenUnhealthy"
+.PP
+Default: 0
+.PP
+When set, As soon as a node becomes unhealthy, that node will also automatically become permanently DISABLED\&. Once a node is DISABLED, the only way to make it participate in the cluster again and host services is by manually enabling the node again using \'ctdb enable\'\&.
+.PP
+This disables parts of the resilience and robustness of the cluster and should ONLY be used when the system administrator is actively monitoring the cluster, so that nodes can be enabled again\&.
+.SS "NoIPFailback"
+.PP
+Default: 0
+.PP
+When set to 1, ctdb will not perform failback of IP addresses when a node becomes healthy\&. Ctdb WILL perform failover of public IP addresses when a node becomes UNHEALTHY, but when the node becomes HEALTHY again, ctdb will not fail the addresses back\&.
+.PP
+Use with caution! Normally when a node becomes available to the cluster ctdb will try to reassign public IP addresses onto the new node as a way to distribute the workload evenly across the clusternode\&. Ctdb tries to make sure that all running nodes have approximately the same number of public addresses it hosts\&.
+.PP
+When you enable this tunable, CTDB will no longer attempt to rebalance the cluster by failing IP addresses back to the new nodes\&. An unbalanced cluster will therefore remain unbalanced until there is manual intervention from the administrator\&. When this parameter is set, you can manually fail public IP addresses over to the new node(s) using the \'ctdb moveip\' command\&.
+.SH "LVS"
+.PP
+LVS is a mode where CTDB presents one single IP address for the entire cluster\&. This is an alternative to using public IP addresses and round\-robin DNS to loadbalance clients across the cluster\&.
+.PP
+This is similar to using a layer\-4 loadbalancing switch but with some restrictions\&.
+.PP
+In this mode the cluster select a set of nodes in the cluster and loadbalance all client access to the LVS address across this set of nodes\&. This set of nodes are all LVS capable nodes that are HEALTHY, or if no HEALTHY nodes exists all LVS capable nodes regardless of health status\&. LVS will however never loadbalance traffic to nodes that are BANNED, STOPPED, DISABLED or DISCONNECTED\&. The "ctdb lvs" command is used to show which nodes are currently load\-balanced across\&.
+.PP
+One of the these nodes are elected as the LVSMASTER\&. This node receives all traffic from clients coming in to the LVS address and multiplexes it across the internal network to one of the nodes that LVS is using\&. When responding to the client, that node will send the data back directly to the client, bypassing the LVSMASTER node\&. The command "ctdb lvsmaster" will show which node is the current LVSMASTER\&.
+.PP
+The path used for a client i/o is thus :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+	(1) Client sends request packet to LVSMASTER
+	(2) LVSMASTER passes the request on to one node across the internal network\&.
+	(3) Selected node processes the request\&.
+	(4) Node responds back to client\&.
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+This means that all incoming traffic to the cluster will pass through one physical node, which limits scalability\&. You can send more data to the LVS address that one physical node can multiplex\&. This means that you should not use LVS if your I/O pattern is write\-intensive since you will be limited in the available network bandwidth that node can handle\&. LVS does work wery well for read\-intensive workloads where only smallish READ requests are going through the LVSMASTER bottleneck and the majority of the traffic volume (the data in the read replies) goes straight from the processing node back to the clients\&. For read\-intensive i/o patterns you can acheive very high throughput rates in this mode\&.
+.PP
+Note: you can use LVS and public addresses at the same time\&.
+.SS "Configuration"
+.PP
+To activate LVS on a CTDB node you must specify CTDB_PUBLIC_INTERFACE and CTDB_LVS_PUBLIC_ADDRESS in /etc/sysconfig/ctdb\&.
+.PP
+You must also specify the "\-\-lvs" command line argument to ctdbd to activate LVS as a capability of the node\&. This should be done automatically for you by the /etc/init\&.d/ctdb script\&.
+.PP
+Example:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+	CTDB_PUBLIC_INTERFACE=eth0
+	CTDB_LVS_PUBLIC_IP=10\&.0\&.0\&.237
+	
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+If you use LVS, you must still have a real/permanent address configured for the public interface on each node\&. This address must be routable and the cluster nodes must be configured so that all traffic back to client hosts are routed through this interface\&. This is also required in order to allow samba/winbind on the node to talk to the domain controller\&. (we can not use the lvs IP address to initiate outgoing traffic)
+.PP
+I\&.e\&. make sure that you can "ping" both the domain controller and also all of the clients from the node BEFORE you enable LVS\&. Also make sure that when you ping these hosts that the traffic is routed out through the eth0 interface\&.
+.SH "REMOTE CLUSTER NODES"
+.PP
+It is possible to have a CTDB cluster that spans across a WAN link\&. For example where you have a CTDB cluster in your datacentre but you also want to have one additional CTDB node located at a remote branch site\&. This is similar to how a WAN accelerator works but with the difference that while a WAN\-accelerator often acts as a Proxy or a MitM, in the ctdb remote cluster node configuration the Samba instance at the remote site IS the genuine server, not a proxy and not a MitM, and thus provides 100% correct CIFS semantics to clients\&.
+.PP
+See the cluster as one single multihomed samba server where one of the NICs (the remote node) is very far away\&.
+.PP
+NOTE: This does require that the cluster filesystem you use can cope with WAN\-link latencies\&. Not all cluster filesystems can handle WAN\-link latencies! Whether this will provide very good WAN\-accelerator performance or it will perform very poorly depends entirely on how optimized your cluster filesystem is in handling high latency for data and metadata operations\&.
+.PP
+To activate a node as being a remote cluster node you need to set the following two parameters in /etc/sysconfig/ctdb for the remote node:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+CTDB_CAPABILITY_LMASTER=no
+CTDB_CAPABILITY_RECMASTER=no
+	
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Verify with the command "ctdb getcapabilities" that that node no longer has the recmaster or the lmaster capabilities\&.
+.SH "NAT-GW"
+.PP
+Sometimes it is desireable to run services on the CTDB node which will need to originate outgoing traffic to external servers\&. This might be contacting NIS servers, LDAP servers etc\&. etc\&.
+.PP
+This can sometimes be problematic since there are situations when a node does not have any public ip addresses assigned\&. This could be due to the nobe just being started up and no addresses have been assigned yet or it could be that the node is UNHEALTHY in which case all public addresses have been migrated off\&.
+.PP
+If then the service status of CTDB depends on such services being able to always being able to originate traffic to external resources this becomes extra troublesome\&. The node might be UNHEALTHY because the service can not be reached, and the service can not be reached because the node is UNHEALTHY\&.
+.PP
+There are two ways to solve this problem\&. The first is by assigning a static ip address for one public interface on every node which will allow every node to be able to route traffic to the public network even if there are no public addresses assigned to the node\&. This is the simplest way but it uses up a lot of ip addresses since you have to assign both static and also public addresses to each node\&.
+.SS "NAT\-GW"
+.PP
+A second way is to use the built in NAT\-GW feature in CTDB\&. With NAT\-GW you assign one public NATGW address for each natgw group\&. Each NATGW group is a set of nodes in the cluster that shares the same NATGW address to talk to the outside world\&. Normally there would only be one NATGW group spanning the entire cluster, but in situations where one ctdb cluster spans multiple physical sites it is useful to have one NATGW group for each of the two sites\&.
+.PP
+There can be multiple NATGW groups in one cluster but each node can only be member of one NATGW group\&.
+.PP
+In each NATGW group, one of the nodes is designated the NAT Gateway through which all traffic that is originated by nodes in this group will be routed through if a public addresses are not available\&.
+.SS "Configuration"
+.PP
+NAT\-GW is configured in /etc/sysconfigctdb by setting the following variables:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# NAT\-GW configuration
+# Some services running on nthe CTDB node may need to originate traffic to
+# remote servers before the node is assigned any IP addresses,
+# This is problematic since before the node has public addresses the node might
+# not be able to route traffic to the public networks\&.
+# One solution is to have static public addresses assigned with routing
+# in addition to the public address interfaces, thus guaranteeing that
+# a node always can route traffic to the external network\&.
+# This is the most simple solution but it uses up a large number of 
+# additional ip addresses\&.
+#
+# A more complex solution is NAT\-GW\&.
+# In this mode we only need one additional ip address for the cluster from
+# the exsternal public network\&.
+# One of the nodes in the cluster is elected to be hosting this ip address
+# so it can reach the external services\&. This node is also configured
+# to use NAT MASQUERADING for all traffic from the internal private network
+# to the external network\&. This node is the NAT\-GW node\&.
+#
+# All other nodes are set up with a default rote with a metric of 10 to point
+# to the nat\-gw node\&.
+# 
+# The effect of this is that only when a node does not have a public address
+# and thus no proper routes to the external world it will instead
+# route all packets through the nat\-gw node\&.
+#
+# CTDB_NATGW_NODES is the list of nodes that belong to this natgw group\&.
+# You can have multiple natgw groups in one cluster but each node
+# can only belong to one single natgw group\&.
+#
+# CTDB_NATGW_PUBLIC_IP=10\&.0\&.0\&.227/24
+# CTDB_NATGW_PUBLIC_IFACE=eth0
+# CTDB_NATGW_DEFAULT_GATEWAY=10\&.0\&.0\&.1
+# CTDB_NATGW_PRIVATE_NETWORK=10\&.1\&.1\&.0/24
+# CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+#
+# Normally any node in the natgw group can act as the natgw master\&.
+# In some configurations you may have special nodes that is a part of the
+# cluster/natgw group, but where the node lacks connectivity to the 
+# public network\&.
+# For these cases, set this variable to make these nodes not able to
+# become natgw master\&.
+#
+# CTDB_NATGW_SLAVE_ONLY=yes
+    
+.fi
+.if n \{\
+.RE
+.\}
+.SS "CTDB_NATGW_PUBLIC_IP"
+.PP
+This is an ip address in the public network that is used for all outgoing traffic when the public addresses are not assigned\&. This address will be assigned to one of the nodes in the cluster which will masquerade all traffic for the other nodes\&.
+.PP
+Format of this parameter is IPADDRESS/NETMASK
+.SS "CTDB_NATGW_PUBLIC_IFACE"
+.PP
+This is the physical interface where the CTDB_NATGW_PUBLIC_IP will be assigned to\&. This should be an interface connected to the public network\&.
+.PP
+Format of this parameter is INTERFACE
+.SS "CTDB_NATGW_DEFAULT_GATEWAY"
+.PP
+This is the default gateway to use on the node that is elected to host the CTDB_NATGW_PUBLIC_IP\&. This is the default gateway on the public network\&.
+.PP
+Format of this parameter is IPADDRESS
+.SS "CTDB_NATGW_PRIVATE_NETWORK"
+.PP
+This is the network/netmask used for the interal private network\&.
+.PP
+Format of this parameter is IPADDRESS/NETMASK
+.SS "CTDB_NATGW_NODES"
+.PP
+This is the list of all nodes that belong to the same NATGW group as this node\&. The default is /etc/ctdb/natgw_nodes\&.
+.SS "Operation"
+.PP
+When the NAT\-GW functionality is used, one of the nodes is elected to act as a NAT router for all the other nodes in the group when they need to originate traffic to the external public network\&.
+.PP
+The NAT\-GW node is assigned the CTDB_NATGW_PUBLIC_IP to the designated interface and the provided default route\&. The NAT\-GW is configured to act as a router and to masquerade all traffic it receives from the internal private network and which is destined to the external network(s)\&.
+.PP
+All other nodes in the group are configured with a default route of metric 10 pointing to the designated NAT GW node\&.
+.PP
+This is implemented in the 11\&.natgw eventscript\&. Please see the eventscript for further information\&.
+.SS "Removing/Changing NATGW at runtime"
+.PP
+The following are the procedures to change/remove a NATGW configuration at runtime, without having to restart ctdbd\&.
+.PP
+If you want to remove NATGW completely from a node, use these steps:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+1, Run \'CTDB_BASE=/etc/ctdb /etc/ctdb/events\&.d/11\&.natgw removenatgw\'
+2, Then remove the configuration from /etc/sysconfig/ctdb
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+If you want to change the NATGW configuration on a node :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+1, Run \'CTDB_BASE=/etc/ctdb /etc/ctdb/events\&.d/11\&.natgw removenatgw\'
+2, Then change the configuration in /etc/sysconfig/ctdb
+3, Run \'CTDB_BASE=/etc/ctdb /etc/ctdb/events\&.d/11\&.natgw updatenatgw\'
+    
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NOTIFICATION SCRIPT"
+.PP
+Notification scripts are used with ctdb to have a call\-out from ctdb to a user\-specified script when certain state changes occur in ctdb\&. This is commonly to set up either sending SNMP traps or emails when a node becomes unhealthy and similar\&.
+.PP
+This is activated by setting CTDB_NOTIFY_SCRIPT=<your script> in the sysconfig file, or by adding \-\-notification\-script=<your script>\&.
+.PP
+See /etc/ctdb/notify\&.sh for an example script\&.
+.PP
+CTDB currently generates notifications on these state changes:
+.SS "unhealthy"
+.PP
+This call\-out is triggered when the node changes to UNHEALTHY state\&.
+.SS "healthy"
+.PP
+This call\-out is triggered when the node changes to HEALTHY state\&.
+.SS "startup"
+.PP
+This call\-out is triggered when ctdb has started up and all managed services are up and running\&.
+.SH "CLAMAV DAEMON"
+.PP
+CTDB has support to manage the popular anti\-virus daemon ClamAV\&. This support is implemented through the eventscript : /etc/ctdb/events\&.d/31\&.clamd\&.
+.SS "Configuration"
+.PP
+Start by configuring CLAMAV normally and test that it works\&. Once this is done, copy the configuration files over to all the nodes so that all nodes share identical CLAMAV configurations\&. Once this is done you can proceed with the intructions below to activate CTDB support for CLAMAV\&.
+.PP
+First, to activate CLAMAV support in CTDB, edit /etc/sysconfig/ctdb and add the two lines :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+CTDB_MANAGES_CLAMD=yes
+CTDB_CLAMD_SOCKET="/path/to/clamd\&.socket"
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Second, activate the eventscript
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ctdb enablescript 31\&.clamd
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Third, CTDB will now be starting and stopping this service accordingly, so make sure that the system is not configured to start/stop this service automatically\&. On RedHat systems you can disable the system starting/stopping CLAMAV automatically by running :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+chkconfig clamd off
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Once you have restarted CTDBD, use
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ctdb scriptstatus
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+and verify that the 31\&.clamd eventscript is listed and that it was executed successfully\&.
+.SH "SEE ALSO"
+.PP
+ctdb(1), onnode(1)
+\m[blue]\fB\%http://ctdb.samba.org/\fR\m[]
+.SH "COPYRIGHT/LICENSE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Copyright (C) Andrew Tridgell 2007
+Copyright (C) Ronnie sahlberg 2007
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version\&.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&.  See the GNU
+General Public License for more details\&.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www\&.gnu\&.org/licenses/\&.
+.fi
+.if n \{\
+.RE
+.\}

Added: branches/ctdb/squeeze-backports/doc/ctdbd.1.html
===================================================================
--- branches/ctdb/squeeze-backports/doc/ctdbd.1.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ctdbd.1.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,633 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" title="ctdbd"><a name="ctdbd.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd — The CTDB cluster daemon</p></div><div class="refsynopsisdiv" title="Synopsis"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdbd</code> </p></div><div class="cmdsynopsis"><p><code class="command">ctdbd</code>  [-? --help] [-d --debug=<INTEGER>] {--dbdir=<directory>} {--dbdir-persistent=<directory>} [--event-script-dir=<directory>] [-i --interactive] [--listen=<address>] [--logfile=<filename>] [--lvs] {--nlist=<filename>} [--no-lmaster] [--no-recmaster] [--nosetsched] {--notification-script=<filename>} [--public-addresses=<filename>] [--public-interface=<interface>] {--reclock=<filename>} [--single-public-ip=<address>] [--socket=<filename>] [--start-as-disabled] [--start-as-stopped] [--syslog] [--log-ringbuf-size=<num-entries>] [--torture] [--transport=<STRING>] [--usage]</p></div></div><div class="refsect1" title="DESCRIPTION"><a name="id424915"></a><h2>DESCRIPTION</h2><p>
+      ctdbd is the main ctdb daemon.
+    </p><p>
+      ctdbd provides a clustered version of the TDB database with automatic rebuild/recovery of the databases upon nodefailures.
+    </p><p>
+      Combined with a cluster filesystem ctdbd provides a full HA environment for services such as clustered Samba and NFS as well as other services.
+    </p><p>
+      ctdbd provides monitoring of all nodes in the cluster and automatically reconfigures the cluster and recovers upon node failures.
+    </p><p>
+      ctdbd is the main component in clustered Samba that provides a high-availability load-sharing CIFS server cluster.
+    </p></div><div class="refsect1" title="OPTIONS"><a name="id424942"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">-? --help</span></dt><dd><p>
+            Print some help text to the screen.
+          </p></dd><dt><span class="term">-d --debug=<DEBUGLEVEL></span></dt><dd><p>
+            This option sets the debuglevel on the ctdbd daemon which controls what will be written to the logfile. The default is 0 which will only log important events and errors. A larger number will provide additional logging.
+          </p></dd><dt><span class="term">--dbdir=<directory></span></dt><dd><p>
+            This is the directory on local storage where ctdbd keeps the local
+            copy of the TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem.
+          </p><p>
+            This directory would usually be /var/ctdb .
+          </p></dd><dt><span class="term">--dbdir-persistent=<directory></span></dt><dd><p>
+            This is the directory on local storage where ctdbd keeps the local
+            copy of the persistent TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem.
+          </p><p>
+            This directory would usually be /etc/ctdb/persistent .
+          </p></dd><dt><span class="term">--event-script-dir=<directory></span></dt><dd><p>
+            This option is used to specify the directory where the CTDB event
+	    scripts are stored.
+          </p><p>
+            This will normally be /etc/ctdb/events.d which is part of the ctdb distribution.
+          </p></dd><dt><span class="term">-i --interactive</span></dt><dd><p>
+            By default ctdbd will detach itself from the shell and run in
+            the background as a daemon. This option makes ctdbd to start in interactive mode.
+          </p></dd><dt><span class="term">--listen=<address></span></dt><dd><p>
+            This specifies which ip address ctdb will bind to. By default ctdbd will bind to the first address it finds in the /etc/ctdb/nodes file and which is also present on the local system in which case you do not need to provide this option.
+          </p><p>
+            This option is only required when you want to run multiple ctdbd daemons/nodes on the same physical host in which case there would be multiple entries in /etc/ctdb/nodes what would match a local interface.
+          </p></dd><dt><span class="term">--logfile=<filename></span></dt><dd><p>
+            This is the file where ctdbd will write its log. This is usually /var/log/log.ctdb .
+          </p></dd><dt><span class="term">--lvs</span></dt><dd><p>
+	  This option is used to activate the LVS capability on a CTDB node.
+	  Please see the LVS section.
+          </p></dd><dt><span class="term">--nlist=<filename></span></dt><dd><p>
+            This file contains a list of the private ip addresses of every node in the cluster. There is one line/ip address for each node. This file must be the same for all nodes in the cluster.
+          </p><p>
+            This file is usually /etc/ctdb/nodes .
+          </p></dd><dt><span class="term">--no-lmaster</span></dt><dd><p>
+	  This argument specifies that this node can NOT become an lmaster
+	  for records in the database. This means that it will never show up
+	  in the vnnmap. This feature is primarily used for making a cluster
+	span across a WAN link and use CTDB as a WAN-accelerator.
+          </p><p>
+	  Please see the "remote cluster nodes" section for more information.
+          </p></dd><dt><span class="term">--no-recmaster</span></dt><dd><p>
+	  This argument specifies that this node can NOT become a recmaster
+	  for the database. This feature is primarily used for making a cluster
+	span across a WAN link and use CTDB as a WAN-accelerator.
+          </p><p>
+	  Please see the "remote cluster nodes" section for more information.
+          </p></dd><dt><span class="term">--nosetsched</span></dt><dd><p>
+	    This is a ctdbd debugging option. this option is only used when
+	    debugging ctdbd.
+	  </p><p>
+            Normally ctdb will change its scheduler to run as a real-time 
+	    process. This is the default mode for a normal ctdbd operation
+	    to gurarantee that ctdbd always gets the cpu cycles that it needs.
+          </p><p>
+	    This option is used to tell ctdbd to NOT run as a real-time process
+	    and instead run ctdbd as a normal userspace process.
+	    This is useful for debugging and when you want to run ctdbd under
+	    valgrind or gdb. (You don't want to attach valgrind or gdb to a
+	    real-time process.)
+          </p></dd><dt><span class="term">--notification-script=<filename></span></dt><dd><p>
+	    This specifies a script which will be invoked by ctdb when certain
+	    state changes occur in ctdbd and when you may want to trigger this
+	    to run certain scripts.
+          </p><p>
+            This file is usually /etc/ctdb/notify.sh .
+          </p><p>
+	    See the NOTIFICATION SCRIPT section below for more information.
+          </p></dd><dt><span class="term">--public_addresses=<filename></span></dt><dd><p>
+            When used with IP takeover this specifies a file containing the public ip addresses to use on the cluster. This file contains a list of ip addresses netmasks and interfaces. When ctdb is operational it will distribute these public ip addresses evenly across the available nodes.
+          </p><p>
+            This is usually the file /etc/ctdb/public_addresses
+          </p></dd><dt><span class="term">--public-interface=<interface></span></dt><dd><p>
+            This option tells ctdb which interface to attach public-addresses
+	    to and also where to attach the single-public-ip when used.
+	    </p><p>
+	    This is only required when using public ip addresses and only when
+	    you don't specify the interface explicitly in /etc/ctdb/public_addresses or when you are using --single-public-ip.
+          </p><p>
+	  If you omit this argument when using public addresses or single public ip, ctdb will not be able to send out Gratious ARPs correctly or be able to kill tcp connections correctly which will lead to application failures. 
+          </p></dd><dt><span class="term">--reclock=<filename></span></dt><dd><p>
+            This is the name of the lock file stored of the shared cluster filesystem that ctdbd uses to prevent split brains from occuring.
+            This file must be stored on shared storage.
+          </p><p>
+	    It is possible to run CTDB without a reclock file, but then there 
+	    will be no protection against split brain if the network becomes
+	    partitioned. Using CTDB without a reclock file is strongly
+	    discouraged.
+          </p></dd><dt><span class="term">--socket=<filename></span></dt><dd><p>
+            This specifies the name of the domain socket that ctdbd will create. This socket is used for local clients to attach to and communicate with the ctdbd daemon.
+          </p><p>
+            The default is /tmp/ctdb.socket . You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host.
+          </p></dd><dt><span class="term">--start-as-disabled</span></dt><dd><p>
+	  This makes the ctdb daemon to be DISABLED when it starts up.
+          </p><p>
+	  As it is DISABLED it will not get any of the public ip addresses
+	  allocated to it, and thus this allow you to start ctdb on a node 
+	  without causing any ip address to failover from other nodes onto
+	  the new node.
+          </p><p>
+	  When used, the administrator must keep track of when nodes start and
+	  manually enable them again using the "ctdb enable" command, or else
+	  the node will not host any services.
+          </p><p>
+	  A node that is DISABLED will not host any services and will not be
+	  reachable/used by any clients.
+          </p></dd><dt><span class="term">--start-as-stopped</span></dt><dd><p>
+	  This makes the ctdb daemon to be STOPPED when it starts up.
+          </p><p>
+	  A node that is STOPPED does not host any public addresses. It is not part of the VNNMAP so it does act as an LMASTER. It also has all databases locked in recovery mode until restarted.
+          </p><p>
+	  To restart and activate a STOPPED node, the command "ctdb continue" is used.
+          </p><p>
+	  A node that is STOPPED will not host any services and will not be
+	  reachable/used by any clients.
+          </p></dd><dt><span class="term">--syslog</span></dt><dd><p>
+	    Send all log messages to syslog instead of to the ctdb logfile.
+          </p></dd><dt><span class="term">--log-ringbuf-size=<num-entries></span></dt><dd><p>
+	    In addition to the normal loggign to a log file,
+	    CTDBD also keeps a in-memory ringbuffer containing the most recent
+	    log entries for all log levels (except DEBUG).
+          </p><p>
+	    This is useful since it allows for keeping continuous logs to a file
+	    at a reasonable non-verbose level, but shortly after an incident has
+	    occured, a much more detailed log can be pulled from memory. This
+	    can allow you to avoid having to reproduce an issue due to the
+	    on-disk logs being of insufficient detail.
+          </p><p>
+	    This in-memory ringbuffer contains a fixed number of the most recent
+	    entries. This is settable at startup either through the
+	    --log-ringbuf-size argument, or preferably by using
+	    CTDB_LOG_RINGBUF_SIZE in the sysconfig file.
+          </p><p>
+	    Use the "ctdb getlog" command to access this log.
+          </p></dd><dt><span class="term">--torture</span></dt><dd><p>
+            This option is only used for development and testing of ctdbd. It adds artificial errors and failures to the common codepaths in ctdbd to verify that ctdbd can recover correctly for failures.
+          </p><p>
+            You do NOT want to use this option unless you are developing and testing new functionality in ctdbd.
+          </p></dd><dt><span class="term">--transport=<STRING></span></dt><dd><p>
+            This option specifies which transport to use for ctdbd internode communications. The default is "tcp".
+          </p><p>
+            Currently only "tcp" is supported but "infiniband" might be
+	    implemented in the future.
+          </p></dd><dt><span class="term">--usage</span></dt><dd><p>
+            Print useage information to the screen.
+          </p></dd></dl></div></div><div class="refsect1" title="Private vs Public addresses"><a name="id382958"></a><h2>Private vs Public addresses</h2><p>
+      When used for ip takeover in a HA environment, each node in a ctdb 
+      cluster has multiple ip addresses assigned to it. One private and one or more public.
+    </p><div class="refsect2" title="Private address"><a name="id382967"></a><h3>Private address</h3><p>
+        This is the physical ip address of the node which is configured in 
+        linux and attached to a physical interface. This address uniquely
+        identifies a physical node in the cluster and is the ip addresses
+        that ctdbd will use to communicate with the ctdbd daemons on the
+        other nodes in the cluster.
+      </p><p>
+        The private addresses are configured in /etc/ctdb/nodes 
+        (unless the --nlist option is used) and contain one line for each 
+        node in the cluster. Each line contains the private ip address for one
+        node in the cluster. This file must be the same on all nodes in the
+	cluster.
+      </p><p>
+        Since the private addresses are only available to the network when the
+        corresponding node is up and running you should not use these addresses
+        for clients to connect to services provided by the cluster. Instead
+        client applications should only attach to the public addresses since
+        these are guaranteed to always be available.
+      </p><p>
+        When using ip takeover, it is strongly recommended that the private 
+	addresses are configured on a private network physically separated
+	from the rest of the network and that this private network is dedicated
+	to CTDB traffic.
+      </p>
+      Example /etc/ctdb/nodes for a four node cluster:
+      <pre class="screen">
+        10.1.1.1
+        10.1.1.2
+        10.1.1.3
+        10.1.1.4
+      </pre></div><div class="refsect2" title="Public address"><a name="id383002"></a><h3>Public address</h3><p>
+        A public address on the other hand is not attached to an interface.
+        This address is managed by ctdbd itself and is attached/detached to
+        a physical node at runtime.
+      </p><p>
+        The ctdb cluster will assign/reassign these public addresses across the
+        available healthy nodes in the cluster. When one node fails, its public address
+        will be migrated to and taken over by a different node in the cluster
+        to ensure that all public addresses are always available to clients as 
+	long as there are still nodes available capable of hosting this address.
+      </p><p>
+        These addresses are not physically attached to a specific node. 
+        The 'ctdb ip' command can be used to view the current assignment of 
+        public addresses and which physical node is currently serving it.
+      </p><p>
+	On each node this file contains a list of the public addresses that 
+	this node is capable of hosting.
+        The list also contain the netmask and the 
+	interface where this address should be attached for the case where you
+	may want to serve data out through multiple different interfaces.
+      </p>
+      Example /etc/ctdb/public_addresses for a node that can host 4 public addresses:
+      <pre class="screen">
+        11.1.1.1/24 eth0
+        11.1.1.2/24 eth0
+        11.1.2.1/24 eth1
+        11.1.2.2/24 eth1
+      </pre><p>
+	In most cases this file would be the same on all nodes in a cluster but
+	there are exceptions when one may want to use different files
+	on different nodes.
+	</p>
+	Example: 4 nodes partitioned into two subgroups :
+	<pre class="screen">
+	Node 0:/etc/ctdb/public_addresses
+		10.1.1.1/24 eth0
+		10.1.1.2/24 eth0
+
+	Node 1:/etc/ctdb/public_addresses
+		10.1.1.1/24 eth0
+		10.1.1.2/24 eth0
+
+	Node 2:/etc/ctdb/public_addresses
+		10.2.1.1/24 eth0
+		10.2.1.2/24 eth0
+
+	Node 3:/etc/ctdb/public_addresses
+		10.2.1.1/24 eth0
+		10.2.1.2/24 eth0
+	</pre><p>
+	In this example nodes 0 and 1 host two public addresses on the 
+	10.1.1.x network  while nodes 2 and 3 host two public addresses for the 
+	10.2.1.x network.
+	</p><p>
+	Ip address 10.1.1.1 can be hosted by either of nodes 0 or 1 and will be
+	available to clients as long as at least one of these two nodes are
+	available.
+	If both nodes 0 and node 1 become unavailable 10.1.1.1 also becomes 
+	unavailable. 10.1.1.1 can not be failed over to node 2 or node 3 since
+	these nodes do not have this ip address listed in their public
+	addresses file.
+	</p></div></div><div class="refsect1" title="Node status"><a name="id383063"></a><h2>Node status</h2><p>
+      The current status of each node in the cluster can be viewed by the 
+      'ctdb status' command.
+    </p><p>
+      There are five possible states for a node.
+    </p><p>
+      OK - This node is fully functional.
+    </p><p>
+      DISCONNECTED - This node could not be connected through the network 
+      and is currently not particpating in the cluster. If there is a 
+      public IP address associated with this node it should have been taken 
+      over by a different node. No services are running on this node.
+    </p><p>
+      DISABLED - This node has been administratively disabled. This node is 
+      still functional and participates in the CTDB cluster but its IP 
+      addresses have been taken over by a different node and no services are 
+      currently being hosted.
+    </p><p>
+      UNHEALTHY - A service provided by this node is malfunctioning and should 
+      be investigated. The CTDB daemon itself is operational and participates 
+      in the cluster. Its public IP address has been taken over by a different 
+      node and no services are currently being hosted. All unhealthy nodes 
+      should be investigated and require an administrative action to rectify.
+    </p><p>
+      BANNED - This node failed too many recovery attempts and has been banned 
+      from participating in the cluster for a period of RecoveryBanPeriod 
+      seconds. Any public IP address has been taken over by other nodes. This 
+      node does not provide any services. All banned nodes should be 
+      investigated and require an administrative action to rectify. This node 
+      does not perticipate in the CTDB cluster but can still be communicated 
+      with. I.e. ctdb commands can be sent to it.
+    </p><p>
+      STOPPED - A node that is stopped does not host any public ip addresses,
+      nor is it part of the VNNMAP. A stopped node can not become LVSMASTER,
+      RECMASTER or NATGW.
+      This node does not perticipate in the CTDB cluster but can still be
+      communicated with. I.e. ctdb commands can be sent to it.
+    </p></div><div class="refsect1" title="PUBLIC TUNABLES"><a name="id383111"></a><h2>PUBLIC TUNABLES</h2><p>
+    These are the public tuneables that can be used to control how ctdb behaves.
+    </p><div class="refsect2" title="KeepaliveInterval"><a name="id383121"></a><h3>KeepaliveInterval</h3><p>Default: 1</p><p>
+    How often should the nodes send keepalives to eachother.
+    </p></div><div class="refsect2" title="KeepaliveLimit"><a name="id383133"></a><h3>KeepaliveLimit</h3><p>Default: 5</p><p>
+    After how many keepalive intervals without any traffic should a node
+    wait until marking the peer as DISCONNECTED.
+    </p></div><div class="refsect2" title="MonitorInterval"><a name="id383147"></a><h3>MonitorInterval</h3><p>Default: 15</p><p>
+    How often should ctdb run the event scripts to check for a nodes health.
+    </p></div><div class="refsect2" title="TickleUpdateInterval"><a name="id383160"></a><h3>TickleUpdateInterval</h3><p>Default: 20</p><p>
+    How often will ctdb record and store the "tickle" information used to
+    kickstart stalled tcp connections after a recovery.
+    </p></div><div class="refsect2" title="EventScriptTimeout"><a name="id383173"></a><h3>EventScriptTimeout</h3><p>Default: 20</p><p>
+    How long should ctdb let an event script run before aborting it and
+    marking the node unhealthy.
+    </p></div><div class="refsect2" title="RecoveryBanPeriod"><a name="id383186"></a><h3>RecoveryBanPeriod</h3><p>Default: 300</p><p>
+    If a node becomes banned causing repetitive recovery failures. The node will
+    eventually become banned from the cluster.
+    This controls how long the culprit node will be banned from the cluster
+    before it is allowed to try to join the cluster again.
+    Don't set to small. A node gets banned for a reason and it is usually due
+    to real problems with the node.
+    </p></div><div class="refsect2" title="DatabaseHashSize"><a name="id383202"></a><h3>DatabaseHashSize</h3><p>Default: 100000</p><p>
+    Size of the hash chains for the local store of the tdbs that ctdb manages.
+    </p></div><div class="refsect2" title="RerecoveryTimeout"><a name="id383215"></a><h3>RerecoveryTimeout</h3><p>Default: 10</p><p>
+    Once a recovery has completed, no additional recoveries are permitted until this timeout has expired.
+    </p></div><div class="refsect2" title="EnableBans"><a name="id383228"></a><h3>EnableBans</h3><p>Default: 1</p><p>
+    When set to 0, this disables BANNING completely in the cluster and thus nodes can not get banned, even it they break. Don't set to 0.
+    </p></div><div class="refsect2" title="DeterministicIPs"><a name="id383242"></a><h3>DeterministicIPs</h3><p>Default: 1</p><p>
+    When enabled, this tunable makes ctdb try to keep public IP addresses locked to specific nodes as far as possible. This makes it easier for debugging since you can know that as long as all nodes are healthy public IP X will always be hosted by node Y. 
+    </p><p>
+    The cost of using deterministic IP address assignment is that it disables part of the logic where ctdb tries to reduce the number of public IP assignment changes in the cluster. This tunable may increase the number of IP failover/failbacks that are performed on the cluster by a small margin.
+    </p></div><div class="refsect2" title="DisableWhenUnhealthy"><a name="id383262"></a><h3>DisableWhenUnhealthy</h3><p>Default: 0</p><p>
+    When set, As soon as a node becomes unhealthy, that node will also automatically become permanently DISABLED. Once a node is DISABLED, the only way to make it participate in the cluster again and host services is by manually enabling the node again using 'ctdb enable'. 
+    </p><p>
+    This disables parts of the resilience and robustness of the cluster and should ONLY be used when the system administrator is actively monitoring the cluster, so that nodes can be enabled again.
+    </p></div><div class="refsect2" title="NoIPFailback"><a name="id383282"></a><h3>NoIPFailback</h3><p>Default: 0</p><p>
+    When set to 1, ctdb will not perform failback of IP addresses when a node becomes healthy. Ctdb WILL perform failover of public IP addresses when a node becomes UNHEALTHY, but when the node becomes HEALTHY again, ctdb will not fail the addresses back.
+    </p><p>
+    Use with caution! Normally when a node becomes available to the cluster
+ctdb will try to reassign public IP addresses onto the new node as a way to distribute the workload evenly across the clusternode. Ctdb tries to make sure that all running nodes have approximately the same number of public addresses it hosts.
+    </p><p>
+    When you enable this tunable, CTDB will no longer attempt to rebalance the cluster by failing IP addresses back to the new nodes. An unbalanced cluster will therefore remain unbalanced until there is manual intervention from the administrator. When this parameter is set, you can manually fail public IP addresses over to the new node(s) using the 'ctdb moveip' command.
+    </p></div></div><div class="refsect1" title="LVS"><a name="id383310"></a><h2>LVS</h2><p>
+    LVS is a mode where CTDB presents one single IP address for the entire
+    cluster. This is an alternative to using public IP addresses and round-robin
+    DNS to loadbalance clients across the cluster.
+    </p><p>
+    This is similar to using a layer-4 loadbalancing switch but with some restrictions.
+    </p><p>
+    In this mode the cluster select a set of nodes in the cluster and loadbalance
+    all client access to the LVS address across this set of nodes. This set of nodes are all LVS capable nodes that are HEALTHY, or if no HEALTHY nodes exists
+    all LVS capable nodes regardless of health status.
+    LVS will however never loadbalance traffic to nodes that are BANNED,
+    STOPPED, DISABLED or DISCONNECTED. The "ctdb lvs" command is used to show
+    which nodes are currently load-balanced across.
+    </p><p>
+    One of the these nodes are elected as the LVSMASTER. This node receives all
+    traffic from clients coming in to the LVS address and multiplexes it
+    across the internal network to one of the nodes that LVS is using.
+    When responding to the client, that node will send the data back
+    directly to the client, bypassing the LVSMASTER node.
+    The command "ctdb lvsmaster" will show which node is the current
+    LVSMASTER.
+    </p><p>
+    The path used for a client i/o is thus :
+    </p><pre class="screen">
+	(1) Client sends request packet to LVSMASTER
+	(2) LVSMASTER passes the request on to one node across the internal network.
+	(3) Selected node processes the request.
+	(4) Node responds back to client.
+    </pre><p>
+    </p><p> 
+    This means that all incoming traffic to the cluster will pass through
+    one physical node, which limits scalability. You can send more data to the
+    LVS address that one physical node can multiplex. This means that you 
+    should not use LVS if your I/O pattern is write-intensive since you will be
+    limited in the available network bandwidth that node can handle.
+    LVS does work wery well for read-intensive workloads where only smallish
+    READ requests are going through the LVSMASTER bottleneck and the majority
+    of the traffic volume (the data in the read replies) goes straight from
+    the processing node back to the clients. For read-intensive i/o patterns you can acheive very high throughput rates in this mode.
+    </p><p>
+    Note: you can use LVS and public addresses at the same time.
+    </p><div class="refsect2" title="Configuration"><a name="id383366"></a><h3>Configuration</h3><p>
+    To activate LVS on a CTDB node you must specify CTDB_PUBLIC_INTERFACE and 
+    CTDB_LVS_PUBLIC_ADDRESS in /etc/sysconfig/ctdb.
+	</p><p>
+You must also specify the "--lvs" command line argument to ctdbd to activate LVS as a capability of the node. This should be done automatically for you by the /etc/init.d/ctdb script.
+	</p><p>
+	Example:
+    </p><pre class="screen">
+	CTDB_PUBLIC_INTERFACE=eth0
+	CTDB_LVS_PUBLIC_IP=10.0.0.237
+	</pre><p>
+	</p></div><p>
+    If you use LVS, you must still have a real/permanent address configured
+    for the public interface on each node. This address must be routable
+    and the cluster nodes must be configured so that all traffic back to client
+    hosts are routed through this interface. This is also required in order
+    to allow samba/winbind on the node to talk to the domain controller.
+    (we can not use the lvs IP address to initiate outgoing traffic)
+    </p><p>
+    I.e. make sure that you can "ping" both the domain controller and also
+    all of the clients from the node BEFORE you enable LVS. Also make sure
+    that when you ping these hosts that the traffic is routed out through the
+    eth0 interface.
+    </p></div><div class="refsect1" title="REMOTE CLUSTER NODES"><a name="id383403"></a><h2>REMOTE CLUSTER NODES</h2><p>
+It is possible to have a CTDB cluster that spans across a WAN link. 
+For example where you have a CTDB cluster in your datacentre but you also
+want to have one additional CTDB node located at a remote branch site.
+This is similar to how a WAN accelerator works but with the difference 
+that while a WAN-accelerator often acts as a Proxy or a MitM, in 
+the ctdb remote cluster node configuration the Samba instance at the remote site
+IS the genuine server, not a proxy and not a MitM, and thus provides 100%
+correct CIFS semantics to clients.
+    </p><p>
+	See the cluster as one single multihomed samba server where one of
+	the NICs (the remote node) is very far away.
+    </p><p>
+	NOTE: This does require that the cluster filesystem you use can cope
+	with WAN-link latencies. Not all cluster filesystems can handle
+	WAN-link latencies! Whether this will provide very good WAN-accelerator
+	performance or it will perform very poorly depends entirely
+	on how optimized your cluster filesystem is in handling high latency
+	for data and metadata operations.
+    </p><p>
+	To activate a node as being a remote cluster node you need to set
+	the following two parameters in /etc/sysconfig/ctdb  for the remote node:
+        </p><pre class="screen">
+CTDB_CAPABILITY_LMASTER=no
+CTDB_CAPABILITY_RECMASTER=no
+	</pre><p>
+    </p><p>
+	Verify with the command "ctdb getcapabilities" that that node no longer
+	has the recmaster or the lmaster capabilities.
+    </p></div><div class="refsect1" title="NAT-GW"><a name="id383442"></a><h2>NAT-GW</h2><p>
+      Sometimes it is desireable to run services on the CTDB node which will
+      need to originate outgoing traffic to external servers. This might
+      be contacting NIS servers, LDAP servers etc. etc.
+    </p><p>
+      This can sometimes be problematic since there are situations when a
+      node does not have any public ip addresses assigned. This could
+      be due to the nobe just being started up and no addresses have been
+      assigned yet or it could be that the node is UNHEALTHY in which
+      case all public addresses have been migrated off.
+    </p><p>
+      If then the service status of CTDB depends on such services being
+      able to always being able to originate traffic to external resources
+      this becomes extra troublesome. The node might be UNHEALTHY because
+      the service can not be reached, and the service can not be reached
+      because the node is UNHEALTHY.
+    </p><p>
+      There are two ways to solve this problem. The first is by assigning a
+      static ip address for one public interface on every node which will allow
+      every node to be able to route traffic to the public network even
+      if there are no public addresses assigned to the node.
+      This is the simplest way but it uses up a lot of ip addresses since you
+      have to assign both static and also public addresses to each node.
+    </p><div class="refsect2" title="NAT-GW"><a name="id426195"></a><h3>NAT-GW</h3><p>
+      A second way is to use the built in NAT-GW feature in CTDB.
+      With NAT-GW you assign one public NATGW address for each natgw group.
+      Each NATGW group is a set of nodes in the cluster that shares the same
+      NATGW address to talk to the outside world. Normally there would only be
+      one NATGW group spanning the entire cluster, but in situations where one
+      ctdb cluster spans multiple physical sites it is useful to have one
+      NATGW group for each of the two sites.
+    </p><p>
+      There can be multiple NATGW groups in one cluster but each node can only
+      be member of one NATGW group.
+    </p><p>
+      In each NATGW group, one of the nodes is designated the NAT Gateway
+      through which all traffic that is originated by nodes in this group
+      will be routed through if a public addresses are not available. 
+    </p></div><div class="refsect2" title="Configuration"><a name="id426217"></a><h3>Configuration</h3><p>
+      NAT-GW is configured in /etc/sysconfigctdb by setting the following
+      variables:
+    </p><pre class="screen">
+# NAT-GW configuration
+# Some services running on nthe CTDB node may need to originate traffic to
+# remote servers before the node is assigned any IP addresses,
+# This is problematic since before the node has public addresses the node might
+# not be able to route traffic to the public networks.
+# One solution is to have static public addresses assigned with routing
+# in addition to the public address interfaces, thus guaranteeing that
+# a node always can route traffic to the external network.
+# This is the most simple solution but it uses up a large number of 
+# additional ip addresses.
+#
+# A more complex solution is NAT-GW.
+# In this mode we only need one additional ip address for the cluster from
+# the exsternal public network.
+# One of the nodes in the cluster is elected to be hosting this ip address
+# so it can reach the external services. This node is also configured
+# to use NAT MASQUERADING for all traffic from the internal private network
+# to the external network. This node is the NAT-GW node.
+#
+# All other nodes are set up with a default rote with a metric of 10 to point
+# to the nat-gw node.
+# 
+# The effect of this is that only when a node does not have a public address
+# and thus no proper routes to the external world it will instead
+# route all packets through the nat-gw node.
+#
+# CTDB_NATGW_NODES is the list of nodes that belong to this natgw group.
+# You can have multiple natgw groups in one cluster but each node
+# can only belong to one single natgw group.
+#
+# CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
+# CTDB_NATGW_PUBLIC_IFACE=eth0
+# CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
+# CTDB_NATGW_PRIVATE_NETWORK=10.1.1.0/24
+# CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+#
+# Normally any node in the natgw group can act as the natgw master.
+# In some configurations you may have special nodes that is a part of the
+# cluster/natgw group, but where the node lacks connectivity to the 
+# public network.
+# For these cases, set this variable to make these nodes not able to
+# become natgw master.
+#
+# CTDB_NATGW_SLAVE_ONLY=yes
+    </pre></div><div class="refsect2" title="CTDB_NATGW_PUBLIC_IP"><a name="id426266"></a><h3>CTDB_NATGW_PUBLIC_IP</h3><p>
+      This is an ip address in the public network that is used for all outgoing
+      traffic when the public addresses are not assigned.
+      This address will be assigned to one of the nodes in the cluster which
+      will masquerade all traffic for the other nodes.
+    </p><p>
+      Format of this parameter is IPADDRESS/NETMASK
+    </p></div><div class="refsect2" title="CTDB_NATGW_PUBLIC_IFACE"><a name="id426280"></a><h3>CTDB_NATGW_PUBLIC_IFACE</h3><p>
+      This is the physical interface where the CTDB_NATGW_PUBLIC_IP will be
+      assigned to. This should be an interface connected to the public network.
+    </p><p>
+      Format of this parameter is INTERFACE
+    </p></div><div class="refsect2" title="CTDB_NATGW_DEFAULT_GATEWAY"><a name="id426293"></a><h3>CTDB_NATGW_DEFAULT_GATEWAY</h3><p>
+      This is the default gateway to use on the node that is elected to host
+      the CTDB_NATGW_PUBLIC_IP. This is the default gateway on the public network.
+    </p><p>
+      Format of this parameter is IPADDRESS
+    </p></div><div class="refsect2" title="CTDB_NATGW_PRIVATE_NETWORK"><a name="id426306"></a><h3>CTDB_NATGW_PRIVATE_NETWORK</h3><p>
+      This is the network/netmask used for the interal private network.
+    </p><p>
+      Format of this parameter is IPADDRESS/NETMASK
+    </p></div><div class="refsect2" title="CTDB_NATGW_NODES"><a name="id426319"></a><h3>CTDB_NATGW_NODES</h3><p>
+      This is the list of all nodes that belong to the same NATGW group
+      as this node. The default is /etc/ctdb/natgw_nodes.
+    </p></div><div class="refsect2" title="Operation"><a name="id426329"></a><h3>Operation</h3><p>
+      When the NAT-GW functionality is used, one of the nodes is elected
+      to act as a NAT router for all the other nodes in the group when
+      they need to originate traffic to the external public network.
+    </p><p>
+      The NAT-GW node is assigned the CTDB_NATGW_PUBLIC_IP to the designated
+      interface and the provided default route. The NAT-GW is configured
+      to act as a router and to masquerade all traffic it receives from the
+      internal private network and which is destined to the external network(s).
+    </p><p>
+      All other nodes in the group are configured with a default route of
+      metric 10 pointing to the designated NAT GW node.
+    </p><p>
+      This is implemented in the 11.natgw eventscript. Please see the
+      eventscript for further information.
+    </p></div><div class="refsect2" title="Removing/Changing NATGW at runtime"><a name="id426354"></a><h3>Removing/Changing NATGW at runtime</h3><p>
+      The following are the procedures to change/remove a NATGW configuration 
+      at runtime, without having to restart ctdbd.
+    </p><p>
+      If you want to remove NATGW completely from a node, use these steps:
+    </p><pre class="screen">
+1, Run 'CTDB_BASE=/etc/ctdb /etc/ctdb/events.d/11.natgw removenatgw'
+2, Then remove the configuration from /etc/sysconfig/ctdb
+    </pre><p>
+      If you want to change the NATGW configuration on a node :
+    </p><pre class="screen">
+1, Run 'CTDB_BASE=/etc/ctdb /etc/ctdb/events.d/11.natgw removenatgw'
+2, Then change the configuration in /etc/sysconfig/ctdb
+3, Run 'CTDB_BASE=/etc/ctdb /etc/ctdb/events.d/11.natgw updatenatgw'
+    </pre></div></div><div class="refsect1" title="NOTIFICATION SCRIPT"><a name="id426385"></a><h2>NOTIFICATION SCRIPT</h2><p>
+      Notification scripts are used with ctdb to have a call-out from ctdb
+      to a user-specified script when certain state changes occur in ctdb.
+      This is commonly to set up either sending SNMP traps or emails
+      when a node becomes unhealthy and similar.
+    </p><p>
+      This is activated by setting CTDB_NOTIFY_SCRIPT=<your script> in the
+	sysconfig file, or by adding --notification-script=<your script>.
+    </p><p>
+      See /etc/ctdb/notify.sh for an example script.
+    </p><p>
+      CTDB currently generates notifications on these state changes:
+    </p><div class="refsect2" title="unhealthy"><a name="id426409"></a><h3>unhealthy</h3><p>
+      This call-out is triggered when the node changes to UNHEALTHY state.
+    </p></div><div class="refsect2" title="healthy"><a name="id426418"></a><h3>healthy</h3><p>
+      This call-out is triggered when the node changes to HEALTHY state.
+    </p></div><div class="refsect2" title="startup"><a name="id426427"></a><h3>startup</h3><p>
+      This call-out is triggered when ctdb has started up and all managed services are up and running.
+    </p></div></div><div class="refsect1" title="ClamAV Daemon"><a name="id426438"></a><h2>ClamAV Daemon</h2><p>
+CTDB has support to manage the popular anti-virus daemon ClamAV.
+This support is implemented through the
+eventscript : /etc/ctdb/events.d/31.clamd.
+</p><div class="refsect2" title="Configuration"><a name="id426447"></a><h3>Configuration</h3><p>
+Start by configuring CLAMAV normally and test that it works. Once this is
+done, copy the configuration files over to all the nodes so that all nodes
+share identical CLAMAV configurations.
+Once this is done you can proceed with the intructions below to activate
+CTDB support for CLAMAV.
+</p><p>
+First, to activate CLAMAV support in CTDB, edit /etc/sysconfig/ctdb and add the two lines :
+</p><pre class="screen">
+CTDB_MANAGES_CLAMD=yes
+CTDB_CLAMD_SOCKET="/path/to/clamd.socket"
+</pre><p>
+Second, activate the eventscript
+</p><pre class="screen">
+ctdb enablescript 31.clamd
+</pre><p>
+Third, CTDB will now be starting and stopping this service accordingly,
+so make sure that the system is not configured to start/stop this service
+automatically.
+On RedHat systems you can disable the system starting/stopping CLAMAV automatically by running :
+</p><pre class="screen">
+chkconfig clamd off
+</pre><p>
+</p><p>
+Once you have restarted CTDBD, use
+</p><pre class="screen">
+ctdb scriptstatus
+</pre><p>
+and verify that the 31.clamd eventscript is listed and that it was executed successfully.
+</p></div></div><div class="refsect1" title="SEE ALSO"><a name="id426497"></a><h2>SEE ALSO</h2><p>
+      ctdb(1), onnode(1)
+      <a class="ulink" href="http://ctdb.samba.org/" target="_top">http://ctdb.samba.org/</a>
+    </p></div><div class="refsect1" title="COPYRIGHT/LICENSE"><a name="id426509"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
+Copyright (C) Andrew Tridgell 2007<br>
+Copyright (C) Ronnie sahlberg 2007<br>
+<br>
+This program is free software; you can redistribute it and/or modify<br>
+it under the terms of the GNU General Public License as published by<br>
+the Free Software Foundation; either version 3 of the License, or (at<br>
+your option) any later version.<br>
+<br>
+This program is distributed in the hope that it will be useful, but<br>
+WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
+General Public License for more details.<br>
+<br>
+You should have received a copy of the GNU General Public License<br>
+along with this program; if not, see http://www.gnu.org/licenses/.<br>
+</p></div></div></div></body></html>

Added: branches/ctdb/squeeze-backports/doc/ctdbd.1.xml
===================================================================
--- branches/ctdb/squeeze-backports/doc/ctdbd.1.xml	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ctdbd.1.xml	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1134 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="ctdbd.1">
+
+<refmeta>
+	<refentrytitle>ctdbd</refentrytitle>
+	<manvolnum>1</manvolnum>
+	<refmiscinfo class="source">ctdb</refmiscinfo>
+	<refmiscinfo class="manual">CTDB - clustered TDB database</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+	<refname>ctdbd</refname>
+	<refpurpose>The CTDB cluster daemon</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+	<cmdsynopsis>
+		<command>ctdbd</command>
+	</cmdsynopsis>
+	
+	<cmdsynopsis>
+		<command>ctdbd</command>
+		<arg choice="opt">-? --help</arg>
+		<arg choice="opt">-d --debug=<INTEGER></arg>
+		<arg choice="req">--dbdir=<directory></arg>
+		<arg choice="req">--dbdir-persistent=<directory></arg>
+		<arg choice="opt">--event-script-dir=<directory></arg>
+		<arg choice="opt">-i --interactive</arg>
+		<arg choice="opt">--listen=<address></arg>
+		<arg choice="opt">--logfile=<filename></arg>
+		<arg choice="opt">--lvs</arg>
+		<arg choice="req">--nlist=<filename></arg>
+		<arg choice="opt">--no-lmaster</arg>
+		<arg choice="opt">--no-recmaster</arg>
+		<arg choice="opt">--nosetsched</arg>
+		<arg choice="req">--notification-script=<filename></arg>
+		<arg choice="opt">--public-addresses=<filename></arg>
+		<arg choice="opt">--public-interface=<interface></arg>
+		<arg choice="req">--reclock=<filename></arg>
+		<arg choice="opt">--single-public-ip=<address></arg>
+		<arg choice="opt">--socket=<filename></arg>
+		<arg choice="opt">--start-as-disabled</arg>
+		<arg choice="opt">--start-as-stopped</arg>
+		<arg choice="opt">--syslog</arg>
+		<arg choice="opt">--log-ringbuf-size=<num-entries></arg>
+		<arg choice="opt">--torture</arg>
+		<arg choice="opt">--transport=<STRING></arg>
+		<arg choice="opt">--usage</arg>
+	</cmdsynopsis>
+	
+</refsynopsisdiv>
+
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      ctdbd is the main ctdb daemon.
+    </para>
+    <para>
+      ctdbd provides a clustered version of the TDB database with automatic rebuild/recovery of the databases upon nodefailures.
+    </para>
+    <para>
+      Combined with a cluster filesystem ctdbd provides a full HA environment for services such as clustered Samba and NFS as well as other services.
+    </para>
+    <para>
+      ctdbd provides monitoring of all nodes in the cluster and automatically reconfigures the cluster and recovers upon node failures.
+    </para>
+    <para>
+      ctdbd is the main component in clustered Samba that provides a high-availability load-sharing CIFS server cluster.
+    </para>
+  </refsect1>
+
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist>
+      <varlistentry><term>-? --help</term>
+        <listitem>
+          <para>
+            Print some help text to the screen.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-d --debug=<DEBUGLEVEL></term>
+        <listitem>
+          <para>
+            This option sets the debuglevel on the ctdbd daemon which controls what will be written to the logfile. The default is 0 which will only log important events and errors. A larger number will provide additional logging.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--dbdir=<directory></term>
+        <listitem>
+          <para>
+            This is the directory on local storage where ctdbd keeps the local
+            copy of the TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem.
+          </para>
+          <para>
+            This directory would usually be /var/ctdb .
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--dbdir-persistent=<directory></term>
+        <listitem>
+          <para>
+            This is the directory on local storage where ctdbd keeps the local
+            copy of the persistent TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem.
+          </para>
+          <para>
+            This directory would usually be /etc/ctdb/persistent .
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--event-script-dir=<directory></term>
+        <listitem>
+          <para>
+            This option is used to specify the directory where the CTDB event
+	    scripts are stored.
+          </para>
+          <para>
+            This will normally be /etc/ctdb/events.d which is part of the ctdb distribution.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-i --interactive</term>
+        <listitem>
+          <para>
+            By default ctdbd will detach itself from the shell and run in
+            the background as a daemon. This option makes ctdbd to start in interactive mode.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--listen=<address></term>
+        <listitem>
+          <para>
+            This specifies which ip address ctdb will bind to. By default ctdbd will bind to the first address it finds in the /etc/ctdb/nodes file and which is also present on the local system in which case you do not need to provide this option.
+          </para>
+          <para>
+            This option is only required when you want to run multiple ctdbd daemons/nodes on the same physical host in which case there would be multiple entries in /etc/ctdb/nodes what would match a local interface.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--logfile=<filename></term>
+        <listitem>
+          <para>
+            This is the file where ctdbd will write its log. This is usually /var/log/log.ctdb .
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--lvs</term>
+        <listitem>
+          <para>
+	  This option is used to activate the LVS capability on a CTDB node.
+	  Please see the LVS section.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--nlist=<filename></term>
+        <listitem>
+          <para>
+            This file contains a list of the private ip addresses of every node in the cluster. There is one line/ip address for each node. This file must be the same for all nodes in the cluster.
+          </para>
+          <para>
+            This file is usually /etc/ctdb/nodes .
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--no-lmaster</term>
+        <listitem>
+          <para>
+	  This argument specifies that this node can NOT become an lmaster
+	  for records in the database. This means that it will never show up
+	  in the vnnmap. This feature is primarily used for making a cluster
+	span across a WAN link and use CTDB as a WAN-accelerator.
+          </para>
+          <para>
+	  Please see the "remote cluster nodes" section for more information.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--no-recmaster</term>
+        <listitem>
+          <para>
+	  This argument specifies that this node can NOT become a recmaster
+	  for the database. This feature is primarily used for making a cluster
+	span across a WAN link and use CTDB as a WAN-accelerator.
+          </para>
+          <para>
+	  Please see the "remote cluster nodes" section for more information.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--nosetsched</term>
+        <listitem>
+          <para>
+	    This is a ctdbd debugging option. this option is only used when
+	    debugging ctdbd.
+	  </para>
+	  <para>
+            Normally ctdb will change its scheduler to run as a real-time 
+	    process. This is the default mode for a normal ctdbd operation
+	    to gurarantee that ctdbd always gets the cpu cycles that it needs.
+          </para>
+          <para>
+	    This option is used to tell ctdbd to NOT run as a real-time process
+	    and instead run ctdbd as a normal userspace process.
+	    This is useful for debugging and when you want to run ctdbd under
+	    valgrind or gdb. (You don't want to attach valgrind or gdb to a
+	    real-time process.)
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--notification-script=<filename></term>
+        <listitem>
+          <para>
+	    This specifies a script which will be invoked by ctdb when certain
+	    state changes occur in ctdbd and when you may want to trigger this
+	    to run certain scripts.
+          </para>
+          <para>
+            This file is usually /etc/ctdb/notify.sh .
+          </para>
+          <para>
+	    See the NOTIFICATION SCRIPT section below for more information.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--public_addresses=<filename></term>
+        <listitem>
+          <para>
+            When used with IP takeover this specifies a file containing the public ip addresses to use on the cluster. This file contains a list of ip addresses netmasks and interfaces. When ctdb is operational it will distribute these public ip addresses evenly across the available nodes.
+          </para>
+          <para>
+            This is usually the file /etc/ctdb/public_addresses
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--public-interface=<interface></term>
+        <listitem>
+          <para>
+            This option tells ctdb which interface to attach public-addresses
+	    to and also where to attach the single-public-ip when used.
+	    </para>
+	    <para>
+	    This is only required when using public ip addresses and only when
+	    you don't specify the interface explicitly in /etc/ctdb/public_addresses or when you are using --single-public-ip.
+          </para>
+          <para>
+	  If you omit this argument when using public addresses or single public ip, ctdb will not be able to send out Gratious ARPs correctly or be able to kill tcp connections correctly which will lead to application failures. 
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--reclock=<filename></term>
+        <listitem>
+          <para>
+            This is the name of the lock file stored of the shared cluster filesystem that ctdbd uses to prevent split brains from occuring.
+            This file must be stored on shared storage.
+          </para>
+          <para>
+	    It is possible to run CTDB without a reclock file, but then there 
+	    will be no protection against split brain if the network becomes
+	    partitioned. Using CTDB without a reclock file is strongly
+	    discouraged.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--socket=<filename></term>
+        <listitem>
+          <para>
+            This specifies the name of the domain socket that ctdbd will create. This socket is used for local clients to attach to and communicate with the ctdbd daemon.
+          </para>
+          <para>
+            The default is /tmp/ctdb.socket . You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--start-as-disabled</term>
+        <listitem>
+          <para>
+	  This makes the ctdb daemon to be DISABLED when it starts up.
+          </para>
+          <para>
+	  As it is DISABLED it will not get any of the public ip addresses
+	  allocated to it, and thus this allow you to start ctdb on a node 
+	  without causing any ip address to failover from other nodes onto
+	  the new node.
+          </para>
+          <para>
+	  When used, the administrator must keep track of when nodes start and
+	  manually enable them again using the "ctdb enable" command, or else
+	  the node will not host any services.
+          </para>
+          <para>
+	  A node that is DISABLED will not host any services and will not be
+	  reachable/used by any clients.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--start-as-stopped</term>
+        <listitem>
+          <para>
+	  This makes the ctdb daemon to be STOPPED when it starts up.
+          </para>
+          <para>
+	  A node that is STOPPED does not host any public addresses. It is not part of the VNNMAP so it does act as an LMASTER. It also has all databases locked in recovery mode until restarted.
+          </para>
+          <para>
+	  To restart and activate a STOPPED node, the command "ctdb continue" is used.
+          </para>
+          <para>
+	  A node that is STOPPED will not host any services and will not be
+	  reachable/used by any clients.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--syslog</term>
+        <listitem>
+          <para>
+	    Send all log messages to syslog instead of to the ctdb logfile.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--log-ringbuf-size=<num-entries></term>
+        <listitem>
+          <para>
+	    In addition to the normal loggign to a log file,
+	    CTDBD also keeps a in-memory ringbuffer containing the most recent
+	    log entries for all log levels (except DEBUG).
+          </para>
+          <para>
+	    This is useful since it allows for keeping continuous logs to a file
+	    at a reasonable non-verbose level, but shortly after an incident has
+	    occured, a much more detailed log can be pulled from memory. This
+	    can allow you to avoid having to reproduce an issue due to the
+	    on-disk logs being of insufficient detail.
+          </para>
+          <para>
+	    This in-memory ringbuffer contains a fixed number of the most recent
+	    entries. This is settable at startup either through the
+	    --log-ringbuf-size argument, or preferably by using
+	    CTDB_LOG_RINGBUF_SIZE in the sysconfig file.
+          </para>
+          <para>
+	    Use the "ctdb getlog" command to access this log.
+          </para>
+        </listitem>
+      </varlistentry>
+
+
+      <varlistentry><term>--torture</term>
+        <listitem>
+          <para>
+            This option is only used for development and testing of ctdbd. It adds artificial errors and failures to the common codepaths in ctdbd to verify that ctdbd can recover correctly for failures.
+          </para>
+          <para>
+            You do NOT want to use this option unless you are developing and testing new functionality in ctdbd.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--transport=<STRING></term>
+        <listitem>
+          <para>
+            This option specifies which transport to use for ctdbd internode communications. The default is "tcp".
+          </para>
+          <para>
+            Currently only "tcp" is supported but "infiniband" might be
+	    implemented in the future.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--usage</term>
+        <listitem>
+          <para>
+            Print useage information to the screen.
+          </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+
+  <refsect1><title>Private vs Public addresses</title>
+    <para>
+      When used for ip takeover in a HA environment, each node in a ctdb 
+      cluster has multiple ip addresses assigned to it. One private and one or more public.
+    </para>
+
+    <refsect2><title>Private address</title>
+      <para>
+        This is the physical ip address of the node which is configured in 
+        linux and attached to a physical interface. This address uniquely
+        identifies a physical node in the cluster and is the ip addresses
+        that ctdbd will use to communicate with the ctdbd daemons on the
+        other nodes in the cluster.
+      </para>
+      <para>
+        The private addresses are configured in /etc/ctdb/nodes 
+        (unless the --nlist option is used) and contain one line for each 
+        node in the cluster. Each line contains the private ip address for one
+        node in the cluster. This file must be the same on all nodes in the
+	cluster.
+      </para>
+      <para>
+        Since the private addresses are only available to the network when the
+        corresponding node is up and running you should not use these addresses
+        for clients to connect to services provided by the cluster. Instead
+        client applications should only attach to the public addresses since
+        these are guaranteed to always be available.
+      </para>
+      <para>
+        When using ip takeover, it is strongly recommended that the private 
+	addresses are configured on a private network physically separated
+	from the rest of the network and that this private network is dedicated
+	to CTDB traffic.
+      </para>
+      Example /etc/ctdb/nodes for a four node cluster:
+      <screen format="linespecific">
+        10.1.1.1
+        10.1.1.2
+        10.1.1.3
+        10.1.1.4
+      </screen>
+    </refsect2>
+    <refsect2><title>Public address</title>
+      <para>
+        A public address on the other hand is not attached to an interface.
+        This address is managed by ctdbd itself and is attached/detached to
+        a physical node at runtime.
+      </para>
+      <para>
+        The ctdb cluster will assign/reassign these public addresses across the
+        available healthy nodes in the cluster. When one node fails, its public address
+        will be migrated to and taken over by a different node in the cluster
+        to ensure that all public addresses are always available to clients as 
+	long as there are still nodes available capable of hosting this address.
+      </para>
+      <para>
+        These addresses are not physically attached to a specific node. 
+        The 'ctdb ip' command can be used to view the current assignment of 
+        public addresses and which physical node is currently serving it.
+      </para>
+      <para>
+	On each node this file contains a list of the public addresses that 
+	this node is capable of hosting.
+        The list also contain the netmask and the 
+	interface where this address should be attached for the case where you
+	may want to serve data out through multiple different interfaces.
+      </para>
+      Example /etc/ctdb/public_addresses for a node that can host 4 public addresses:
+      <screen format="linespecific">
+        11.1.1.1/24 eth0
+        11.1.1.2/24 eth0
+        11.1.2.1/24 eth1
+        11.1.2.2/24 eth1
+      </screen>
+
+	<para>
+	In most cases this file would be the same on all nodes in a cluster but
+	there are exceptions when one may want to use different files
+	on different nodes.
+	</para>
+	Example: 4 nodes partitioned into two subgroups :
+	<screen format="linespecific">
+	Node 0:/etc/ctdb/public_addresses
+		10.1.1.1/24 eth0
+		10.1.1.2/24 eth0
+
+	Node 1:/etc/ctdb/public_addresses
+		10.1.1.1/24 eth0
+		10.1.1.2/24 eth0
+
+	Node 2:/etc/ctdb/public_addresses
+		10.2.1.1/24 eth0
+		10.2.1.2/24 eth0
+
+	Node 3:/etc/ctdb/public_addresses
+		10.2.1.1/24 eth0
+		10.2.1.2/24 eth0
+	</screen>
+	<para>
+	In this example nodes 0 and 1 host two public addresses on the 
+	10.1.1.x network  while nodes 2 and 3 host two public addresses for the 
+	10.2.1.x network.
+	</para>
+	<para>
+	Ip address 10.1.1.1 can be hosted by either of nodes 0 or 1 and will be
+	available to clients as long as at least one of these two nodes are
+	available.
+	If both nodes 0 and node 1 become unavailable 10.1.1.1 also becomes 
+	unavailable. 10.1.1.1 can not be failed over to node 2 or node 3 since
+	these nodes do not have this ip address listed in their public
+	addresses file.
+	</para>
+    </refsect2>
+  </refsect1>
+
+
+  <refsect1><title>Node status</title>
+    <para>
+      The current status of each node in the cluster can be viewed by the 
+      'ctdb status' command.
+    </para>
+    <para>
+      There are five possible states for a node.
+    </para>
+
+    <para>
+      OK - This node is fully functional.
+    </para>
+    
+    <para>
+      DISCONNECTED - This node could not be connected through the network 
+      and is currently not particpating in the cluster. If there is a 
+      public IP address associated with this node it should have been taken 
+      over by a different node. No services are running on this node.
+    </para>
+ 
+    <para>
+      DISABLED - This node has been administratively disabled. This node is 
+      still functional and participates in the CTDB cluster but its IP 
+      addresses have been taken over by a different node and no services are 
+      currently being hosted.
+    </para>
+   
+    <para>
+      UNHEALTHY - A service provided by this node is malfunctioning and should 
+      be investigated. The CTDB daemon itself is operational and participates 
+      in the cluster. Its public IP address has been taken over by a different 
+      node and no services are currently being hosted. All unhealthy nodes 
+      should be investigated and require an administrative action to rectify.
+    </para>
+    
+    <para>
+      BANNED - This node failed too many recovery attempts and has been banned 
+      from participating in the cluster for a period of RecoveryBanPeriod 
+      seconds. Any public IP address has been taken over by other nodes. This 
+      node does not provide any services. All banned nodes should be 
+      investigated and require an administrative action to rectify. This node 
+      does not perticipate in the CTDB cluster but can still be communicated 
+      with. I.e. ctdb commands can be sent to it.
+    </para>
+
+    <para>
+      STOPPED - A node that is stopped does not host any public ip addresses,
+      nor is it part of the VNNMAP. A stopped node can not become LVSMASTER,
+      RECMASTER or NATGW.
+      This node does not perticipate in the CTDB cluster but can still be
+      communicated with. I.e. ctdb commands can be sent to it.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>PUBLIC TUNABLES</title>
+    <para>
+    These are the public tuneables that can be used to control how ctdb behaves.
+    </para>
+
+    <refsect2><title>KeepaliveInterval</title>
+    <para>Default: 1</para>
+    <para>
+    How often should the nodes send keepalives to eachother.
+    </para>
+    </refsect2>
+    <refsect2><title>KeepaliveLimit</title>
+    <para>Default: 5</para>
+    <para>
+    After how many keepalive intervals without any traffic should a node
+    wait until marking the peer as DISCONNECTED.
+    </para>
+    </refsect2>
+    <refsect2><title>MonitorInterval</title>
+    <para>Default: 15</para>
+    <para>
+    How often should ctdb run the event scripts to check for a nodes health.
+    </para>
+    </refsect2>
+    <refsect2><title>TickleUpdateInterval</title>
+    <para>Default: 20</para>
+    <para>
+    How often will ctdb record and store the "tickle" information used to
+    kickstart stalled tcp connections after a recovery.
+    </para>
+    </refsect2>
+    <refsect2><title>EventScriptTimeout</title>
+    <para>Default: 20</para>
+    <para>
+    How long should ctdb let an event script run before aborting it and
+    marking the node unhealthy.
+    </para>
+    </refsect2>
+    <refsect2><title>RecoveryBanPeriod</title>
+    <para>Default: 300</para>
+    <para>
+    If a node becomes banned causing repetitive recovery failures. The node will
+    eventually become banned from the cluster.
+    This controls how long the culprit node will be banned from the cluster
+    before it is allowed to try to join the cluster again.
+    Don't set to small. A node gets banned for a reason and it is usually due
+    to real problems with the node.
+    </para>
+    </refsect2>
+    <refsect2><title>DatabaseHashSize</title>
+    <para>Default: 100000</para>
+    <para>
+    Size of the hash chains for the local store of the tdbs that ctdb manages.
+    </para>
+    </refsect2>
+    <refsect2><title>RerecoveryTimeout</title>
+    <para>Default: 10</para>
+    <para>
+    Once a recovery has completed, no additional recoveries are permitted until this timeout has expired.
+    </para>
+    </refsect2>
+    <refsect2><title>EnableBans</title>
+    <para>Default: 1</para>
+    <para>
+    When set to 0, this disables BANNING completely in the cluster and thus nodes can not get banned, even it they break. Don't set to 0.
+    </para>
+    </refsect2>
+    <refsect2><title>DeterministicIPs</title>
+    <para>Default: 1</para>
+    <para>
+    When enabled, this tunable makes ctdb try to keep public IP addresses locked to specific nodes as far as possible. This makes it easier for debugging since you can know that as long as all nodes are healthy public IP X will always be hosted by node Y. 
+    </para>
+    <para>
+    The cost of using deterministic IP address assignment is that it disables part of the logic where ctdb tries to reduce the number of public IP assignment changes in the cluster. This tunable may increase the number of IP failover/failbacks that are performed on the cluster by a small margin.
+    </para>
+    </refsect2>
+    <refsect2><title>DisableWhenUnhealthy</title>
+    <para>Default: 0</para>
+    <para>
+    When set, As soon as a node becomes unhealthy, that node will also automatically become permanently DISABLED. Once a node is DISABLED, the only way to make it participate in the cluster again and host services is by manually enabling the node again using 'ctdb enable'. 
+    </para>
+    <para>
+    This disables parts of the resilience and robustness of the cluster and should ONLY be used when the system administrator is actively monitoring the cluster, so that nodes can be enabled again.
+    </para>
+    </refsect2>
+    <refsect2><title>NoIPFailback</title>
+    <para>Default: 0</para>
+    <para>
+    When set to 1, ctdb will not perform failback of IP addresses when a node becomes healthy. Ctdb WILL perform failover of public IP addresses when a node becomes UNHEALTHY, but when the node becomes HEALTHY again, ctdb will not fail the addresses back.
+    </para>
+    <para>
+    Use with caution! Normally when a node becomes available to the cluster
+ctdb will try to reassign public IP addresses onto the new node as a way to distribute the workload evenly across the clusternode. Ctdb tries to make sure that all running nodes have approximately the same number of public addresses it hosts.
+    </para>
+    <para>
+    When you enable this tunable, CTDB will no longer attempt to rebalance the cluster by failing IP addresses back to the new nodes. An unbalanced cluster will therefore remain unbalanced until there is manual intervention from the administrator. When this parameter is set, you can manually fail public IP addresses over to the new node(s) using the 'ctdb moveip' command.
+    </para>
+    </refsect2>
+  </refsect1>
+
+  <refsect1><title>LVS</title>
+    <para>
+    LVS is a mode where CTDB presents one single IP address for the entire
+    cluster. This is an alternative to using public IP addresses and round-robin
+    DNS to loadbalance clients across the cluster.
+    </para>
+
+    <para>
+    This is similar to using a layer-4 loadbalancing switch but with some restrictions.
+    </para>
+
+    <para>
+    In this mode the cluster select a set of nodes in the cluster and loadbalance
+    all client access to the LVS address across this set of nodes. This set of nodes are all LVS capable nodes that are HEALTHY, or if no HEALTHY nodes exists
+    all LVS capable nodes regardless of health status.
+    LVS will however never loadbalance traffic to nodes that are BANNED,
+    STOPPED, DISABLED or DISCONNECTED. The "ctdb lvs" command is used to show
+    which nodes are currently load-balanced across.
+    </para>
+
+    <para>
+    One of the these nodes are elected as the LVSMASTER. This node receives all
+    traffic from clients coming in to the LVS address and multiplexes it
+    across the internal network to one of the nodes that LVS is using.
+    When responding to the client, that node will send the data back
+    directly to the client, bypassing the LVSMASTER node.
+    The command "ctdb lvsmaster" will show which node is the current
+    LVSMASTER.
+    </para>
+
+    <para>
+    The path used for a client i/o is thus :
+    <screen format="linespecific">
+	(1) Client sends request packet to LVSMASTER
+	(2) LVSMASTER passes the request on to one node across the internal network.
+	(3) Selected node processes the request.
+	(4) Node responds back to client.
+    </screen>
+    </para>
+
+    <para> 
+    This means that all incoming traffic to the cluster will pass through
+    one physical node, which limits scalability. You can send more data to the
+    LVS address that one physical node can multiplex. This means that you 
+    should not use LVS if your I/O pattern is write-intensive since you will be
+    limited in the available network bandwidth that node can handle.
+    LVS does work wery well for read-intensive workloads where only smallish
+    READ requests are going through the LVSMASTER bottleneck and the majority
+    of the traffic volume (the data in the read replies) goes straight from
+    the processing node back to the clients. For read-intensive i/o patterns you can acheive very high throughput rates in this mode.
+    </para>
+
+    <para>
+    Note: you can use LVS and public addresses at the same time.
+    </para>
+
+    <refsect2><title>Configuration</title>
+	<para>
+    To activate LVS on a CTDB node you must specify CTDB_PUBLIC_INTERFACE and 
+    CTDB_LVS_PUBLIC_ADDRESS in /etc/sysconfig/ctdb.
+	</para>
+
+	<para>
+You must also specify the "--lvs" command line argument to ctdbd to activate LVS as a capability of the node. This should be done automatically for you by the /etc/init.d/ctdb script.
+	</para>
+
+	<para>
+	Example:
+    <screen format="linespecific">
+	CTDB_PUBLIC_INTERFACE=eth0
+	CTDB_LVS_PUBLIC_IP=10.0.0.237
+	</screen>
+	</para>
+
+    </refsect2>
+
+    <para>
+    If you use LVS, you must still have a real/permanent address configured
+    for the public interface on each node. This address must be routable
+    and the cluster nodes must be configured so that all traffic back to client
+    hosts are routed through this interface. This is also required in order
+    to allow samba/winbind on the node to talk to the domain controller.
+    (we can not use the lvs IP address to initiate outgoing traffic)
+    </para>
+    <para>
+    I.e. make sure that you can "ping" both the domain controller and also
+    all of the clients from the node BEFORE you enable LVS. Also make sure
+    that when you ping these hosts that the traffic is routed out through the
+    eth0 interface.
+    </para>
+  </refsect1>
+    
+
+  <refsect1><title>REMOTE CLUSTER NODES</title>
+    <para>
+It is possible to have a CTDB cluster that spans across a WAN link. 
+For example where you have a CTDB cluster in your datacentre but you also
+want to have one additional CTDB node located at a remote branch site.
+This is similar to how a WAN accelerator works but with the difference 
+that while a WAN-accelerator often acts as a Proxy or a MitM, in 
+the ctdb remote cluster node configuration the Samba instance at the remote site
+IS the genuine server, not a proxy and not a MitM, and thus provides 100%
+correct CIFS semantics to clients.
+    </para>
+
+    <para>
+	See the cluster as one single multihomed samba server where one of
+	the NICs (the remote node) is very far away.
+    </para>
+
+    <para>
+	NOTE: This does require that the cluster filesystem you use can cope
+	with WAN-link latencies. Not all cluster filesystems can handle
+	WAN-link latencies! Whether this will provide very good WAN-accelerator
+	performance or it will perform very poorly depends entirely
+	on how optimized your cluster filesystem is in handling high latency
+	for data and metadata operations.
+    </para>
+
+    <para>
+	To activate a node as being a remote cluster node you need to set
+	the following two parameters in /etc/sysconfig/ctdb  for the remote node:
+        <screen format="linespecific">
+CTDB_CAPABILITY_LMASTER=no
+CTDB_CAPABILITY_RECMASTER=no
+	</screen>
+    </para>
+
+    <para>
+	Verify with the command "ctdb getcapabilities" that that node no longer
+	has the recmaster or the lmaster capabilities.
+    </para>
+
+  </refsect1>
+
+
+  <refsect1><title>NAT-GW</title>
+    <para>
+      Sometimes it is desireable to run services on the CTDB node which will
+      need to originate outgoing traffic to external servers. This might
+      be contacting NIS servers, LDAP servers etc. etc.
+    </para>
+    <para>
+      This can sometimes be problematic since there are situations when a
+      node does not have any public ip addresses assigned. This could
+      be due to the nobe just being started up and no addresses have been
+      assigned yet or it could be that the node is UNHEALTHY in which
+      case all public addresses have been migrated off.
+    </para>
+    <para>
+      If then the service status of CTDB depends on such services being
+      able to always being able to originate traffic to external resources
+      this becomes extra troublesome. The node might be UNHEALTHY because
+      the service can not be reached, and the service can not be reached
+      because the node is UNHEALTHY.
+    </para>
+    <para>
+      There are two ways to solve this problem. The first is by assigning a
+      static ip address for one public interface on every node which will allow
+      every node to be able to route traffic to the public network even
+      if there are no public addresses assigned to the node.
+      This is the simplest way but it uses up a lot of ip addresses since you
+      have to assign both static and also public addresses to each node.
+    </para>
+    <refsect2><title>NAT-GW</title>
+    <para>
+      A second way is to use the built in NAT-GW feature in CTDB.
+      With NAT-GW you assign one public NATGW address for each natgw group.
+      Each NATGW group is a set of nodes in the cluster that shares the same
+      NATGW address to talk to the outside world. Normally there would only be
+      one NATGW group spanning the entire cluster, but in situations where one
+      ctdb cluster spans multiple physical sites it is useful to have one
+      NATGW group for each of the two sites.
+    </para>
+    <para>
+      There can be multiple NATGW groups in one cluster but each node can only
+      be member of one NATGW group.
+    </para>
+    <para>
+      In each NATGW group, one of the nodes is designated the NAT Gateway
+      through which all traffic that is originated by nodes in this group
+      will be routed through if a public addresses are not available. 
+    </para>
+    </refsect2>
+
+    <refsect2><title>Configuration</title>
+    <para>
+      NAT-GW is configured in /etc/sysconfigctdb by setting the following
+      variables:
+    </para>
+    <screen format="linespecific">
+# NAT-GW configuration
+# Some services running on nthe CTDB node may need to originate traffic to
+# remote servers before the node is assigned any IP addresses,
+# This is problematic since before the node has public addresses the node might
+# not be able to route traffic to the public networks.
+# One solution is to have static public addresses assigned with routing
+# in addition to the public address interfaces, thus guaranteeing that
+# a node always can route traffic to the external network.
+# This is the most simple solution but it uses up a large number of 
+# additional ip addresses.
+#
+# A more complex solution is NAT-GW.
+# In this mode we only need one additional ip address for the cluster from
+# the exsternal public network.
+# One of the nodes in the cluster is elected to be hosting this ip address
+# so it can reach the external services. This node is also configured
+# to use NAT MASQUERADING for all traffic from the internal private network
+# to the external network. This node is the NAT-GW node.
+#
+# All other nodes are set up with a default rote with a metric of 10 to point
+# to the nat-gw node.
+# 
+# The effect of this is that only when a node does not have a public address
+# and thus no proper routes to the external world it will instead
+# route all packets through the nat-gw node.
+#
+# CTDB_NATGW_NODES is the list of nodes that belong to this natgw group.
+# You can have multiple natgw groups in one cluster but each node
+# can only belong to one single natgw group.
+#
+# CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
+# CTDB_NATGW_PUBLIC_IFACE=eth0
+# CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
+# CTDB_NATGW_PRIVATE_NETWORK=10.1.1.0/24
+# CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
+#
+# Normally any node in the natgw group can act as the natgw master.
+# In some configurations you may have special nodes that is a part of the
+# cluster/natgw group, but where the node lacks connectivity to the 
+# public network.
+# For these cases, set this variable to make these nodes not able to
+# become natgw master.
+#
+# CTDB_NATGW_SLAVE_ONLY=yes
+    </screen>
+    </refsect2>
+
+    <refsect2><title>CTDB_NATGW_PUBLIC_IP</title>
+    <para>
+      This is an ip address in the public network that is used for all outgoing
+      traffic when the public addresses are not assigned.
+      This address will be assigned to one of the nodes in the cluster which
+      will masquerade all traffic for the other nodes.
+    </para>
+    <para>
+      Format of this parameter is IPADDRESS/NETMASK
+    </para>
+    </refsect2>
+
+    <refsect2><title>CTDB_NATGW_PUBLIC_IFACE</title>
+    <para>
+      This is the physical interface where the CTDB_NATGW_PUBLIC_IP will be
+      assigned to. This should be an interface connected to the public network.
+    </para>
+    <para>
+      Format of this parameter is INTERFACE
+    </para>
+    </refsect2>
+
+    <refsect2><title>CTDB_NATGW_DEFAULT_GATEWAY</title>
+    <para>
+      This is the default gateway to use on the node that is elected to host
+      the CTDB_NATGW_PUBLIC_IP. This is the default gateway on the public network.
+    </para>
+    <para>
+      Format of this parameter is IPADDRESS
+    </para>
+    </refsect2>
+
+    <refsect2><title>CTDB_NATGW_PRIVATE_NETWORK</title>
+    <para>
+      This is the network/netmask used for the interal private network.
+    </para>
+    <para>
+      Format of this parameter is IPADDRESS/NETMASK
+    </para>
+    </refsect2>
+
+    <refsect2><title>CTDB_NATGW_NODES</title>
+    <para>
+      This is the list of all nodes that belong to the same NATGW group
+      as this node. The default is /etc/ctdb/natgw_nodes.
+    </para>
+    </refsect2>
+
+    <refsect2><title>Operation</title>
+    <para>
+      When the NAT-GW functionality is used, one of the nodes is elected
+      to act as a NAT router for all the other nodes in the group when
+      they need to originate traffic to the external public network.
+    </para>
+    <para>
+      The NAT-GW node is assigned the CTDB_NATGW_PUBLIC_IP to the designated
+      interface and the provided default route. The NAT-GW is configured
+      to act as a router and to masquerade all traffic it receives from the
+      internal private network and which is destined to the external network(s).
+    </para>
+    <para>
+      All other nodes in the group are configured with a default route of
+      metric 10 pointing to the designated NAT GW node.
+    </para>
+    <para>
+      This is implemented in the 11.natgw eventscript. Please see the
+      eventscript for further information.
+    </para>
+
+    </refsect2>
+
+    <refsect2><title>Removing/Changing NATGW at runtime</title>
+    <para>
+      The following are the procedures to change/remove a NATGW configuration 
+      at runtime, without having to restart ctdbd.
+    </para>
+
+    <para>
+      If you want to remove NATGW completely from a node, use these steps:
+    </para>
+    <screen format="linespecific">
+1, Run 'CTDB_BASE=/etc/ctdb /etc/ctdb/events.d/11.natgw removenatgw'
+2, Then remove the configuration from /etc/sysconfig/ctdb
+    </screen>
+
+    <para>
+      If you want to change the NATGW configuration on a node :
+    </para>
+    <screen format="linespecific">
+1, Run 'CTDB_BASE=/etc/ctdb /etc/ctdb/events.d/11.natgw removenatgw'
+2, Then change the configuration in /etc/sysconfig/ctdb
+3, Run 'CTDB_BASE=/etc/ctdb /etc/ctdb/events.d/11.natgw updatenatgw'
+    </screen>
+
+    </refsect2>
+
+  </refsect1>
+
+  <refsect1><title>NOTIFICATION SCRIPT</title>
+    <para>
+      Notification scripts are used with ctdb to have a call-out from ctdb
+      to a user-specified script when certain state changes occur in ctdb.
+      This is commonly to set up either sending SNMP traps or emails
+      when a node becomes unhealthy and similar.
+    </para>
+    <para>
+      This is activated by setting CTDB_NOTIFY_SCRIPT=<your script> in the
+	sysconfig file, or by adding --notification-script=<your script>.
+    </para>
+    <para>
+      See /etc/ctdb/notify.sh for an example script.
+    </para>
+    <para>
+      CTDB currently generates notifications on these state changes:
+    </para>
+
+    <refsect2><title>unhealthy</title>
+    <para>
+      This call-out is triggered when the node changes to UNHEALTHY state.
+    </para>
+    </refsect2>
+
+    <refsect2><title>healthy</title>
+    <para>
+      This call-out is triggered when the node changes to HEALTHY state.
+    </para>
+    </refsect2>
+
+    <refsect2><title>startup</title>
+    <para>
+      This call-out is triggered when ctdb has started up and all managed services are up and running.
+    </para>
+    </refsect2>
+
+  </refsect1>
+
+
+<refsect1><title>ClamAV Daemon</title>
+<para>
+CTDB has support to manage the popular anti-virus daemon ClamAV.
+This support is implemented through the
+eventscript : /etc/ctdb/events.d/31.clamd.
+</para>
+      
+<refsect2><title>Configuration</title>
+<para>
+Start by configuring CLAMAV normally and test that it works. Once this is
+done, copy the configuration files over to all the nodes so that all nodes
+share identical CLAMAV configurations.
+Once this is done you can proceed with the intructions below to activate
+CTDB support for CLAMAV.
+</para>
+
+<para>
+First, to activate CLAMAV support in CTDB, edit /etc/sysconfig/ctdb and add the two lines :
+</para>
+<screen format="linespecific">
+CTDB_MANAGES_CLAMD=yes
+CTDB_CLAMD_SOCKET="/path/to/clamd.socket"
+</screen>
+
+<para>
+Second, activate the eventscript
+</para>
+<screen format="linespecific">
+ctdb enablescript 31.clamd
+</screen>
+
+<para>
+Third, CTDB will now be starting and stopping this service accordingly,
+so make sure that the system is not configured to start/stop this service
+automatically.
+On RedHat systems you can disable the system starting/stopping CLAMAV automatically by running :
+<screen format="linespecific">
+chkconfig clamd off
+</screen>
+</para>
+
+
+<para>
+Once you have restarted CTDBD, use
+<screen format="linespecific">
+ctdb scriptstatus
+</screen>
+and verify that the 31.clamd eventscript is listed and that it was executed successfully.
+</para>
+
+</refsect2>
+</refsect1>
+
+
+
+
+  <refsect1><title>SEE ALSO</title>
+    <para>
+      ctdb(1), onnode(1)
+      <ulink url="http://ctdb.samba.org/"/>
+    </para>
+  </refsect1>
+
+  <refsect1><title>COPYRIGHT/LICENSE</title>
+<literallayout>
+Copyright (C) Andrew Tridgell 2007
+Copyright (C) Ronnie sahlberg 2007
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www.gnu.org/licenses/.
+</literallayout>
+  </refsect1>
+</refentry>

Added: branches/ctdb/squeeze-backports/doc/ltdbtool.1
===================================================================
--- branches/ctdb/squeeze-backports/doc/ltdbtool.1	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ltdbtool.1	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,258 @@
+'\" t
+.\"     Title: ltdbtool
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: 05/04/2011
+.\"    Manual:  
+.\"    Source:  
+.\"  Language: English
+.\"
+.TH "LTDBTOOL" "1" "05/04/2011" "" ""
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+ltdbtool \- handle ctdb\*(Aqs local tdb copies
+.SH "SYNOPSIS"
+.HP \w'\fBltdbtool\ [OPTIONS]\ COMMAND\fR\ 'u
+\fBltdbtool [OPTIONS] COMMAND\fR
+.SH "DESCRIPTION"
+.PP
+ltdbtool is a utility to cope with ctdb\*(Aqs local tdb copies (LTDBs) without connecting to a ctdb daemon\&.
+.PP
+It can be used to
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+dump the contents of a LTDB, optionally printing the ctdb record header information,
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+convert between an LTDB and a non\-clustered tdb by adding or removing ctdb headers and
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+convert between 64 and 32 bit LTDBs where the ctdb record headers differ by 4 bytes of padding\&.
+.RE
+.sp
+.SH "COMMANDS"
+.PP
+help
+.RS 4
+Print a help text\&.
+.RE
+.PP
+dump <IDB>
+.RS 4
+Dump the contents of a LTDB file to standard output in a human\-readable format\&.
+.RE
+.PP
+convert <IDB> <ODB>
+.RS 4
+Make a copy of a LTDB optionally adding or removing ctdb headers\&.
+.RE
+.SH "OPTIONS"
+.PP
+\-p
+.RS 4
+Dump with header information, similar to "ctdb catdb"\&.
+.RE
+.PP
+\-s {0|32|64}
+.RS 4
+Specify how to determine the ctdb record header size for the input database:
+.PP
+0
+.RS 4
+no ctdb header
+.RE
+.PP
+32
+.RS 4
+ctdb header size of a 32 bit system (20 bytes)
+.RE
+.PP
+64
+.RS 4
+ctdb header size of a 64 bit system (24 bytes)
+.RE
+.sp
+The default is 32 or 64 depending on the system architecture\&.
+.RE
+.PP
+\-o {0|32|64}
+.RS 4
+Specify how to determine the ctdb record header size for the output database, see \-s
+.RE
+.PP
+\-S <SIZE>
+.RS 4
+Explicitly specify the ctdb record header size of the input database in bytes\&.
+.RE
+.PP
+\-O <SIZE>
+.RS 4
+Explicitly specify the ctdb record header size for the output database in bytes\&.
+.RE
+.PP
+\-h
+.RS 4
+Print a help text\&.
+.RE
+.SH "EXAMPLES"
+.PP
+Print a local tdb in "tdbdump" style:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ltdbtool dump idmap2\&.tdb\&.0
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Print a local tdb with header information similar to "ctdb catdb":
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ltdbtool dump \-p idmap2\&.tdb\&.0
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Strip the ctdb headers from records:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ltdbtool convert \-o0 idmap2\&.tdb\&.0 idmap\&.tdb
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Strip 64 bit ctdb headers from records, running on i386:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ltdbtool convert \-s64 \-o0 idmap2\&.tdb\&.0 idmap\&.tdb
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Strip the ctdb headers from records by piping through tdbrestore:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ltdbtool dump idmap2\&.tdb\&.0 | tdbrestore idmap\&.tdb
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Convert a local tdb from a 64 bit system for usage on a 32 bit system:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ltdbtool convert \-s64 \-o32 idmap2\&.tdb\&.0 idmap2\&.tdb\&.1
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Add a default header:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ltdbtool convert \-s0 idmap\&.tdb idmap2\&.tdb\&.0
+    
+.fi
+.if n \{\
+.RE
+.\}
+.SH "SEE ALSO"
+.PP
+ctdbd(1), ctdb(1), tdbdump(1), tdbrestore(1),
+\m[blue]\fB\%http://ctdb.samba.org/\fR\m[]
+.SH "COPYRIGHT/LICENSE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Copyright (C) Gregor Beck 2011
+Copyright (C) Michael Adam 2011
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version\&.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&.  See the GNU
+General Public License for more details\&.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www\&.gnu\&.org/licenses/\&.
+.fi
+.if n \{\
+.RE
+.\}

Added: branches/ctdb/squeeze-backports/doc/ltdbtool.1.html
===================================================================
--- branches/ctdb/squeeze-backports/doc/ltdbtool.1.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ltdbtool.1.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,84 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ltdbtool</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" title="ltdbtool"><a name="ltdbtool.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ltdbtool — handle ctdb's local tdb copies </p></div><div class="refsynopsisdiv" title="Synopsis"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ltdbtool [OPTIONS] COMMAND</code> </p></div></div><div class="refsect1" title="DESCRIPTION"><a name="id417069"></a><h2>DESCRIPTION</h2><p>
+      ltdbtool is a utility to cope with ctdb's local tdb copies (LTDBs)
+      without connecting to a ctdb daemon.
+    </p><p>It can be used to
+    </p><div class="itemizedlist"><ul class="itemizedlist" type="disc" compact><li class="listitem"><p>
+	  dump the contents of a LTDB, optionally printing the ctdb
+	  record header information,
+	</p></li><li class="listitem"><p>
+	  convert between an LTDB and a non-clustered tdb
+	  by adding or removing ctdb headers and
+	</p></li><li class="listitem"><p>convert between 64 and 32 bit LTDBs where the ctdb record
+	headers differ by 4 bytes of padding.
+	</p></li></ul></div><p>
+    </p></div><div class="refsect1" title="COMMANDS"><a name="id417114"></a><h2>COMMANDS</h2><div class="variablelist"><dl><dt><span class="term">help</span></dt><dd><p>
+	    Print a help text.
+	  </p></dd><dt><span class="term">dump <IDB></span></dt><dd><p>
+	    Dump the contents of a LTDB file to standard output in a
+	    human-readable format.
+	  </p></dd><dt><span class="term">convert <IDB> <ODB></span></dt><dd><p>
+	    Make a copy of a LTDB optionally adding or removing ctdb headers.
+	  </p></dd></dl></div></div><div class="refsect1" title="OPTIONS"><a name="id417160"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">-p</span></dt><dd><p>
+	    Dump with header information, similar to "ctdb catdb".
+	  </p></dd><dt><span class="term">-s {0|32|64}</span></dt><dd><p>
+	    Specify how to determine the ctdb record header size
+	    for the input database:
+	    </p><div class="variablelist"><dl><dt><span class="term">0</span></dt><dd><p>no ctdb header</p></dd><dt><span class="term">32</span></dt><dd><p>ctdb header size of a 32 bit system (20 bytes)</p></dd><dt><span class="term">64</span></dt><dd><p>ctdb header size of a 64 bit system (24 bytes)</p></dd></dl></div><p>
+	    The default is 32 or 64 depending on the system architecture.
+	  </p></dd><dt><span class="term">-o {0|32|64}</span></dt><dd><p>
+	    Specify how to determine the ctdb record header size
+	    for the output database, see -s
+	  </p></dd><dt><span class="term">-S <SIZE></span></dt><dd><p>
+	    Explicitly specify the ctdb record header size of the input database in bytes.
+	  </p></dd><dt><span class="term">-O <SIZE></span></dt><dd><p>
+	    Explicitly specify the ctdb record header size for the output database in bytes.
+	  </p></dd><dt><span class="term">-h</span></dt><dd><p>
+            Print a help text.
+	  </p></dd></dl></div></div><div class="refsect1" title="EXAMPLES"><a name="id417288"></a><h2>EXAMPLES</h2><p>
+      Print a local tdb in "tdbdump" style:
+    </p><pre class="screen">
+      ltdbtool dump idmap2.tdb.0
+    </pre><p>
+      Print a local tdb with header information similar to "ctdb catdb":
+    </p><pre class="screen">
+      ltdbtool dump -p idmap2.tdb.0
+    </pre><p>
+      Strip the ctdb headers from records:
+    </p><pre class="screen">
+      ltdbtool convert -o0 idmap2.tdb.0 idmap.tdb
+    </pre><p>
+      Strip 64 bit ctdb headers from records, running on i386:
+    </p><pre class="screen">
+      ltdbtool convert -s64 -o0 idmap2.tdb.0 idmap.tdb
+    </pre><p>
+      Strip the ctdb headers from records by piping through tdbrestore:
+    </p><pre class="screen">
+      ltdbtool dump idmap2.tdb.0 | tdbrestore idmap.tdb
+    </pre><p>
+      Convert a local tdb from a 64 bit system for usage on a 32 bit system:
+    </p><pre class="screen">
+      ltdbtool convert -s64 -o32 idmap2.tdb.0 idmap2.tdb.1
+    </pre><p>
+      Add a default header:
+    </p><pre class="screen">
+      ltdbtool convert -s0 idmap.tdb idmap2.tdb.0
+    </pre></div><div class="refsect1" title="SEE ALSO"><a name="id417355"></a><h2>SEE ALSO</h2><p>
+      ctdbd(1), ctdb(1), tdbdump(1), tdbrestore(1),
+      <a class="ulink" href="http://ctdb.samba.org/" target="_top">http://ctdb.samba.org/</a>
+    </p></div><div class="refsect1" title="COPYRIGHT/LICENSE"><a name="id417368"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
+Copyright (C) Gregor Beck 2011<br>
+Copyright (C) Michael Adam 2011<br>
+<br>
+This program is free software; you can redistribute it and/or modify<br>
+it under the terms of the GNU General Public License as published by<br>
+the Free Software Foundation; either version 3 of the License, or (at<br>
+your option) any later version.<br>
+<br>
+This program is distributed in the hope that it will be useful, but<br>
+WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
+General Public License for more details.<br>
+<br>
+You should have received a copy of the GNU General Public License<br>
+along with this program; if not, see http://www.gnu.org/licenses/.<br>
+</p></div></div></div></body></html>

Added: branches/ctdb/squeeze-backports/doc/ltdbtool.1.xml
===================================================================
--- branches/ctdb/squeeze-backports/doc/ltdbtool.1.xml	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ltdbtool.1.xml	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="ltdbtool.1">
+
+<refmeta>
+	<refentrytitle>ltdbtool</refentrytitle>
+	<manvolnum>1</manvolnum>
+	<refmiscinfo class="source"> </refmiscinfo>
+	<refmiscinfo class="manual"> </refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+	<refname>ltdbtool</refname>
+        <refpurpose>handle ctdb's local tdb copies </refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+	<cmdsynopsis>
+		<command>ltdbtool [OPTIONS] COMMAND</command>
+	</cmdsynopsis>
+</refsynopsisdiv>
+
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      ltdbtool is a utility to cope with ctdb's local tdb copies (LTDBs)
+      without connecting to a ctdb daemon.
+    </para>
+    <para>It can be used to
+    <itemizedlist spacing='compact'> <!-- mark='opencircle' -->
+      <listitem>
+	<para>
+	  dump the contents of a LTDB, optionally printing the ctdb
+	  record header information,
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  convert between an LTDB and a non-clustered tdb
+	  by adding or removing ctdb headers and
+	</para>
+      </listitem>
+      <listitem>
+	<para>convert between 64 and 32 bit LTDBs where the ctdb record
+	headers differ by 4 bytes of padding.
+	</para>
+      </listitem>
+    </itemizedlist>
+    </para>
+  </refsect1>
+
+  <refsect1><title>COMMANDS</title>
+
+    <variablelist>
+      <varlistentry><term>help</term>
+        <listitem>
+          <para>
+	    Print a help text.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry><term>dump <IDB></term>
+        <listitem>
+          <para>
+	    Dump the contents of a LTDB file to standard output in a
+	    human-readable format.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>convert <IDB> <ODB></term>
+        <listitem>
+          <para>
+	    Make a copy of a LTDB optionally adding or removing ctdb headers.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>OPTIONS</title>
+
+    <variablelist>
+      <varlistentry><term>-p</term>
+        <listitem>
+          <para>
+	    Dump with header information, similar to "ctdb catdb".
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-s {0|32|64}</term>
+        <listitem>
+	  <para>
+	    Specify how to determine the ctdb record header size
+	    for the input database:
+	    <variablelist spacing="normal">
+	      <varlistentry><term>0</term>
+	      <listitem>
+		<para>no ctdb header</para>
+	      </listitem>
+	      </varlistentry>
+	      <varlistentry><term>32</term>
+	      <listitem>
+		<para>ctdb header size of a 32 bit system (20 bytes)</para>
+	      </listitem>
+	      </varlistentry>
+	      <varlistentry><term>64</term>
+	      <listitem>
+		<para>ctdb header size of a 64 bit system (24 bytes)</para>
+	      </listitem>
+	      </varlistentry>
+	    </variablelist>
+	    The default is 32 or 64 depending on the system architecture.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-o {0|32|64}</term>
+        <listitem>
+          <para>
+	    Specify how to determine the ctdb record header size
+	    for the output database, see -s
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-S <SIZE></term>
+        <listitem>
+          <para>
+	    Explicitly specify the ctdb record header size of the input database in bytes.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-O <SIZE></term>
+        <listitem>
+          <para>
+	    Explicitly specify the ctdb record header size for the output database in bytes.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-h</term>
+        <listitem>
+          <para>
+            Print a help text.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>EXAMPLES</title>
+    <para>
+      Print a local tdb in "tdbdump" style:
+    </para>
+    <screen format="linespecific">
+      ltdbtool dump idmap2.tdb.0
+    </screen>
+
+    <para>
+      Print a local tdb with header information similar to "ctdb catdb":
+    </para>
+    <screen format="linespecific">
+      ltdbtool dump -p idmap2.tdb.0
+    </screen>
+
+    <para>
+      Strip the ctdb headers from records:
+    </para>
+    <screen format="linespecific">
+      ltdbtool convert -o0 idmap2.tdb.0 idmap.tdb
+    </screen>
+
+    <para>
+      Strip 64 bit ctdb headers from records, running on i386:
+    </para>
+    <screen format="linespecific">
+      ltdbtool convert -s64 -o0 idmap2.tdb.0 idmap.tdb
+    </screen>
+
+    <para>
+      Strip the ctdb headers from records by piping through tdbrestore:
+    </para>
+    <screen format="linespecific">
+      ltdbtool dump idmap2.tdb.0 | tdbrestore idmap.tdb
+    </screen>
+
+    <para>
+      Convert a local tdb from a 64 bit system for usage on a 32 bit system:
+    </para>
+    <screen format="linespecific">
+      ltdbtool convert -s64 -o32 idmap2.tdb.0 idmap2.tdb.1
+    </screen>
+
+    <para>
+      Add a default header:
+    </para>
+    <screen format="linespecific">
+      ltdbtool convert -s0 idmap.tdb idmap2.tdb.0
+    </screen>
+  </refsect1>
+
+  <refsect1><title>SEE ALSO</title>
+    <para>
+      ctdbd(1), ctdb(1), tdbdump(1), tdbrestore(1),
+      <ulink url="http://ctdb.samba.org/"/>
+    </para>
+  </refsect1>
+  <refsect1><title>COPYRIGHT/LICENSE</title>
+<literallayout>
+Copyright (C) Gregor Beck 2011
+Copyright (C) Michael Adam 2011
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www.gnu.org/licenses/.
+</literallayout>
+  </refsect1>
+</refentry>

Added: branches/ctdb/squeeze-backports/doc/onnode.1
===================================================================
--- branches/ctdb/squeeze-backports/doc/onnode.1	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/onnode.1	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,225 @@
+'\" t
+.\"     Title: onnode
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: 02/05/2010
+.\"    Manual:  
+.\"    Source:  
+.\"  Language: English
+.\"
+.TH "ONNODE" "1" "02/05/2010" "" ""
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+onnode \- run commands on ctdb nodes
+.SH "SYNOPSIS"
+.HP \w'\fBonnode\ [OPTION]\ \&.\&.\&.\ NODES\ COMMAND\ \&.\&.\&.\fR\ 'u
+\fBonnode [OPTION] \&.\&.\&. NODES COMMAND \&.\&.\&.\fR
+.SH "DESCRIPTION"
+.PP
+onnode is a utility to run commands on a specific node of a CTDB cluster, or on all nodes\&.
+.PP
+The NODES option specifies which node to run a command on\&. You can specify a numeric node number (from 0 to N\-1) or a descriptive node specification (see DESCRIPTIVE NODE SPECIFICATIONS below)\&. You can also specify lists of nodes, separated by commas, and ranges of numeric node numbers, separated by dashes\&. If nodes are specified multiple times then the command will be executed multiple times on those nodes\&. The order of nodes is significant\&.
+.PP
+The COMMAND can be any shell command\&. The onnode utility uses ssh or rsh to connect to the remote nodes and run the command\&.
+.SH "DESCRIPTIVE NODE SPECIFICATIONS"
+.PP
+The following descriptive node specification can be used in place of numeric node numbers:
+.PP
+all
+.RS 4
+All nodes\&.
+.RE
+.PP
+any
+.RS 4
+A node where ctdbd is running\&. This semi\-random but there is a bias towards choosing a low numbered node\&.
+.RE
+.PP
+ok | healthy
+.RS 4
+All nodes that are not disconnected, banned, disabled or unhealthy\&.
+.RE
+.PP
+con | connected
+.RS 4
+All nodes that are not disconnected\&.
+.RE
+.PP
+lvs | lvsmaster
+.RS 4
+The current LVS master\&.
+.RE
+.PP
+natgw | natgwlist
+.RS 4
+The current NAT gateway\&.
+.RE
+.PP
+rm | recmaster
+.RS 4
+The current recovery master\&.
+.RE
+.SH "OPTIONS"
+.PP
+\-c
+.RS 4
+Execute COMMAND in the current working directory on the specified nodes\&.
+.RE
+.PP
+\-o <prefix>
+.RS 4
+Causes standard output from each node to be saved into a file with name <prefix>\&.<ip>\&.
+.RE
+.PP
+\-p
+.RS 4
+Run COMMAND in parallel on the specified nodes\&. The default is to run COMMAND sequentially on each node\&.
+.RE
+.PP
+\-q
+.RS 4
+Do not print node addresses\&. Normally, onnode prints informational node addresses if more than one node is specified\&. This overrides \-v\&.
+.RE
+.PP
+\-n
+.RS 4
+Allow nodes to be specified by name rather than node numbers\&. These nodes don\'t need to be listed in the nodes file\&. You can avoid the nodes file entirely by combining this with
+\-f /dev/null\&.
+.RE
+.PP
+\-f <file>
+.RS 4
+Specify an alternative nodes file to use instead of the default\&. This option overrides the CTDB_NODES_FILE environment variable\&. See the discussion of
+/etc/ctdb/nodes
+in the FILES section for more details\&.
+.RE
+.PP
+\-v
+.RS 4
+Print a node addresses even if only one node is specified\&. Normally, onnode prints informational node addresses when more than one node is specified\&.
+.RE
+.PP
+\-h, \-\-help
+.RS 4
+Show a short usage guide\&.
+.RE
+.SH "EXAMPLES"
+.PP
+The following command would show the process ID of ctdb on all nodes
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      onnode all pidof ctdbd
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+The following command would show the last 5 lines of log on each node, preceded by the node\'s hostname
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      onnode all "hostname; tail \-5 /var/log/log\&.ctdb"
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+The following command would restart the ctdb service on all nodes\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      onnode all service ctdb restart
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+The following command would run \&./foo in the current working directory, in parallel, on nodes 0, 2, 3 and 4\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      onnode \-c \-p 0,2\-4 \&./foo
+    
+.fi
+.if n \{\
+.RE
+.\}
+.SH "ENVIRONMENT"
+.PP
+\fBCTDB_NODES_FILE\fR
+.RS 4
+Name of alternative nodes file to use instead of the default\&. See the discussion of
+/etc/ctdb/nodes
+in the FILES section for more details\&.
+.RE
+.SH "FILES"
+.PP
+/etc/ctdb/nodes
+.RS 4
+Default file containing a list of each node\'s IP address or hostname\&.
+.sp
+Actually, the default is
+$\fBCTDB_BASE\fR/nodes, where
+\fB$CTDB_BASE\fR
+defaults to
+/etc/ctdb\&. If a relative path is given (via the \-f option or
+\fB$CTDB_BASE\fR) and no corresponding file exists relative to the current directory then the file is also searched for in the
+$\fBCTDB_BASE\fR
+directory\&.
+.RE
+.PP
+/etc/ctdb/onnode\&.conf
+.RS 4
+If this file exists it is sourced by onnode\&. The main purpose is to allow the administrator to set $SSH to something other than "ssh"\&. In this case the \-t option is ignored\&. For example, the administrator may choose to use use rsh instead of ssh\&.
+.RE
+.SH "SEE ALSO"
+.PP
+ctdbd(1), ctdb(1),
+\m[blue]\fB\%http://ctdb.samba.org/\fR\m[]
+.SH "COPYRIGHT/LICENSE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Copyright (C) Andrew Tridgell 2007
+Copyright (C) Ronnie sahlberg 2007
+Copyright (C) Martin Schwenke 2008
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version\&.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&.  See the GNU
+General Public License for more details\&.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www\&.gnu\&.org/licenses/\&.
+.fi
+.if n \{\
+.RE
+.\}

Added: branches/ctdb/squeeze-backports/doc/onnode.1.html
===================================================================
--- branches/ctdb/squeeze-backports/doc/onnode.1.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/onnode.1.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,125 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>onnode</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" title="onnode"><a name="onnode.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>onnode — run commands on ctdb nodes</p></div><div class="refsynopsisdiv" title="Synopsis"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">onnode [OPTION] ... NODES COMMAND ...</code> </p></div></div><div class="refsect1" title="DESCRIPTION"><a name="id2602518"></a><h2>DESCRIPTION</h2><p>
+      onnode is a utility to run commands on a specific node of a CTDB
+      cluster, or on all nodes.
+    </p><p>
+      The NODES option specifies which node to run a command on.  You
+      can specify a numeric node number (from 0 to N-1) or a
+      descriptive node specification (see DESCRIPTIVE NODE
+      SPECIFICATIONS below).  You can also specify lists of nodes,
+      separated by commas, and ranges of numeric node numbers,
+      separated by dashes.  If nodes are specified multiple times then
+      the command will be executed multiple times on those nodes.  The
+      order of nodes is significant.
+    </p><p>
+      The COMMAND can be any shell command. The onnode utility uses
+      ssh or rsh to connect to the remote nodes and run the command.
+    </p></div><div class="refsect1" title="DESCRIPTIVE NODE SPECIFICATIONS"><a name="id2602547"></a><h2>DESCRIPTIVE NODE SPECIFICATIONS</h2><p>
+      The following descriptive node specification can be used in
+      place of numeric node numbers:
+    </p><div class="variablelist"><dl><dt><span class="term">all</span></dt><dd><p>
+            All nodes.
+	  </p></dd><dt><span class="term">any</span></dt><dd><p>
+             A node where ctdbd is running.  This semi-random but
+             there is a bias towards choosing a low numbered node.
+	  </p></dd><dt><span class="term">ok | healthy</span></dt><dd><p>
+            All nodes that are not disconnected, banned, disabled or
+            unhealthy.
+	  </p></dd><dt><span class="term">con | connected</span></dt><dd><p>
+            All nodes that are not disconnected.
+	  </p></dd><dt><span class="term">lvs | lvsmaster</span></dt><dd><p>
+            The current LVS master.
+	  </p></dd><dt><span class="term">natgw | natgwlist</span></dt><dd><p>
+            The current NAT gateway.
+	  </p></dd><dt><span class="term">rm | recmaster</span></dt><dd><p>
+            The current recovery master.
+	  </p></dd></dl></div></div><div class="refsect1" title="OPTIONS"><a name="id2600718"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">-c</span></dt><dd><p>
+            Execute COMMAND in the current working directory on the
+            specified nodes.
+	  </p></dd><dt><span class="term">-o <prefix></span></dt><dd><p>
+	    Causes standard output from each node to be saved into a
+	    file with name <prefix>.<ip>.
+	  </p></dd><dt><span class="term">-p</span></dt><dd><p>
+            Run COMMAND in parallel on the specified nodes.  The
+            default is to run COMMAND sequentially on each node.
+	  </p></dd><dt><span class="term">-q</span></dt><dd><p>
+            Do not print node addresses.  Normally, onnode prints
+            informational node addresses if more than one node is
+            specified.  This overrides -v.
+	  </p></dd><dt><span class="term">-n</span></dt><dd><p>
+            Allow nodes to be specified by name rather than node
+            numbers.  These nodes don't need to be listed in the nodes
+            file.  You can avoid the nodes file entirely by combining
+            this with <code class="code">-f /dev/null</code>.
+	  </p></dd><dt><span class="term">-f <file></span></dt><dd><p>
+            Specify an alternative nodes file to use instead of the
+            default.  This option overrides the CTDB_NODES_FILE
+            environment variable.  See the discussion of
+            <code class="filename">/etc/ctdb/nodes</code> in the FILES section
+            for more details.
+	  </p></dd><dt><span class="term">-v</span></dt><dd><p>
+            Print a node addresses even if only one node is specified.
+            Normally, onnode prints informational node addresses when
+            more than one node is specified.
+	  </p></dd><dt><span class="term">-h, --help</span></dt><dd><p>
+            Show a short usage guide.
+	  </p></dd></dl></div></div><div class="refsect1" title="EXAMPLES"><a name="id2600855"></a><h2>EXAMPLES</h2><p>
+      The following command would show the process ID of ctdb on all nodes
+    </p><pre class="screen">
+      onnode all pidof ctdbd
+    </pre><p>
+      The following command would show the last 5 lines of log on each
+      node, preceded by the node's hostname
+    </p><pre class="screen">
+      onnode all "hostname; tail -5 /var/log/log.ctdb"
+    </pre><p>
+      The following command would restart the ctdb service on all nodes.
+    </p><pre class="screen">
+      onnode all service ctdb restart
+    </pre><p>
+      The following command would run ./foo in the current working
+      directory, in parallel, on nodes 0, 2, 3 and 4.
+    </p><pre class="screen">
+      onnode -c -p 0,2-4 ./foo
+    </pre></div><div class="refsect1" title="ENVIRONMENT"><a name="id2600905"></a><h2>ENVIRONMENT</h2><div class="variablelist"><dl><dt><span class="term"><code class="envar">CTDB_NODES_FILE</code></span></dt><dd><p>
+	    Name of alternative nodes file to use instead of the
+            default.  See the discussion of
+            <code class="filename">/etc/ctdb/nodes</code> in the FILES section
+            for more details.
+	  </p></dd></dl></div></div><div class="refsect1" title="FILES"><a name="id2652169"></a><h2>FILES</h2><div class="variablelist"><dl><dt><span class="term"><code class="filename">/etc/ctdb/nodes</code></span></dt><dd><p>
+            Default file containing a list of each node's IP address
+            or hostname.
+	  </p><p>
+	    Actually, the default is
+            <code class="filename">$<code class="envar">CTDB_BASE</code>/nodes</code>,
+            where <code class="envar">$CTDB_BASE</code> defaults to
+            <code class="filename">/etc/ctdb</code>.  If a relative path is
+            given (via the -f option or <code class="envar">$CTDB_BASE</code>) and
+            no corresponding file exists relative to the current
+            directory then the file is also searched for in the
+            <code class="filename">$<code class="envar">CTDB_BASE</code></code> directory.
+	  </p></dd><dt><span class="term"><code class="filename">/etc/ctdb/onnode.conf</code></span></dt><dd><p>
+            If this file exists it is sourced by onnode.  The main
+            purpose is to allow the administrator to set $SSH to
+            something other than "ssh".  In this case the -t option is
+            ignored.  For example, the administrator may choose to use
+            use rsh instead of ssh.
+	  </p></dd></dl></div></div><div class="refsect1" title="SEE ALSO"><a name="id2652258"></a><h2>SEE ALSO</h2><p>
+      ctdbd(1), ctdb(1), <a class="ulink" href="http://ctdb.samba.org/" target="_top">http://ctdb.samba.org/</a>
+    </p></div><div class="refsect1" title="COPYRIGHT/LICENSE"><a name="id2652271"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
+Copyright (C) Andrew Tridgell 2007<br>
+Copyright (C) Ronnie sahlberg 2007<br>
+Copyright (C) Martin Schwenke 2008<br>
+<br>
+This program is free software; you can redistribute it and/or modify<br>
+it under the terms of the GNU General Public License as published by<br>
+the Free Software Foundation; either version 3 of the License, or (at<br>
+your option) any later version.<br>
+<br>
+This program is distributed in the hope that it will be useful, but<br>
+WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
+General Public License for more details.<br>
+<br>
+You should have received a copy of the GNU General Public License<br>
+along with this program; if not, see http://www.gnu.org/licenses/.<br>
+</p></div></div></div></body></html>

Added: branches/ctdb/squeeze-backports/doc/onnode.1.xml
===================================================================
--- branches/ctdb/squeeze-backports/doc/onnode.1.xml	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/onnode.1.xml	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="onnode.1">
+
+<refmeta>
+	<refentrytitle>onnode</refentrytitle>
+	<manvolnum>1</manvolnum>
+	<refmiscinfo class="source"> </refmiscinfo>
+	<refmiscinfo class="manual"> </refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+	<refname>onnode</refname>
+        <refpurpose>run commands on ctdb nodes</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+	<cmdsynopsis>
+		<command>onnode [OPTION] ... NODES COMMAND ...</command>
+	</cmdsynopsis>
+</refsynopsisdiv>
+
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      onnode is a utility to run commands on a specific node of a CTDB
+      cluster, or on all nodes.
+    </para>
+    <para>
+      The NODES option specifies which node to run a command on.  You
+      can specify a numeric node number (from 0 to N-1) or a
+      descriptive node specification (see DESCRIPTIVE NODE
+      SPECIFICATIONS below).  You can also specify lists of nodes,
+      separated by commas, and ranges of numeric node numbers,
+      separated by dashes.  If nodes are specified multiple times then
+      the command will be executed multiple times on those nodes.  The
+      order of nodes is significant.
+    </para>
+    <para>
+      The COMMAND can be any shell command. The onnode utility uses
+      ssh or rsh to connect to the remote nodes and run the command.
+    </para>
+  </refsect1>
+
+  <refsect1><title>DESCRIPTIVE NODE SPECIFICATIONS</title>
+
+    <para>
+      The following descriptive node specification can be used in
+      place of numeric node numbers:
+    </para>
+
+    <variablelist>
+      <varlistentry><term>all</term>
+        <listitem>
+          <para>
+            All nodes.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry><term>any</term>
+        <listitem>
+          <para>
+             A node where ctdbd is running.  This semi-random but
+             there is a bias towards choosing a low numbered node.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry><term>ok | healthy</term>
+        <listitem>
+          <para>
+            All nodes that are not disconnected, banned, disabled or
+            unhealthy.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry><term>con | connected</term>
+        <listitem>
+          <para>
+            All nodes that are not disconnected.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry><term>lvs | lvsmaster</term>
+        <listitem>
+          <para>
+            The current LVS master.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry><term>natgw | natgwlist</term>
+        <listitem>
+          <para>
+            The current NAT gateway.
+	  </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry><term>rm | recmaster</term>
+        <listitem>
+          <para>
+            The current recovery master.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>OPTIONS</title>
+
+    <variablelist>
+      <varlistentry><term>-c</term>
+        <listitem>
+          <para>
+            Execute COMMAND in the current working directory on the
+            specified nodes.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-o <prefix></term>
+        <listitem>
+          <para>
+	    Causes standard output from each node to be saved into a
+	    file with name <prefix>.<ip>.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-p</term>
+        <listitem>
+          <para>
+            Run COMMAND in parallel on the specified nodes.  The
+            default is to run COMMAND sequentially on each node.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-q</term>
+        <listitem>
+          <para>
+            Do not print node addresses.  Normally, onnode prints
+            informational node addresses if more than one node is
+            specified.  This overrides -v.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-n</term>
+        <listitem>
+          <para>
+            Allow nodes to be specified by name rather than node
+            numbers.  These nodes don't need to be listed in the nodes
+            file.  You can avoid the nodes file entirely by combining
+            this with <code>-f /dev/null</code>.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-f <file></term>
+        <listitem>
+          <para>
+            Specify an alternative nodes file to use instead of the
+            default.  This option overrides the CTDB_NODES_FILE
+            environment variable.  See the discussion of
+            <filename>/etc/ctdb/nodes</filename> in the FILES section
+            for more details.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-v</term>
+        <listitem>
+          <para>
+            Print a node addresses even if only one node is specified.
+            Normally, onnode prints informational node addresses when
+            more than one node is specified.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-h, --help</term>
+        <listitem>
+          <para>
+            Show a short usage guide.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>EXAMPLES</title>
+    <para>
+      The following command would show the process ID of ctdb on all nodes
+    </para>
+    <screen format="linespecific">
+      onnode all pidof ctdbd
+    </screen>
+
+    <para>
+      The following command would show the last 5 lines of log on each
+      node, preceded by the node's hostname
+    </para>
+    <screen format="linespecific">
+      onnode all "hostname; tail -5 /var/log/log.ctdb"
+    </screen>
+
+    <para>
+      The following command would restart the ctdb service on all nodes.
+    </para>
+    <screen format="linespecific">
+      onnode all service ctdb restart
+    </screen>
+
+    <para>
+      The following command would run ./foo in the current working
+      directory, in parallel, on nodes 0, 2, 3 and 4.
+    </para>
+    <screen format="linespecific">
+      onnode -c -p 0,2-4 ./foo
+    </screen>
+  </refsect1>
+
+  <refsect1><title>ENVIRONMENT</title>
+
+    <variablelist>
+      <varlistentry><term><envar>CTDB_NODES_FILE</envar></term>
+        <listitem>
+          <para>
+	    Name of alternative nodes file to use instead of the
+            default.  See the discussion of
+            <filename>/etc/ctdb/nodes</filename> in the FILES section
+            for more details.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>FILES</title>
+
+    <variablelist>
+      <varlistentry><term><filename>/etc/ctdb/nodes</filename></term>
+        <listitem>
+          <para>
+            Default file containing a list of each node's IP address
+            or hostname.
+	  </para>
+	  <para>
+	    Actually, the default is
+            <filename>$<envar>CTDB_BASE</envar>/nodes</filename>,
+            where <envar>$CTDB_BASE</envar> defaults to
+            <filename>/etc/ctdb</filename>.  If a relative path is
+            given (via the -f option or <envar>$CTDB_BASE</envar>) and
+            no corresponding file exists relative to the current
+            directory then the file is also searched for in the
+            <filename>$<envar>CTDB_BASE</envar></filename> directory.
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term><filename>/etc/ctdb/onnode.conf</filename></term>
+        <listitem>
+          <para>
+            If this file exists it is sourced by onnode.  The main
+            purpose is to allow the administrator to set $SSH to
+            something other than "ssh".  In this case the -t option is
+            ignored.  For example, the administrator may choose to use
+            use rsh instead of ssh.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>SEE ALSO</title>
+    <para>
+      ctdbd(1), ctdb(1), <ulink url="http://ctdb.samba.org/"/>
+    </para>
+  </refsect1>
+  <refsect1><title>COPYRIGHT/LICENSE</title>
+<literallayout>
+Copyright (C) Andrew Tridgell 2007
+Copyright (C) Ronnie sahlberg 2007
+Copyright (C) Martin Schwenke 2008
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www.gnu.org/licenses/.
+</literallayout>
+  </refsect1>
+</refentry>

Added: branches/ctdb/squeeze-backports/doc/ping_pong.1
===================================================================
--- branches/ctdb/squeeze-backports/doc/ping_pong.1	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ping_pong.1	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,110 @@
+'\" t
+.\"     Title: ping_pong
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
+.\"      Date: 03/26/2011
+.\"    Manual:  
+.\"    Source:  
+.\"  Language: English
+.\"
+.TH "PING_PONG" "1" "03/26/2011" "" ""
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+ping_pong \- measures the ping\-pong byte range lock latency
+.SH "SYNOPSIS"
+.HP \w'\fBping_pong\ [options]\ <file>\ <num_locks>\fR\ 'u
+\fBping_pong [options] <file> <num_locks>\fR
+.HP \w'\fBping_pong\fR\ 'u
+\fBping_pong\fR [\-r] [\-w] [\-m]
+.SH "DESCRIPTION"
+.PP
+This measures the ping\-pong byte range lock latency\&. It is especially useful on a cluster of nodes sharing a common lock manager as it will give some indication of the lock managers performance under stress\&.
+.SH "OPTIONS"
+.PP
+\-r
+.RS 4
+do reads
+.RE
+.PP
+\-w
+.RS 4
+do writes
+.RE
+.PP
+\-m
+.RS 4
+use mmap
+.RE
+.SH "EXAMPLES"
+.PP
+Testing lock coherence
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ping_pong test\&.dat N
+    
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+Testing IO coherence
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+      ping_pong \-rw test\&.dat N
+    
+.fi
+.if n \{\
+.RE
+.\}
+.SH "SEE ALSO"
+.PP
+
+\m[blue]\fB\%https://wiki.samba.org/index.php/Ping_pong\fR\m[], ctdb(1), ctdbd(1)
+.SH "COPYRIGHT/LICENSE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Copyright (C) Andrew Tridgell 2002
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version\&.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&.  See the GNU
+General Public License for more details\&.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www\&.gnu\&.org/licenses/\&.
+.fi
+.if n \{\
+.RE
+.\}

Added: branches/ctdb/squeeze-backports/doc/ping_pong.1.html
===================================================================
--- branches/ctdb/squeeze-backports/doc/ping_pong.1.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ping_pong.1.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,37 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ping_pong</title><meta name="generator" content="DocBook XSL Stylesheets V1.76.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" title="ping_pong"><a name="ping_pong.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ping_pong — measures the ping-pong byte range lock latency</p></div><div class="refsynopsisdiv" title="Synopsis"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ping_pong [options] <file> <num_locks></code> </p></div><div class="cmdsynopsis"><p><code class="command">ping_pong</code>  [-r] [-w] [-m]</p></div></div><div class="refsect1" title="DESCRIPTION"><a name="id2949769"></a><h2>DESCRIPTION</h2><p>
+      This measures the ping-pong byte range lock latency. It is
+      especially useful on a cluster of nodes sharing a common lock
+      manager as it will give some indication of the lock managers
+      performance under stress.
+    </p></div><div class="refsect1" title="OPTIONS"><a name="id2949782"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">-r</span></dt><dd><p>
+	    do reads
+	  </p></dd><dt><span class="term">-w</span></dt><dd><p>
+	    do writes
+	  </p></dd><dt><span class="term">-m</span></dt><dd><p>
+	    use mmap
+	  </p></dd></dl></div></div><div class="refsect1" title="EXAMPLES"><a name="id2949828"></a><h2>EXAMPLES</h2><p>
+      Testing lock coherence
+    </p><pre class="screen">
+      ping_pong test.dat N
+    </pre><p>
+      Testing IO coherence
+    </p><pre class="screen">
+      ping_pong -rw test.dat N
+    </pre></div><div class="refsect1" title="SEE ALSO"><a name="id2949852"></a><h2>SEE ALSO</h2><p>
+      <a class="ulink" href="https://wiki.samba.org/index.php/Ping_pong" target="_top">https://wiki.samba.org/index.php/Ping_pong</a>, ctdb(1), ctdbd(1)
+    </p></div><div class="refsect1" title="COPYRIGHT/LICENSE"><a name="id2949866"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
+Copyright (C) Andrew Tridgell 2002<br>
+<br>
+This program is free software; you can redistribute it and/or modify<br>
+it under the terms of the GNU General Public License as published by<br>
+the Free Software Foundation; either version 3 of the License, or (at<br>
+your option) any later version.<br>
+<br>
+This program is distributed in the hope that it will be useful, but<br>
+WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
+General Public License for more details.<br>
+<br>
+You should have received a copy of the GNU General Public License<br>
+along with this program; if not, see http://www.gnu.org/licenses/.<br>
+</p></div></div></div></body></html>

Added: branches/ctdb/squeeze-backports/doc/ping_pong.1.xml
===================================================================
--- branches/ctdb/squeeze-backports/doc/ping_pong.1.xml	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/ping_pong.1.xml	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="ping_pong.1">
+
+<refmeta>
+	<refentrytitle>ping_pong</refentrytitle>
+	<manvolnum>1</manvolnum>
+	<refmiscinfo class="source"> </refmiscinfo>
+	<refmiscinfo class="manual"> </refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+	<refname>ping_pong</refname>
+        <refpurpose>measures the ping-pong byte range lock latency</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+	<cmdsynopsis>
+		<command>ping_pong [options] <file> <num_locks></command>
+	</cmdsynopsis>
+
+	<cmdsynopsis>
+		<command>ping_pong</command>
+		<arg choice="opt">-r</arg>
+		<arg choice="opt">-w</arg>
+		<arg choice="opt">-m</arg>
+	</cmdsynopsis>
+	
+</refsynopsisdiv>
+
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      This measures the ping-pong byte range lock latency. It is
+      especially useful on a cluster of nodes sharing a common lock
+      manager as it will give some indication of the lock managers
+      performance under stress.
+    </para>
+
+  </refsect1>
+
+  <refsect1><title>OPTIONS</title>
+
+    <variablelist>
+      <varlistentry><term>-r</term>
+        <listitem>
+          <para>
+	    do reads
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-w</term>
+        <listitem>
+          <para>
+	    do writes
+	  </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-m</term>
+        <listitem>
+          <para>
+	    use mmap
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>EXAMPLES</title>
+    <para>
+      Testing lock coherence
+    </para>
+    <screen format="linespecific">
+      ping_pong test.dat N
+    </screen>
+
+    <para>
+      Testing IO coherence
+    </para>
+    <screen format="linespecific">
+      ping_pong -rw test.dat N
+    </screen>
+  </refsect1>
+
+  <refsect1><title>SEE ALSO</title>
+    <para>
+      <ulink url="https://wiki.samba.org/index.php/Ping_pong"/>, ctdb(1), ctdbd(1)
+    </para>
+  </refsect1>
+  <refsect1><title>COPYRIGHT/LICENSE</title>
+<literallayout>
+Copyright (C) Andrew Tridgell 2002
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see http://www.gnu.org/licenses/.
+</literallayout>
+  </refsect1>
+</refentry>

Added: branches/ctdb/squeeze-backports/doc/readonlyrecords.txt
===================================================================
--- branches/ctdb/squeeze-backports/doc/readonlyrecords.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/readonlyrecords.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,257 @@
+Read-Only locks in CTDB
+=======================
+
+Problem
+=======
+CTDB currently only supports exclusive Read-Write locks for clients(samba) accessing the TDB databases.
+This works well mostly, but when very mny number of clients are accessing the same file, at the same time,
+this will cause the exclusive lock as well as the record itself to rapidly bounce between nodes, and acts as
+a scalability limitation.
+
+This primarily affects locking.tdb and brlock.tdb, two databases where record access is mostly read, and where a read request is magnitudes more common than read-write requests.
+
+For the common case, if CTDB provided shared non-exlusive Read-Only lock semantincs, this would greatly improve scaling for these workloads.
+
+
+Desired properties
+==================
+We can not make backward incompatible changes the ctdb/ltdb header for the records.
+
+A Read-Only lock enabled ctdb demon must be able to interoperate with a non-Read-Only lock enbled daemon.
+
+Getting a Read-Only look should not be slower than getting a Read-Write lock.
+
+Requesting a Read-Only lock should never trigger a record migration.
+
+When revoking Read-Only locks for a record, this should involve only those nodes that hold a Read-Only lock right now and should avoid broadcasting opportunistic revocations. (must track which nodes are delegated to)
+
+When a Read-Write lock is requested, if there are Read-Only locks delegated to other nodes, the DMASTER will defer the record migration until all read-only locks are first revoked (synchronous revoke).
+
+Due to the cost of revoking Read-Only locks has on getting a Read-Write lock, the implementation should try to avoid
+creating Read-Only locks, unless it has indication that there is contention. This may mean that even if client requests a Read-Only lock we may still provide a full Read-Write lock in order to avoid the cost of revoking the locks in some cases.
+
+Read-Only locks require additional state to be stored in a separate database, containing information about which nodes have have been delegated Read-Only locks. This database should be kept at minimal size.
+
+Read-Only locks should not significantly complicate the normal record/create/migration/deletion cycle for normal records.
+
+Read-Only locks should not complicate the recovery process.
+
+Read-Only locks should not complicate the vacuuming process.
+
+We should avoid forking new child processes as far as possible from the main daemon.
+
+Client-side implementation, samba, libctdb, others, should have minimal impact when Read-Only locks are implemented.
+Client-side implementation must be possible with only minor conditionals added to the existing lock-check-fetch-unlock loop that clients use today for Read-Write locks. So that clients only need one single loop that can handle both Read-Write locking as well as Read-Only locking. Clients should not need two nearly identical loops.
+
+
+Implementation
+==============
+
+Four new flags are allocated in the ctdb/ltdb record header.
+HAVE_DELEGATIONS, HAVE_READONLY_LOCK, REVOKING_READONLY and REVOKE_COMPLETE
+
+HAVE_DELEGATIONS is a flag that can only be set on the node that is currently the DMASTER for the record. When set, this
+flag indicates that there are Read-Only locks delegated to other nodes in the cluster for this record.
+
+HAVE_READONLY is a flag that is only set on nodes that are NOT the DMASTER for the record. If set this flag
+indicates that this record contains an up-to-date Read-Only version of this record.
+A client that only needs to read, but not to write, the record can safely use the content of this record as is regardless of the value of the DMASTER field of the record.
+
+REVOKING_READONLY is a flag that is used while a set of read only delegations are being revoked.
+This flag is only set when HAVE_DELEGATIONS is also set, and is cleared at the same time as HAVE_DELEGATIONS is cleared.
+Normal operations is that first the HAVE_DELEGATIONS flag is set when the first delegation is generated.
+When the delegations are about to be revoked, the REVOKING_READONLY flag is set too.
+Once all delegations are revoked, both flags are cleared at the same time.
+While REVOKING_READONLY is set, any requests for the record, either normal request or request for readonly will be deferred.
+Deferred requests are linked to a list of deferred requests for the hash of the record until the time that the revokation is completed.
+This flags is set by the main ctdb daemon when it starts revoking this record.
+
+REVOKE_COMPLETE
+The actual revoke of records is done by a child process, spawned from the ctdb amin daemon when it starts the process to revoke the records.
+Once the child process has finished revoking all delegations, it will set the flag REVOKE_COMPLETE for this record to signal to the master daemon that the record has been successfully revoked.
+At this stage the child process will also trigger an event in the main daemon that revoke is complete, and that the main dameon should start re-processing all deferred calls.
+
+
+
+Once the revoke process is completed. There will be at least one deferred call to access this record, the initical call to for an exclusive fetch_lock() that triggered the revoke process to be started.
+In addition to nthis deferred call there may also be additional requests that have also become deferred while the revoke was in process. These can be either exclusive fetch_locks() or they can be other calls to request a new readonly lock on the record.
+Once the revoke is completed, the main daemon will reprocess all exclusive fetch_lock() requests immediately and respond to the clients.
+But any requests for readadonly locks will be deferred for an additional period of time before they are re-processed.
+This is to allow the client that needs a fetch_lock() to update the record to get some time to access and work on the record without having to compete with the possibly very many requests to get new readonly delegations created.
+
+
+
+
+
+
+The ctdbdb structure is expanded so that it contains one extra TDB database for each normal, non-persistent datbase.
+This new database is used for tracking delegations for the records. A record in the normal database that has "HAVE_DELEGATION" set will always have a corresponding record at the same key. This record contains the set of all nodes that the record is delegated to.
+This tracking database is lockless, using TDB_NOLOCK, and is only ever accessed by the main ctdbd daemon.
+The lockless nature and the fact that no other process ever access this TDB means we are guranteed non-blocking access to records in the trcking database.
+
+The ctdb_call PDU is allocated with two new flags WANT_READONLY and WITH_HEADER.
+This first flag is used to explicitely requesting a read-only record from the DMASTER/LMASTER.
+The second flag is used to request that the fetch operation will return not only the data for the record but also
+the record header. 
+If the record does not yet exist, this is a returned as an error to the client and the client will retry the request loop.
+
+A new control is added to make remote nodes remove the HAVE_READONLY_LOCK from a record.
+
+
+
+Client implementation
+=====================
+Clients today use a loop for record fetch lock that looks like this
+    try_again:
+        lock record in tdb
+
+        if record does not exist in tdb,
+            unlock record
+            ask ctdb to migrate record onto the node
+            goto try_again
+
+        if record dmaster != this node pnn
+            unlock record
+            ask ctdb to migrate record onto the node
+            goto try_again
+
+    finished:
+
+where we basically spin, until the record is migrated onto the node and we have managed pinning it down.
+
+This will change to instead do
+
+    try_again:
+        lock record in tdb
+
+        if record does not exist in tdb,
+            unlock record
+            ask ctdb to migrate record onto the node
+            goto try_again
+
+        if record dmaster == current node pnn
+            goto finished
+
+        if read-only lock
+            if HAVE_READONLY_LOCK or HAVE_DELEGATIONS is set
+                goto finished
+            else
+                unlock record 
+                ask ctdb for read-only copy (WANT_READONLY|WITH_HEADER)
+                if failed to get read-only copy (*A)
+                    ask ctdb to migrate the record onto the node
+                    goto try_again
+                lock record in tdb
+                goto finished
+
+        unlock record
+        ask ctdb to migrate record onto the node
+        goto try_again
+
+    finished:
+
+If the record does not yet exist in the local TDB, we always perform a full fetch for a Read-Write lock, even if only a Read-Only lock ws requested.
+This means that for first access, we use the the current grab a Read-Write lock, just like we do today.
+This creates the record and migrates it onto the node. The local node becomes DMASTER for the record.
+This did not yet trigger a Read-Only delegation to be created.
+Future reference to this record by the local samba daemons will still access/lock the record locally without triggereing a Read-Only delegation to be created since the record is already hosted on the local node as DMASTER.
+
+Only if the record is contended, i.e. it has been created but we are no longer the DMASTER for the record, only for this case will we create a Read-Only delegation for this record.
+
+This heuristics provide a mechanism where we will not create Read-Only delegations until we have some indication that the record may be contended.
+
+This avoids creating and revoking Read-Only delegations when only a single client is repeatedly accessing the same set of records.
+This also aims to limit the size of the tracking tdb.
+
+
+Server implementation
+=====================
+When receiving a ctdb_call with the WANT_READONLY flag:
+
+If this is the LMASTER for the record and the record does not yet exist, LMASTER will return an error back to the client (*A above) and the client will try to recover. In particular, LMASTER will not create a new record for this case.
+
+If this is the LMASTER for the record and the record exists, the PDU will be forwrded to the DMASTER for the record.
+
+If this node is not the DMASTER for this record, we forward the PDU back to the LMASTER. Just as we always do today.
+
+If this is the DMASTER for the record, we need to create a Read-Only delegation. This is done by
+     lock record
+     increase the RSN by one for this record
+     set the HAVE_DELEGATIONS flag for the record
+     write the updated record to the TDB
+     create/update the tracking TDB nd add this new node to the set of delegations
+     send a modified copy of the record back to the requesting client.
+         modifications are that RSN is decremented by one, so delegated records are "older" than on the DMASTER,
+         it has HAVE_DELEGATIONS flag stripped off, and has HAVE_READONLY_LOCK added.
+     unlock record
+
+Important to note is that this does not trigger a record migration.
+
+
+When receiving a ctdb_call without the WANT_READONLY flag:
+
+If this is the DMASTER for the this might trigger a migration. So,
+IF the record has HAVE_DELEGATIONS set, we create a child process and defer processing of this PDU until the child process has completed.
+
+From the child process we will call out to all nodes that have delegations for this record and tell them to invalidate this record by clearing the HAVE_READONLY_LOCK from the record.
+Once all delegated nodes respond back, the child process signals back to the main daemon the revoke has completed.
+(child process may not access the tracking tdb since it is lockless)
+
+Main process is triggered to re-process the PDU once the child process has finished.
+Main daemon deletes the corresponding record in the tracking database, clears the HAVE_DELEGATIONS flag for the record and then proceeds to perform the migration as usual.
+
+When receiving a ctdb_call without the flag we want all delegations to be revoked, so we must take care that the delegations are revoked unconditionally before we even check if we are already the DMASTER (in which case thie ctdb_call would normally just be  no-op  (*B below))
+
+
+
+Recovery process changes
+========================
+A recovery implicitely clears/revokes any read only records and delegations from all databases.
+
+During delegations of Read-Only locks, this is done in such way that delegated records will have a RSN smaller than the DMASTER. This guarantees that read-only copies always have a RSN that is smaller than the DMASTER.
+
+During recoveries we do not need to take any special action other than always picking the copy of the record that has the highest RSN, which is what we already do today.
+
+During the recovery process, we strip all flags off all records while writing the new contnent of the database during the PUSH_DB control. 
+
+During processing of the PUSH_DB control and once the new database has been written we then also wipe the tracking database.
+
+This makes changes to the recovery process minimal and nonintrusive.
+
+
+
+Vacuuming process
+=================
+Vacuuming needs only minimal changes.
+
+
+When vacuuming runs, it will do a fetch_lock to migrate any remote records back onto the LMASTER before the record can be purged. This will automatically force all delegations for that record to be revoked before the migration is copied back onto the LMASTER.
+This handles the case where LMASTER is not the DMASTER for the record that will be purged.
+The migration here does force any delegations to be revoked before the migration takes place.
+
+Missing is the case when delegations exist and the LMASTER is also the DMASTER.
+For this case we need to change the vacuuming to unconditionally always try to do a fetch_lock when HAVE_DELEGATIONS is set, even if the record is already stored locally. (*B)
+This fetch lock will not cause any migrations by the ctdb daemon, but since it does not have the WANT_READONLY
+this will still force the delegations to be revoked but no migrations trigger.
+
+
+Traversal process
+=================
+Traversal process is changed to ignore any records with the HAVE_READONLY_LOCK
+
+
+Forward/Backward Compatibility
+==============================
+Non-readonly locking daemons must be able to interoperate with readonly locking enabled daemons.
+
+Non-readonly enabled daemons fetching records from Readonly enabled daemons:
+Non-readonly enabled daemons do not know, and never set the WANT_READONLY flag so these daemons will always request a full migration for a full fetch-lock for all records. Thus a request from a non-readonly enabled daemon will always cause any existing delegations to be immediately revoked. Access will work but performance may be harmed since there will be a lot of revoking of delegations.
+
+Readonly enabled dameons fetching records with WANT_READONLY from non-readonly enabled daemons:
+Non-readonly enabled daemons ingore the WANT_READONLY flag and never return delegations. They always return a full record migration.
+Full record migration is allowed by the protocol, even if the originator only requests the 'hint' WANT_READONLY,
+so this access also interoperates between daemons with different capabilities.
+
+
+
+

Added: branches/ctdb/squeeze-backports/doc/recovery-process.txt
===================================================================
--- branches/ctdb/squeeze-backports/doc/recovery-process.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/doc/recovery-process.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,436 @@
+Valid as of 1.0.66, may/will change in the future
+
+
+RECMASTER
+=========
+Recovery Master, this is one of the nodes in the cluster that has been designated to
+be the "recovery master".
+The recovery master is responsible for performing full checks of cluster and cluster node consistency and is also responsible for performing the actual database recovery procedure.
+
+Only one node at a time can be the recovery master.
+This is ensured by CTDB using a lock on a single file in the shared gpfs filesystem:
+  /etc/sysconfig/ctdb :
+  ...
+  # Options to ctdbd. This is read by /etc/init.d/ctdb
+  # you must specify the location of a shared lock file across all the
+  # nodes. This must be on shared storage
+  # there is no default here
+  CTDB_RECOVERY_LOCK=/gpfs/.ctdb/shared
+  ...
+
+In order to prevent that two nodes become recovery master at the same time (==split brain)
+CTDB here relies on GPFS that GPFS will guarantee coherent locking across the cluster.
+Thus CTDB relies on that GPFS MUST only allow one ctdb process on one node to take out and
+hold this lock.
+
+The recovery master is designated through an election process. 
+
+
+VNNMAP
+======
+The VNNMAP is a list of all nodes in the cluster that is currently part of the cluster
+and participates in hosting the cluster databases.
+All nodes that are CONNECTED but not BANNED be present in the VNNMAP.
+
+The VNNMAP is the list of LMASTERS for the cluster as reported by 'ctdb status' "
+  ...
+  Size:3
+  hash:0 lmaster:0
+  hash:1 lmaster:1
+  hash:2 lmaster:2
+  ...
+
+
+CLUSTER MONITORING
+==================
+All nodes in the cluster monitor its own health and its own consistency regards to the
+recovery master. How and what the nodes monitor for differs between the node which is
+the recovery master and normal nodes.
+This monitoring it to ensure that the cluster is healthy and consistent. 
+This is not related to monitoring of inidividual node health, a.k.a. eventscript monitroing.
+
+At the end of each step in the process are listed some of the most common and important
+error messages that can be generated during that step.
+
+
+NORMAL NODE CLUSTER MONITORING
+------------------------------
+Monitoring is performed in the dedicated recovery daemon process.
+The implementation can be found in server/ctdb_recoverd.c:monitor_cluster()
+This is an overview of the more important tasks during monitoring.
+These tests are to verify that the local node is consistent with the recovery master.
+
+Once every second the following monitoring loop is performed :
+
+1, Verify that the parent ctdb daemon on the local node is still running.
+   If it is not, the recovery daemon logs an error and terminates.
+   "CTDB daemon is no longer available. Shutting down recovery daemon"
+
+2, Check if any of the nodes has been recorded to have misbehaved too many times.
+   If so we ban the node and log a message :
+   "Node %u has caused %u failures in %.0f seconds - banning it for %u seconds"
+
+3, Check that there is a recovery master.
+   If not we initiate a clusterwide election process and log :
+   "Initial recovery master set - forcing election"
+   and we restart monitoring from 1.
+
+4, Verify that recovery daemon and the local ctdb daemon agreed on all the
+   node BANNING flags.
+   If the recovery daemon and the local ctdb daemon disagrees on these flags we update
+   the local ctdb daemon, logs one of two messages and restarts monitoring from 1 again.
+   "Local ctdb daemon on recmaster does not think this node is BANNED but the recovery master disagrees. Unbanning the node"
+   "Local ctdb daemon on non-recmaster does not think this node is BANNED but the recovery master disagrees. Re-banning the node"
+
+5, Verify that the node designated to be recovery master exists in the local list of all nodes.
+   If the recovery master is not in the list of all cluster nodes a new recovery master
+   election is triggered and monitoring restarts from 1.
+   "Recmaster node %u not in list. Force reelection"
+
+6, Check if the recovery master has become disconnected.
+   If is has, log an error message, force a new election and restart monitoring from 1.
+   "Recmaster node %u is disconnected. Force reelection"
+
+7, Read the node flags off the recovery master and verify that it has not become banned.
+   If is has, log an error message, force a new election and restart monitoring from 1.
+   "Recmaster node %u no longer available. Force reelection"
+
+8, Verify that the recmaster and the local node agrees on the flags (BANNED/DISABLED/...)
+   for the local node. 
+   If there is an inconsistency, push the flags for the local node out to all other nodes.
+   "Recmaster disagrees on our flags flags:0x%x recmaster_flags:0x%x  Broadcasting out flags."
+
+9, Verify that the local node hosts all public ip addresses it should host and that it does
+   NOT host any public addresses it should not host.
+   If there is an inconsistency we log an error, trigger a recovery to occur and restart
+   monitoring from 1 again.
+   "Public address '%s' is missing and we should serve this ip"
+   "We are still serving a public address '%s' that we should not be serving."
+
+These are all the checks we perform during monitoring for a normal node.
+These tests are performed on all nodes in the cluster which is why it is optimized to perform
+as few network calls to other nodes as possible.
+Each node only performs 1 call to the recovery master in each loop and to no other nodes.
+
+NORMAL NODE CLUSTER MONITORING
+------------------------------
+The recovery master performs a much more extensive test. In addition to tests 1-9 above
+the recovery master also performs the following tests:
+
+10, Read the list of nodes and flags from all other CONNECTED nodes in the cluster.
+    If there is a failure to read this list from one of the nodes, then log an 
+    error, mark this node as a candidate to become BANNED and restart monitoring from 1.
+    "Unable to get nodemap from remote node %u"
+
+11, Verify that the local recovery master and the remote node agrees on the flags
+    for the remote node. If there is a inconsistency for the BANNING flag,
+    log an error, trigger a new recmaster election and restart monitoring from 1.
+    "Remote node %u had different BANNED flags 0x%x, local had 0x%x - trigger a re-election"
+    "Remote node %u had flags 0x%x, local had 0x%x - updating local"
+
+12, Verify that the local recovery master and the remote node agrees on the flags
+    for the remote node. If one of the flags other than the BANNING flag was inconsistent,
+    just update the set of flags for the local recovery daemon, log an information message
+    and continue monitoring.
+    "Remote node %u had flags 0x%x, local had 0x%x - updating local"
+
+13, Read the list of public ip addresses from all of the CONNECTED nodes and merge into a
+    single clusterwide list.
+    If we fail to read the list of ips from a node, log an error and restart monitoring from 1.
+    "Failed to read public ips from node : %u"
+
+14, Verify that all other nodes agree that this node is the recovery master.
+    If one of the other nodes discgrees this is the recovery master, log an error,
+    force a new election and restart monitoring from 1.
+    "Node %d does not agree we are the recmaster. Need a new recmaster election"
+
+15, Check if the previous attempt to run a recovery failed, and if it did, try a new recovery.
+    After the recovery, restart monitoring from 1.
+    "Starting do_recovery"
+
+16, Verify that all CONNECTED nodes in the cluster are in recovery mode NORMAL.
+    If one of the nodes were in recovery mode ACTIVE, force a new recovery and restart
+    monitoring from 1.
+    "Node:%u was in recovery mode. Restart recovery process"
+
+17, Verify that the filehandle to the recovery lock file is valid.
+    If it is not, this may mean a split brain and is a critical error.
+    Try a new recovery and restart monitoring from 1.
+    "recovery master doesn't have the recovery lock"
+
+18, Verify that GPFS allows us to read from the recovery lock file.
+    If not there is a critical GPFS issue and we may have a split brain.
+    Try forcing a new recovery and restart monitoring from 1.
+    "failed read from recovery_lock_fd - %s"
+
+19, Read the list of all nodes and flags from all CONNECTED nodes in the cluster.
+    If fail to read the nodemap from one of the remote nodes, log an error and restart
+    monitoring from 1.
+    "Unable to get nodemap from remote node %u"
+
+20, If the nodemap differs between the local node and the remote node, log an error
+    and force a recovery.
+    This would happen if the /etc/ctdb/nodes file differs across nodes in the cluster.
+    It is unlikely that the recovery will rectify the situation.
+    This is a critical error, it is most likely the entire cluster will be unavailable
+    until the files are fixed or have became banned.
+    "Remote node:%u has different node count. %u vs %u of the local node"
+
+21, If a remote node disagrees on the content of the nodes list, try a recovery and restart
+    monitoring from 1.
+    It is unlikely that the recovery will rectify the situation.
+    This is a critical error, it is most likely the entire cluster will be unavailable
+    until the files are fixed or have became banned.
+    "Remote node:%u has different nodemap pnn for %d (%u vs %u)."
+
+22, If a remote node disgrees on the node flags in the list, try a recovery to re-sync
+    the flags and restart monitoring from 1.
+    "Remote node:%u has different nodemap flag for %d (0x%x vs 0x%x)"
+
+23, Verify that all active nodes are part of the VNNMAP.
+    If not, this would be a new node that has become CONNECTED but does not yet participate
+    in the cluster.
+    Perform a recovery to merge the new node to the cluster and restart monitoring from 1.
+    "The vnnmap count is different from the number of active nodes. %u vs %u"
+    or
+    "Node %u is active in the nodemap but did not exist in the vnnmap"
+
+24, Read the VNNMAP from all CONNECTED nodes.
+    Verify that all nodes have the same VNNMAP content and that all nodes are in the same
+    generation instance of the databases.
+    If not, force a recovery to re-synchronize the vnnmap and the databases across the cluster
+    and restart monitoring from 1.
+    "Remote node %u has different generation of vnnmap. %u vs %u (ours)"
+    "Remote node %u has different size of vnnmap. %u vs %u (ours)"
+    "Remote node %u has different vnnmap."
+
+25, If there has been changes to the cluster that requires a reallocation of public ip
+    addresses. On all nodes run the "startrecovery" event. Run "releaseip" and "takeip"
+    events to reassign the ips across the cluster and finally run the "recovered" event.
+
+Finished monitoring, continue monitoring from 1.
+
+
+CLUSTER RECOVERY
+================
+Recoveries are driven by the recovery daemon on the node that is currently the recovery
+master.
+Most of the logging that is performed during recovery is only logged on the node that
+is the recovery master.
+Make sure to find which node is the recovery master and check the log for that node.
+
+Example log entries that start in column 1 are expected to be present in the
+log. Example log entries that are indented 3 columns are optional and might
+only be present if an error occured.
+
+
+1, Log that recovery has been initiated.
+"Starting do_recovery"
+
+   It might log an informational message :
+"New recovery culprit %u".
+   This is only semi-accurate and might may not mean that there is any problem
+   at all with the node indicated.
+
+
+2, Check if a node has caused too many failed recoveries and if so ban it from
+   the cluster, giving the other nodes in the cluster a chance to recovery
+   operation.
+   "Node %u has caused %u recoveries in %.0f seconds - banning it for %u seconds"
+
+
+3, Verify that the recovery daemon can lock the recovery lock file.
+   At this stage this should be recovery master. 
+   If this operation fails it means we have a split brain and have to abort recovery.
+   "("ctdb_recovery_lock: Unable to open %s - (%s)"
+   "ctdb_recovery_lock: Failed to get recovery lock on '%s'"
+   "Unable to get recovery lock - aborting recovery"
+"ctdb_recovery_lock: Got recovery lock on '%s'"
+
+
+4, Log which node caused the recovery to be initiated.
+   This is a semi-accurate information message only.
+   This line does NOT mean that there has to be something wrong with the node listed.
+"Recovery initiated due to problem with node %u"
+
+
+5, Pull the names of all databases from all nodes and verify that these databases also
+   exists locally.
+   If a database is missing locally, just create it.
+   It is not an error if a database is missing locally. Databases are created on demand and
+   this could happen if it was one database which samba has never tried to access on the
+   local node.
+
+
+6, Check the list of databases on each remote node and create any databases that may be missing
+   on the remote node.
+"Recovery - created remote databases"
+
+
+7, Set recovery mode to ACTIVE on all remote nodes.
+
+
+8, Run the "startrecovery" eventscript on all nodes.
+
+   At this stage you will also get a few additional log entries, these are not
+   from the recovery daemon but from the main ctdb daemon due to running
+   the eventscript :
+"startrecovery eventscript has been invoked"
+"Monitoring has been disabled"
+"Executing event script ...
+...
+
+
+9, Create a new generation id and update the generation id and the VNNMAP on the local node
+   only.
+   This guarantees that the generation id will now be inconsistent across the cluster and
+   that if recovery fails a new recovery is attempted in the next iteration of the monitoring
+   loop.
+
+
+10, Start a TDB TRANSACTION on all nodes for all databases.
+   This is to ensure that if recovery is aborted or fails that we do not
+   modify any databases on only some of the nodes.
+"started transactions on all nodes"
+
+
+11, For each database, pull the content from all CONNECTED nodes and merge it into 
+    the TDB databases on the local node.
+    This merges the records from the remote nodes based on their serial numbers so we
+    only keep the most recent record found.
+"Recovery - pulled remote database 0x%x"
+
+
+12, For each database, perform a fast TDB WIPE operation to delete the entire TDB under the
+    transaction started above.
+
+
+13, For each database, drop all empty records.
+    Force the DMASTER field of all records to point to the recovery master.
+    Push the database out to all other nodes.
+
+    The PUSH process lists some additional log entries for each database of the
+    form :
+"Recovery - pulled remote database 0x..."
+"Recovery - pushed remote database 0x... of size ..."
+
+
+14, Commit all changes to all TDB databases.
+"Recovery - starting database commits"
+"Recovery - committed databases"
+
+
+15, Create a new VNNMAP of all CONNECTED nodes, create a new generation number
+    and piush this new VNNMAP out to all nodes.
+"Recovery - updated vnnmap"
+
+
+16, Update all nodes that the local node is the recovery master.
+"Recovery - updated recmaster"
+
+
+17, synchronize node flags across the cluster.
+"Recovery - updated flags"
+
+18, Change recovery mode back to NORMAL.
+"Recovery - disabled recovery mode"
+
+
+19, Re-allocate all public ip addresses across the cluster.
+"Deterministic IPs enabled. Resetting all ip allocations"
+
+    If the IP address allocation on the local node changes you might get
+    "Takeover of IP 10.0.0.201/24 on interface eth0"
+    "Release of IP 10.0.0.204/24 on interface eth0"
+
+"Recovery - takeip finished"
+
+
+20, Run the "recovered" eventscript on all nodes.
+"Recovery - finished the recovered event"
+
+    You will also get an entry from the local ctdb daemon itself that it has 
+    switched back to recovery mode NORMAL.
+"Recovery has finished"
+
+
+21, Broadcast a message to all samba daemons in the cluster that the databases have been
+    recovered. Samba will now do some additional checking/cleanup of the content in the stored
+    records.
+
+"Recovery complete"
+
+
+22. Finished. At this stage a 10 second timeout (ctdb listvars : rerecoverytimeout) is 
+    initiated. The cluster will not allow a new recovery to be performed until this timeout
+    has expired.
+
+"New recoveries supressed for the rerecovery timeout"
+"Rerecovery timeout elapsed. Recovery reactivated."
+
+
+
+
+
+
+
+Example : RECOVERY LOG ON RECMASTER
+====================================
+2008/12/01 09:57:28.110732 [ 4933]: 10.0.0.21:4379: node 10.0.0.24:4379 is dead: 2 connected
+2008/12/01 09:57:28.110838 [ 4933]: Tearing down connection to dead node :3
+2008/12/01 09:57:28.967297 [ 4935]: server/ctdb_recoverd.c:2682 The vnnmap count is different from the number of active nodes. 4 vs 3
+2008/12/01 09:57:28.967297 [ 4935]: server/ctdb_recoverd.c:1327 Starting do_recovery
+2008/12/01 09:57:28.967297 [ 4935]: ctdb_recovery_lock: Got recovery lock on '/gpfs/.ctdb/shared'
+2008/12/01 09:57:28.967297 [ 4935]: server/ctdb_recoverd.c:1355 Recovery initiated due to problem with node 0
+2008/12/01 09:57:28.967297 [ 4935]: server/ctdb_recoverd.c:1381 Recovery - created remote databases
+2008/12/01 09:57:28.973543 [ 4933]: server/ctdb_recover.c:589 Recovery mode set to ACTIVE
+2008/12/01 09:57:28.974823 [ 4933]: server/ctdb_recover.c:904 startrecovery eventscript has been invoked
+2008/12/01 09:57:29.187264 [ 4935]: server/ctdb_recoverd.c:1431 started transactions on all nodes
+2008/12/01 09:57:29.187264 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x42fe72c5
+2008/12/01 09:57:29.187264 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x42fe72c5 of size 0
+2008/12/01 09:57:29.187264 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x1421fb78
+2008/12/01 09:57:29.197262 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x1421fb78 of size 0
+2008/12/01 09:57:29.197262 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0xc0bdde6a
+2008/12/01 09:57:29.197262 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0xc0bdde6a of size 0
+2008/12/01 09:57:29.197262 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x17055d90
+2008/12/01 09:57:29.207261 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x17055d90 of size 8
+2008/12/01 09:57:29.207261 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x7bbbd26c
+2008/12/01 09:57:29.207261 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x7bbbd26c of size 1
+2008/12/01 09:57:29.207261 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0xf2a58948
+2008/12/01 09:57:29.217259 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0xf2a58948 of size 51
+2008/12/01 09:57:29.217259 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x92380e87
+2008/12/01 09:57:29.217259 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x92380e87 of size 17
+2008/12/01 09:57:29.227258 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x63501287
+2008/12/01 09:57:29.227258 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x63501287 of size 1
+2008/12/01 09:57:29.227258 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0xe98e08b6
+2008/12/01 09:57:29.227258 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0xe98e08b6 of size 4
+2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x2672a57f
+2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x2672a57f of size 28
+2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0xb775fff6
+2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0xb775fff6 of size 6
+2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1440 Recovery - starting database commits
+2008/12/01 09:57:29.297247 [ 4935]: server/ctdb_recoverd.c:1452 Recovery - committed databases
+2008/12/01 09:57:29.297247 [ 4935]: server/ctdb_recoverd.c:1502 Recovery - updated vnnmap
+2008/12/01 09:57:29.297247 [ 4935]: server/ctdb_recoverd.c:1511 Recovery - updated recmaster
+2008/12/01 09:57:29.297247 [ 4935]: server/ctdb_recoverd.c:1522 Recovery - updated flags
+2008/12/01 09:57:29.305235 [ 4933]: server/ctdb_recover.c:589 Recovery mode set to NORMAL
+2008/12/01 09:57:29.307245 [ 4935]: server/ctdb_recoverd.c:1531 Recovery - disabled recovery mode
+2008/12/01 09:57:29.307245 [ 4935]: Deterministic IPs enabled. Resetting all ip allocations
+2008/12/01 09:57:29.311071 [ 4933]: takeoverip called for an ip '10.0.0.201' that is not a public address
+2008/12/01 09:57:29.311186 [ 4933]: takeoverip called for an ip '10.0.0.202' that is not a public address
+2008/12/01 09:57:29.311204 [ 4933]: takeoverip called for an ip '10.0.0.203' that is not a public address
+2008/12/01 09:57:29.311299 [ 4933]: takeoverip called for an ip '10.0.0.204' that is not a public address
+2008/12/01 09:57:29.537210 [ 4935]: server/ctdb_recoverd.c:1542 Recovery - takeip finished
+2008/12/01 09:57:29.545404 [ 4933]: Recovery has finished
+2008/12/01 09:57:29.807169 [ 4935]: server/ctdb_recoverd.c:1551 Recovery - finished the recovered event
+2008/12/01 09:57:29.807169 [ 4935]: server/ctdb_recoverd.c:1557 Recovery complete
+2008/12/01 09:57:29.807169 [ 4935]: server/ctdb_recoverd.c:1565 New recoveries supressed for the rerecovery timeout
+2008/12/01 09:57:39.815648 [ 4935]: server/ctdb_recoverd.c:1567 Rerecovery timeout elapsed. Recovery reactivated.
+
+
+
+
+
+
+
+

Added: branches/ctdb/squeeze-backports/ib/README.txt
===================================================================
--- branches/ctdb/squeeze-backports/ib/README.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/README.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+Compilation
+===========
+
+For the configure script, please set the OFED include & library path by e.g.:
+
+export CFLAGS="-I/usr/local/ofed/include -L/usr/local/ofed/lib"
+
+After then:
+
+./configure --enable-infiniband
+
+Example for testing
+===================
+bin/ctdb_test --transport ib --nlist ../2nodes_rm.txt --listen 10.0.0.1
+bin/ctdb_test --transport ib --nlist ../2nodes_rm.txt --listen 10.0.0.2
+
+where 2nodes_rm.txt:
+10.0.0.1
+10.0.0.2

Added: branches/ctdb/squeeze-backports/ib/config.m4
===================================================================
--- branches/ctdb/squeeze-backports/ib/config.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/config.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+AC_ARG_ENABLE(--enable-infiniband, 
+[  --enable-infiniband         Turn on infiniband support (default=no)])
+
+HAVE_INFINIBAND=no
+
+if eval "test x$enable_infiniband = xyes"; then
+        AC_DEFINE(USE_INFINIBAND,1,[Use infiniband])
+	HAVE_INFINIBAND=yes
+
+	INFINIBAND_WRAPPER_OBJ="ib/ibwrapper.o ib/ibw_ctdb.o ib/ibw_ctdb_init.o"
+	INFINIBAND_LIBS="-lrdmacm -libverbs"
+	INFINIBAND_BINS="tests/bin/ibwrapper_test"
+
+	AC_CHECK_HEADERS(infiniband/verbs.h, [], [
+		echo "ERROR: you need infiniband/verbs.h when ib enabled!"
+		exit -1])
+	AC_CHECK_HEADERS(rdma/rdma_cma.h, [], [
+		echo "ERROR: you need rdma/rdma_cma.h when ib enabled!"
+		exit -1])
+	AC_CHECK_LIB(ibverbs, ibv_create_qp, [], [
+		echo "ERROR: you need libibverbs when ib enabled!"
+		exit -1])
+	AC_CHECK_LIB(rdmacm, rdma_connect, [], [
+		echo "ERROR: you need librdmacm when ib enabled!"
+		exit -1])
+fi
+
+AC_SUBST(HAVE_INFINIBAND)
+AC_SUBST(INFINIBAND_WRAPPER_OBJ)
+AC_SUBST(INFINIBAND_LIBS)
+AC_SUBST(INFINIBAND_BINS)

Added: branches/ctdb/squeeze-backports/ib/ibw_ctdb.c
===================================================================
--- branches/ctdb/squeeze-backports/ib/ibw_ctdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/ibw_ctdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,176 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join infiniband wrapper and ctdb.
+ *
+ * Copyright (C) Sven Oehme <oehmes at de.ibm.com> 2006
+ *
+ * Major code contributions by Peter Somogyi <psomogyi at gamax.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include <system/network.h>
+#include <assert.h>
+#include "ctdb_private.h"
+#include "ibwrapper.h"
+#include "ibw_ctdb.h"
+
+int ctdb_ibw_get_address(struct ctdb_context *ctdb,
+	const char *address, struct in_addr *addr)
+{
+	if (inet_pton(AF_INET, address, addr) <= 0) {
+		struct hostent *he = gethostbyname(address);
+		if (he == NULL || he->h_length > sizeof(*addr)) {
+			ctdb_set_error(ctdb, "invalid nework address '%s'\n", 
+				       address);
+			return -1;
+		}
+		memcpy(addr, he->h_addr, he->h_length);
+	}
+	return 0;
+}
+
+int ctdb_ibw_node_connect(struct ctdb_node *node)
+{
+	struct ctdb_ibw_node *cn = talloc_get_type(node->private_data, struct ctdb_ibw_node);
+	int	rc;
+
+	assert(cn!=NULL);
+	assert(cn->conn!=NULL);
+	struct sockaddr_in sock_out;
+
+	memset(&sock_out, 0, sizeof(struct sockaddr_in));
+	sock_out.sin_port = htons(node->address.port);
+	sock_out.sin_family = PF_INET;
+	if (ctdb_ibw_get_address(node->ctdb, node->address.address, &sock_out.sin_addr)) {
+		DEBUG(DEBUG_ERR, ("ctdb_ibw_node_connect failed\n"));
+		return -1;
+	}
+
+	rc = ibw_connect(cn->conn, &sock_out, node);
+	if (rc) {
+		DEBUG(DEBUG_ERR, ("ctdb_ibw_node_connect/ibw_connect failed - retrying...\n"));
+		/* try again once a second */
+		event_add_timed(node->ctdb->ev, node, timeval_current_ofs(1, 0), 
+			ctdb_ibw_node_connect_event, node);
+	}
+
+	/* continues at ibw_ctdb.c/IBWC_CONNECTED in good case */
+	return 0;
+}
+
+void ctdb_ibw_node_connect_event(struct event_context *ev, struct timed_event *te, 
+	struct timeval t, void *private_data)
+{
+	struct ctdb_node *node = talloc_get_type(private_data, struct ctdb_node);
+
+	ctdb_ibw_node_connect(node);
+}
+
+int ctdb_ibw_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn)
+{
+	if (ctx!=NULL) {
+		/* ctx->state changed */
+		switch(ctx->state) {
+		case IBWS_INIT: /* ctx start - after ibw_init */
+			break;
+		case IBWS_READY: /* after ibw_bind & ibw_listen */
+			break;
+		case IBWS_CONNECT_REQUEST: /* after [IBWS_READY + incoming request] */
+				/* => [(ibw_accept)IBWS_READY | (ibw_disconnect)STOPPED | ERROR] */
+			if (ibw_accept(ctx, conn, NULL)) {
+				DEBUG(DEBUG_ERR, ("connstate_handler/ibw_accept failed\n"));
+				return -1;
+			} /* else continue in IBWC_CONNECTED */
+			break;
+		case IBWS_STOPPED: /* normal stop <= ibw_disconnect+(IBWS_READY | IBWS_CONNECT_REQUEST) */
+			/* TODO: have a CTDB upcall for which CTDB should wait in a (final) loop */
+			break;
+		case IBWS_ERROR: /* abnormal state; ibw_stop must be called after this */
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+
+	if (conn!=NULL) {
+		/* conn->state changed */
+		switch(conn->state) {
+		case IBWC_INIT: /* conn start - internal state */
+			break;
+		case IBWC_CONNECTED: { /* after ibw_accept or ibw_connect */
+			struct ctdb_node *node = talloc_get_type(conn->conn_userdata, struct ctdb_node);
+			if (node!=NULL) { /* after ibw_connect */
+				struct ctdb_ibw_node *cn = talloc_get_type(node->private_data, struct ctdb_ibw_node);
+
+				node->ctdb->upcalls->node_connected(node);
+				ctdb_flush_cn_queue(cn);
+			} else { /* after ibw_accept */
+				/* NOP in CTDB case */
+			}
+		} break;
+		case IBWC_DISCONNECTED: { /* after ibw_disconnect */
+			struct ctdb_node *node = talloc_get_type(conn->conn_userdata, struct ctdb_node);
+			if (node!=NULL)
+				node->ctdb->upcalls->node_dead(node);
+			talloc_free(conn);
+			/* normal + intended disconnect => not reconnecting in this layer */
+		} break;
+		case IBWC_ERROR: {
+			struct ctdb_node *node = talloc_get_type(conn->conn_userdata, struct ctdb_node);
+			if (node!=NULL) {
+				struct ctdb_ibw_node *cn = talloc_get_type(node->private_data, struct ctdb_ibw_node);
+				struct ibw_ctx *ictx = cn->conn->ctx;
+
+				DEBUG(DEBUG_DEBUG, ("IBWC_ERROR, reconnecting...\n"));
+				talloc_free(cn->conn); /* internal queue content is destroyed */
+				cn->conn = (void *)ibw_conn_new(ictx, node);
+				event_add_timed(node->ctdb->ev, node, timeval_current_ofs(1, 0),
+					ctdb_ibw_node_connect_event, node);
+			}
+		} break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int ctdb_ibw_receive_handler(struct ibw_conn *conn, void *buf, int n)
+{
+	struct ctdb_context *ctdb = talloc_get_type(conn->ctx->ctx_userdata, struct ctdb_context);
+	void	*buf2; /* future TODO: a solution for removal of this */
+
+	assert(ctdb!=NULL);
+	assert(buf!=NULL);
+	assert(conn!=NULL);
+	assert(conn->state==IBWC_CONNECTED);
+
+	/* so far "buf" is an ib-registered memory area
+	 * and being reused for next receive
+	 * noticed that HL requires talloc-ed memory to be stolen */
+	buf2 = talloc_zero_size(conn, n);
+	CTDB_NO_MEMORY(ctdb, buf2);
+
+	memcpy(buf2, buf, n);
+
+	ctdb->upcalls->recv_pkt(ctdb, (uint8_t *)buf2, (uint32_t)n);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/ib/ibw_ctdb.h
===================================================================
--- branches/ctdb/squeeze-backports/ib/ibw_ctdb.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/ibw_ctdb.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,50 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join infiniband wrapper and ctdb.
+ *
+ * Copyright (C) Sven Oehme <oehmes at de.ibm.com> 2006
+ *
+ * Major code contributions by Peter Somogyi <psomogyi at gamax.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+struct ctdb_ibw_msg {
+	uint8_t *data;
+	uint32_t length;
+	struct ctdb_ibw_msg *prev;
+	struct ctdb_ibw_msg *next;
+};
+
+struct ctdb_ibw_node {
+	struct ibw_conn *conn;
+
+	struct ctdb_ibw_msg *queue;
+	struct ctdb_ibw_msg *queue_last;
+	int	qcnt;
+};
+
+int ctdb_ibw_get_address(struct ctdb_context *ctdb,
+	const char *address, struct in_addr *addr);
+
+int ctdb_ibw_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn);
+int ctdb_ibw_receive_handler(struct ibw_conn *conn, void *buf, int n);
+
+int ctdb_ibw_node_connect(struct ctdb_node *node);
+void ctdb_ibw_node_connect_event(struct event_context *ev, struct timed_event *te, 
+	struct timeval t, void *private_data);
+
+int ctdb_flush_cn_queue(struct ctdb_ibw_node *cn);
+
+int ctdb_ibw_init(struct ctdb_context *ctdb);

Added: branches/ctdb/squeeze-backports/ib/ibw_ctdb_init.c
===================================================================
--- branches/ctdb/squeeze-backports/ib/ibw_ctdb_init.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/ibw_ctdb_init.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,248 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join infiniband wrapper and ctdb.
+ *
+ * Copyright (C) Sven Oehme <oehmes at de.ibm.com> 2006
+ *
+ * Major code contributions by Peter Somogyi <psomogyi at gamax.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include <system/network.h>
+#include <assert.h>
+#include "ctdb_private.h"
+#include "ibwrapper.h"
+#include "ibw_ctdb.h"
+
+static int ctdb_ibw_listen(struct ctdb_context *ctdb, int backlog)
+{
+	struct ibw_ctx *ictx = talloc_get_type(ctdb->private_data, struct ibw_ctx);
+	struct sockaddr_in my_addr;
+
+	assert(ictx!=NULL);
+	memset(&my_addr, 0, sizeof(struct sockaddr_in));
+	my_addr.sin_port = htons(ctdb->address.port);
+	my_addr.sin_family = PF_INET;
+	if (ctdb_ibw_get_address(ctdb, ctdb->address.address, &my_addr.sin_addr))
+		return -1;
+
+	if (ibw_bind(ictx, &my_addr)) {
+		DEBUG(DEBUG_CRIT, ("ctdb_ibw_listen: ibw_bind failed\n"));
+		return -1;
+	}
+
+	if (ibw_listen(ictx, backlog)) {
+		DEBUG(DEBUG_CRIT, ("ctdb_ibw_listen: ibw_listen failed\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * initialise ibw portion of a ctdb node 
+ */
+static int ctdb_ibw_add_node(struct ctdb_node *node)
+{
+	struct ibw_ctx *ictx = talloc_get_type(node->ctdb->private_data, struct ibw_ctx);
+	struct ctdb_ibw_node *cn = talloc_zero(node, struct ctdb_ibw_node);
+
+	assert(cn!=NULL);
+	cn->conn = ibw_conn_new(ictx, node);
+	node->private_data = (void *)cn;
+
+	return (cn->conn!=NULL ? 0 : -1);
+}
+
+/*
+ * initialise infiniband
+ */
+static int ctdb_ibw_initialise(struct ctdb_context *ctdb)
+{
+	int i, ret;
+
+	ret = ctdb_ibw_init(ctdb);
+	if (ret != 0) {
+		return ret;
+	}
+
+	for (i=0; i<ctdb->num_nodes; i++) {
+		if (ctdb_ibw_add_node(ctdb->nodes[i]) != 0) {
+			DEBUG(DEBUG_CRIT, ("methods->add_node failed at %d\n", i));
+			return -1;
+		}
+	}
+
+	/* listen on our own address */
+	if (ctdb_ibw_listen(ctdb, 10)) /* TODO: backlog as param */
+		return -1;
+
+	return 0;
+}
+
+
+/*
+ * Start infiniband
+ */
+static int ctdb_ibw_start(struct ctdb_context *ctdb)
+{
+	int i, ret;
+
+	/* everything async here */
+	for (i=0;i<ctdb->num_nodes;i++) {
+		struct ctdb_node *node = ctdb->nodes[i];
+		if (!ctdb_same_address(&ctdb->address, &node->address)) {
+			ctdb_ibw_node_connect(node);
+		}
+	}
+
+	return 0;
+}
+
+static int ctdb_ibw_send_pkt(struct ibw_conn *conn, uint8_t *data, uint32_t length)
+{
+	void	*buf, *key;
+
+	if (ibw_alloc_send_buf(conn, &buf, &key, length)) {
+		DEBUG(DEBUG_ERR, ("queue_pkt/ibw_alloc_send_buf failed\n"));
+		return -1;
+	}
+
+	memcpy(buf, data, length);
+	return ibw_send(conn, buf, key, length);
+}
+
+int ctdb_flush_cn_queue(struct ctdb_ibw_node *cn)
+{
+	struct ctdb_ibw_msg *p;
+	int	rc = 0;
+
+	while(cn->queue) {
+		p = cn->queue;
+		rc = ctdb_ibw_send_pkt(cn->conn, p->data, p->length);
+		if (rc)
+			return -1; /* will be retried later when conn is up */
+
+		DLIST_REMOVE(cn->queue, p);
+		cn->qcnt--;
+		talloc_free(p); /* it will talloc_free p->data as well */
+	}
+	assert(cn->qcnt==0);
+	/* cn->queue_last = NULL is not needed - see DLIST_ADD_AFTER */
+
+	return rc;
+}
+
+static int ctdb_ibw_queue_pkt(struct ctdb_node *node, uint8_t *data, uint32_t length)
+{
+	struct ctdb_ibw_node *cn = talloc_get_type(node->private_data, struct ctdb_ibw_node);
+	int	rc;
+
+	assert(length>=sizeof(uint32_t));
+	assert(cn!=NULL);
+
+	if (cn->conn==NULL) {
+		DEBUG(DEBUG_ERR, ("ctdb_ibw_queue_pkt: conn is NULL\n"));
+		return -1;
+	}
+
+	if (cn->conn->state==IBWC_CONNECTED) {
+		rc = ctdb_ibw_send_pkt(cn->conn, data, length);
+	} else {
+		struct ctdb_ibw_msg *p = talloc_zero(cn, struct ctdb_ibw_msg);
+		CTDB_NO_MEMORY(node->ctdb, p);
+
+		p->data = talloc_memdup(p, data, length);
+		CTDB_NO_MEMORY(node->ctdb, p->data);
+
+		p->length = length;
+
+		DLIST_ADD_AFTER(cn->queue, p, cn->queue_last);
+		cn->queue_last = p;
+		cn->qcnt++;
+
+		rc = 0;
+	}
+
+	return rc;
+}
+
+static void ctdb_ibw_restart(struct ctdb_node *node)
+{
+	/* TODO: implement this method for IB */
+	DEBUG(DEBUG_ALERT,("WARNING: method restart is not yet implemented for IB\n"));
+}
+
+/*
+ * transport packet allocator - allows transport to control memory for packets
+ */
+static void *ctdb_ibw_allocate_pkt(TALLOC_CTX *mem_ctx, size_t size)
+{
+	/* TODO: use ibw_alloc_send_buf instead... */
+	return talloc_size(mem_ctx, size);
+}
+
+#ifdef __NOTDEF__
+
+static int ctdb_ibw_stop(struct ctdb_context *cctx)
+{
+	struct ibw_ctx *ictx = talloc_get_type(cctx->private_data, struct ibw_ctx);
+
+	assert(ictx!=NULL);
+	return ibw_stop(ictx);
+}
+
+#endif /* __NOTDEF__ */
+
+static const struct ctdb_methods ctdb_ibw_methods = {
+	.initialise= ctdb_ibw_initialise,
+	.start     = ctdb_ibw_start,
+	.queue_pkt = ctdb_ibw_queue_pkt,
+	.add_node = ctdb_ibw_add_node,
+	.allocate_pkt = ctdb_ibw_allocate_pkt,
+	.restart      = ctdb_ibw_restart,
+
+//	.stop = ctdb_ibw_stop
+};
+
+/*
+ * initialise ibw portion of ctdb 
+ */
+int ctdb_ibw_init(struct ctdb_context *ctdb)
+{
+	struct ibw_ctx *ictx;
+
+	DEBUG(DEBUG_DEBUG, ("ctdb_ibw_init invoked...\n"));
+	ictx = ibw_init(
+		NULL, //struct ibw_initattr *attr, /* TODO */
+		0, //int nattr, /* TODO */
+		ctdb,
+		ctdb_ibw_connstate_handler,
+		ctdb_ibw_receive_handler,
+		ctdb->ev);
+
+	if (ictx==NULL) {
+		DEBUG(DEBUG_CRIT, ("ctdb_ibw_init: ibw_init failed\n"));
+		return -1;
+	}
+
+	ctdb->methods = &ctdb_ibw_methods;
+	ctdb->private_data = ictx;
+	
+	DEBUG(DEBUG_DEBUG, ("ctdb_ibw_init succeeded.\n"));
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/ib/ibwrapper.c
===================================================================
--- branches/ctdb/squeeze-backports/ib/ibwrapper.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/ibwrapper.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1365 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Wrap Infiniband calls.
+ *
+ * Copyright (C) Sven Oehme <oehmes at de.ibm.com> 2006
+ *
+ * Major code contributions by Peter Somogyi <psomogyi at gamax.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <malloc.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "ibwrapper.h"
+
+#include <infiniband/kern-abi.h>
+#include <rdma/rdma_cma_abi.h>
+#include <rdma/rdma_cma.h>
+
+#include "ibwrapper_internal.h"
+#include "lib/util/dlinklist.h"
+
+#define IBW_LASTERR_BUFSIZE 512
+static char ibw_lasterr[IBW_LASTERR_BUFSIZE];
+
+#define IBW_MAX_SEND_WR 256
+#define IBW_MAX_RECV_WR 1024
+#define IBW_RECV_BUFSIZE 256
+#define IBW_RECV_THRESHOLD (1 * 1024 * 1024)
+
+static void ibw_event_handler_verbs(struct event_context *ev,
+	struct fd_event *fde, uint16_t flags, void *private_data);
+static int ibw_fill_cq(struct ibw_conn *conn);
+static int ibw_wc_recv(struct ibw_conn *conn, struct ibv_wc *wc);
+static int ibw_wc_send(struct ibw_conn *conn, struct ibv_wc *wc);
+static int ibw_send_packet(struct ibw_conn *conn, void *buf, struct ibw_wr *p, uint32_t len);
+
+static void *ibw_alloc_mr(struct ibw_ctx_priv *pctx, struct ibw_conn_priv *pconn,
+	uint32_t n, struct ibv_mr **ppmr)
+{
+	void *buf;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_alloc_mr(cmid=%p, n=%u)\n", pconn->cm_id, n));
+	buf = memalign(pctx->pagesize, n);
+	if (!buf) {
+		sprintf(ibw_lasterr, "couldn't allocate memory\n");
+		return NULL;
+	}
+
+	*ppmr = ibv_reg_mr(pconn->pd, buf, n, IBV_ACCESS_LOCAL_WRITE);
+	if (!*ppmr) {
+		sprintf(ibw_lasterr, "couldn't allocate mr\n");
+		free(buf);
+		return NULL;
+	}
+
+	return buf;
+}
+
+static void ibw_free_mr(char **ppbuf, struct ibv_mr **ppmr)
+{
+	DEBUG(DEBUG_DEBUG, ("ibw_free_mr(%p %p)\n", *ppbuf, *ppmr));
+	if (*ppmr!=NULL) {
+		ibv_dereg_mr(*ppmr);
+		*ppmr = NULL;
+	}
+	if (*ppbuf) {
+		free(*ppbuf);
+		*ppbuf = NULL;
+	}
+}
+
+static int ibw_init_memory(struct ibw_conn *conn)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct ibw_opts *opts = &pctx->opts;
+	int	i;
+	struct ibw_wr	*p;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_init_memory(cmid: %p)\n", pconn->cm_id));
+	pconn->buf_send = ibw_alloc_mr(pctx, pconn,
+		opts->max_send_wr * opts->recv_bufsize, &pconn->mr_send);
+	if (!pconn->buf_send) {
+		sprintf(ibw_lasterr, "couldn't allocate work send buf\n");
+		return -1;
+	}
+
+	pconn->buf_recv = ibw_alloc_mr(pctx, pconn,
+		opts->max_recv_wr * opts->recv_bufsize, &pconn->mr_recv);
+	if (!pconn->buf_recv) {
+		sprintf(ibw_lasterr, "couldn't allocate work recv buf\n");
+		return -1;
+	}
+
+	pconn->wr_index = talloc_size(pconn, opts->max_send_wr * sizeof(struct ibw_wr *));
+	assert(pconn->wr_index!=NULL);
+
+	for(i=0; i<opts->max_send_wr; i++) {
+		p = pconn->wr_index[i] = talloc_zero(pconn, struct ibw_wr);
+		p->buf = pconn->buf_send + (i * opts->recv_bufsize);
+		p->wr_id = i;
+
+		DLIST_ADD(pconn->wr_list_avail, p);
+	}
+
+	return 0;
+}
+
+static int ibw_ctx_priv_destruct(struct ibw_ctx_priv *pctx)
+{
+	DEBUG(DEBUG_DEBUG, ("ibw_ctx_priv_destruct(%p)\n", pctx));
+
+	/* destroy cm */
+	if (pctx->cm_channel) {
+		rdma_destroy_event_channel(pctx->cm_channel);
+		pctx->cm_channel = NULL;
+	}
+	if (pctx->cm_channel_event) {
+		/* TODO: do we have to do this here? */
+		talloc_free(pctx->cm_channel_event);
+		pctx->cm_channel_event = NULL;
+	}
+	if (pctx->cm_id) {
+		rdma_destroy_id(pctx->cm_id);
+		pctx->cm_id = NULL;
+	}
+
+	return 0;
+}
+
+static int ibw_ctx_destruct(struct ibw_ctx *ctx)
+{
+	DEBUG(DEBUG_DEBUG, ("ibw_ctx_destruct(%p)\n", ctx));
+	return 0;
+}
+
+static int ibw_conn_priv_destruct(struct ibw_conn_priv *pconn)
+{
+	DEBUG(DEBUG_DEBUG, ("ibw_conn_priv_destruct(%p, cmid: %p)\n",
+		pconn, pconn->cm_id));
+
+	/* pconn->wr_index is freed by talloc */
+	/* pconn->wr_index[i] are freed by talloc */
+
+	/* destroy verbs */
+	if (pconn->cm_id!=NULL && pconn->cm_id->qp!=NULL) {
+		rdma_destroy_qp(pconn->cm_id);
+		pconn->cm_id->qp = NULL;
+	}
+
+	if (pconn->cq!=NULL) {
+		ibv_destroy_cq(pconn->cq);
+		pconn->cq = NULL;
+	}
+
+	if (pconn->verbs_channel!=NULL) {
+		ibv_destroy_comp_channel(pconn->verbs_channel);
+		pconn->verbs_channel = NULL;
+	}
+
+	/* must be freed here because its order is important */
+	if (pconn->verbs_channel_event) {
+		talloc_free(pconn->verbs_channel_event);
+		pconn->verbs_channel_event = NULL;
+	}
+
+	/* free memory regions */
+	ibw_free_mr(&pconn->buf_send, &pconn->mr_send);
+	ibw_free_mr(&pconn->buf_recv, &pconn->mr_recv);
+
+	if (pconn->pd) {
+		ibv_dealloc_pd(pconn->pd);
+		pconn->pd = NULL;
+		DEBUG(DEBUG_DEBUG, ("pconn=%p pd deallocated\n", pconn));
+	}
+
+	if (pconn->cm_id) {
+		rdma_destroy_id(pconn->cm_id);
+		pconn->cm_id = NULL;
+		DEBUG(DEBUG_DEBUG, ("pconn=%p cm_id destroyed\n", pconn));
+	}
+
+	return 0;
+}
+
+static int ibw_wr_destruct(struct ibw_wr *wr)
+{
+	if (wr->buf_large!=NULL)
+		ibw_free_mr(&wr->buf_large, &wr->mr_large);
+	return 0;
+}
+
+static int ibw_conn_destruct(struct ibw_conn *conn)
+{
+	DEBUG(DEBUG_DEBUG, ("ibw_conn_destruct(%p)\n", conn));
+	
+	/* important here: ctx is a talloc _parent_ */
+	DLIST_REMOVE(conn->ctx->conn_list, conn);
+	return 0;
+}
+
+struct ibw_conn *ibw_conn_new(struct ibw_ctx *ctx, TALLOC_CTX *mem_ctx)
+{
+	struct ibw_conn *conn;
+	struct ibw_conn_priv *pconn;
+
+	assert(ctx!=NULL);
+
+	conn = talloc_zero(mem_ctx, struct ibw_conn);
+	assert(conn!=NULL);
+	talloc_set_destructor(conn, ibw_conn_destruct);
+
+	pconn = talloc_zero(conn, struct ibw_conn_priv);
+	assert(pconn!=NULL);
+	talloc_set_destructor(pconn, ibw_conn_priv_destruct);
+
+	conn->ctx = ctx;
+	conn->internal = (void *)pconn;
+
+	DLIST_ADD(ctx->conn_list, conn);
+
+	return conn;
+}
+
+static int ibw_setup_cq_qp(struct ibw_conn *conn)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct ibv_qp_init_attr init_attr;
+	struct ibv_qp_attr attr;
+	int rc;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_setup_cq_qp(cmid: %p)\n", pconn->cm_id));
+
+	/* init verbs */
+	pconn->verbs_channel = ibv_create_comp_channel(pconn->cm_id->verbs);
+	if (!pconn->verbs_channel) {
+		sprintf(ibw_lasterr, "ibv_create_comp_channel failed %d\n", errno);
+		return -1;
+	}
+	DEBUG(DEBUG_DEBUG, ("created channel %p\n", pconn->verbs_channel));
+
+	pconn->verbs_channel_event = event_add_fd(pctx->ectx, NULL, /* not pconn or conn */
+		pconn->verbs_channel->fd, EVENT_FD_READ, ibw_event_handler_verbs, conn);
+
+	pconn->pd = ibv_alloc_pd(pconn->cm_id->verbs);
+	if (!pconn->pd) {
+		sprintf(ibw_lasterr, "ibv_alloc_pd failed %d\n", errno);
+		return -1;
+	}
+	DEBUG(DEBUG_DEBUG, ("created pd %p\n", pconn->pd));
+
+	/* init mr */
+	if (ibw_init_memory(conn))
+		return -1;
+
+	/* init cq */
+	pconn->cq = ibv_create_cq(pconn->cm_id->verbs,
+		pctx->opts.max_recv_wr + pctx->opts.max_send_wr,
+		conn, pconn->verbs_channel, 0);
+	if (pconn->cq==NULL) {
+		sprintf(ibw_lasterr, "ibv_create_cq failed\n");
+		return -1;
+	}
+
+	rc = ibv_req_notify_cq(pconn->cq, 0);
+	if (rc) {
+		sprintf(ibw_lasterr, "ibv_req_notify_cq failed with %d\n", rc);
+		return rc;
+	}
+
+	/* init qp */
+	memset(&init_attr, 0, sizeof(init_attr));
+	init_attr.cap.max_send_wr = pctx->opts.max_send_wr;
+	init_attr.cap.max_recv_wr = pctx->opts.max_recv_wr;
+	init_attr.cap.max_recv_sge = 1;
+	init_attr.cap.max_send_sge = 1;
+	init_attr.qp_type = IBV_QPT_RC;
+	init_attr.send_cq = pconn->cq;
+	init_attr.recv_cq = pconn->cq;
+
+	rc = rdma_create_qp(pconn->cm_id, pconn->pd, &init_attr);
+	if (rc) {
+		sprintf(ibw_lasterr, "rdma_create_qp failed with %d\n", rc);
+		return rc;
+	}
+	/* elase result is in pconn->cm_id->qp */
+
+	rc = ibv_query_qp(pconn->cm_id->qp, &attr, IBV_QP_PATH_MTU, &init_attr);
+	if (rc) {
+		sprintf(ibw_lasterr, "ibv_query_qp failed with %d\n", rc);
+		return rc;
+	}
+
+	return ibw_fill_cq(conn);
+}
+
+static int ibw_refill_cq_recv(struct ibw_conn *conn)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	int	rc;
+	struct ibv_sge list = {
+		.addr 	= (uintptr_t) NULL, /* filled below */
+		.length = pctx->opts.recv_bufsize,
+		.lkey 	= pconn->mr_recv->lkey /* always the same */
+	};
+	struct ibv_recv_wr wr = {
+		.wr_id 	    = 0, /* filled below */
+		.sg_list    = &list,
+		.num_sge    = 1,
+	};
+	struct ibv_recv_wr *bad_wr;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_refill_cq_recv(cmid: %p)\n", pconn->cm_id));
+
+	list.addr = (uintptr_t) pconn->buf_recv + pctx->opts.recv_bufsize * pconn->recv_index;
+	wr.wr_id = pconn->recv_index;
+	pconn->recv_index = (pconn->recv_index + 1) % pctx->opts.max_recv_wr;
+
+	rc = ibv_post_recv(pconn->cm_id->qp, &wr, &bad_wr);
+	if (rc) {
+		sprintf(ibw_lasterr, "refill/ibv_post_recv failed with %d\n", rc);
+		DEBUG(DEBUG_ERR, (ibw_lasterr));
+		return -2;
+	}
+
+	return 0;
+}
+
+static int ibw_fill_cq(struct ibw_conn *conn)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	int	i, rc;
+	struct ibv_sge list = {
+		.addr 	= (uintptr_t) NULL, /* filled below */
+		.length = pctx->opts.recv_bufsize,
+		.lkey 	= pconn->mr_recv->lkey /* always the same */
+	};
+	struct ibv_recv_wr wr = {
+		.wr_id 	    = 0, /* filled below */
+		.sg_list    = &list,
+		.num_sge    = 1,
+	};
+	struct ibv_recv_wr *bad_wr;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_fill_cq(cmid: %p)\n", pconn->cm_id));
+
+	for(i = pctx->opts.max_recv_wr; i!=0; i--) {
+		list.addr = (uintptr_t) pconn->buf_recv + pctx->opts.recv_bufsize * pconn->recv_index;
+		wr.wr_id = pconn->recv_index;
+		pconn->recv_index = (pconn->recv_index + 1) % pctx->opts.max_recv_wr;
+
+		rc = ibv_post_recv(pconn->cm_id->qp, &wr, &bad_wr);
+		if (rc) {
+			sprintf(ibw_lasterr, "fill/ibv_post_recv failed with %d\n", rc);
+			DEBUG(DEBUG_ERR, (ibw_lasterr));
+			return -2;
+		}
+	}
+
+	return 0;
+}
+
+static int ibw_manage_connect(struct ibw_conn *conn)
+{
+	struct rdma_conn_param conn_param;
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	int	rc;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_manage_connect(cmid: %p)\n", pconn->cm_id));
+
+	if (ibw_setup_cq_qp(conn))
+		return -1;
+
+	/* cm connect */
+	memset(&conn_param, 0, sizeof conn_param);
+	conn_param.responder_resources = 1;
+	conn_param.initiator_depth = 1;
+	conn_param.retry_count = 10;
+
+	rc = rdma_connect(pconn->cm_id, &conn_param);
+	if (rc)
+		sprintf(ibw_lasterr, "rdma_connect error %d\n", rc);
+
+	return rc;
+}
+
+static void ibw_event_handler_cm(struct event_context *ev,
+	struct fd_event *fde, uint16_t flags, void *private_data)
+{
+	int	rc;
+	struct ibw_ctx	*ctx = talloc_get_type(private_data, struct ibw_ctx);
+	struct ibw_ctx_priv *pctx = talloc_get_type(ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn *conn = NULL;
+	struct ibw_conn_priv *pconn = NULL;
+	struct rdma_cm_id *cma_id = NULL;
+	struct rdma_cm_event *event = NULL;
+
+	assert(ctx!=NULL);
+
+	rc = rdma_get_cm_event(pctx->cm_channel, &event);
+	if (rc) {
+		ctx->state = IBWS_ERROR;
+		event = NULL;
+		sprintf(ibw_lasterr, "rdma_get_cm_event error %d\n", rc);
+		goto error;
+	}
+	cma_id = event->id;
+
+	DEBUG(DEBUG_DEBUG, ("cma_event type %d cma_id %p (%s)\n", event->event, cma_id,
+		  (cma_id == pctx->cm_id) ? "parent" : "child"));
+
+	switch (event->event) {
+	case RDMA_CM_EVENT_ADDR_RESOLVED:
+		DEBUG(DEBUG_DEBUG, ("RDMA_CM_EVENT_ADDR_RESOLVED\n"));
+		/* continuing from ibw_connect ... */
+		rc = rdma_resolve_route(cma_id, 2000);
+		if (rc) {
+			sprintf(ibw_lasterr, "rdma_resolve_route error %d\n", rc);
+			goto error;
+		}
+		/* continued at RDMA_CM_EVENT_ROUTE_RESOLVED */
+		break;
+
+	case RDMA_CM_EVENT_ROUTE_RESOLVED:
+		DEBUG(DEBUG_DEBUG, ("RDMA_CM_EVENT_ROUTE_RESOLVED\n"));
+		/* after RDMA_CM_EVENT_ADDR_RESOLVED: */
+		assert(cma_id->context!=NULL);
+		conn = talloc_get_type(cma_id->context, struct ibw_conn);
+
+		rc = ibw_manage_connect(conn);
+		if (rc)
+			goto error;
+
+		break;
+
+	case RDMA_CM_EVENT_CONNECT_REQUEST:
+		DEBUG(DEBUG_DEBUG, ("RDMA_CM_EVENT_CONNECT_REQUEST\n"));
+		ctx->state = IBWS_CONNECT_REQUEST;
+		conn = ibw_conn_new(ctx, ctx);
+		pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+		pconn->cm_id = cma_id; /* !!! event will be freed but id not */
+		cma_id->context = (void *)conn;
+		DEBUG(DEBUG_DEBUG, ("pconn->cm_id %p\n", pconn->cm_id));
+
+		if (ibw_setup_cq_qp(conn))
+			goto error;
+
+		conn->state = IBWC_INIT;
+		pctx->connstate_func(ctx, conn);
+
+		/* continued at ibw_accept when invoked by the func above */
+		if (!pconn->is_accepted) {
+			rc = rdma_reject(cma_id, NULL, 0);
+			if (rc)
+				DEBUG(DEBUG_ERR, ("rdma_reject failed with rc=%d\n", rc));
+			talloc_free(conn);
+			DEBUG(DEBUG_DEBUG, ("pconn->cm_id %p wasn't accepted\n", pconn->cm_id));
+		}
+
+		/* TODO: clarify whether if it's needed by upper layer: */
+		ctx->state = IBWS_READY;
+		pctx->connstate_func(ctx, NULL);
+
+		/* NOTE: more requests can arrive until RDMA_CM_EVENT_ESTABLISHED ! */
+		break;
+
+	case RDMA_CM_EVENT_ESTABLISHED:
+		/* expected after ibw_accept and ibw_connect[not directly] */
+		DEBUG(DEBUG_INFO, ("ESTABLISHED (conn: %p)\n", cma_id->context));
+		conn = talloc_get_type(cma_id->context, struct ibw_conn);
+		assert(conn!=NULL); /* important assumption */
+
+		DEBUG(DEBUG_DEBUG, ("ibw_setup_cq_qp succeeded (cmid=%p)\n", cma_id));
+
+		/* client conn is up */
+		conn->state = IBWC_CONNECTED;
+
+		/* both ctx and conn have changed */
+		pctx->connstate_func(ctx, conn);
+		break;
+
+	case RDMA_CM_EVENT_ADDR_ERROR:
+		sprintf(ibw_lasterr, "RDMA_CM_EVENT_ADDR_ERROR, error %d\n", event->status);
+	case RDMA_CM_EVENT_ROUTE_ERROR:
+		sprintf(ibw_lasterr, "RDMA_CM_EVENT_ROUTE_ERROR, error %d\n", event->status);
+	case RDMA_CM_EVENT_CONNECT_ERROR:
+		sprintf(ibw_lasterr, "RDMA_CM_EVENT_CONNECT_ERROR, error %d\n", event->status);
+	case RDMA_CM_EVENT_UNREACHABLE:
+		sprintf(ibw_lasterr, "RDMA_CM_EVENT_UNREACHABLE, error %d\n", event->status);
+		goto error;
+	case RDMA_CM_EVENT_REJECTED:
+		sprintf(ibw_lasterr, "RDMA_CM_EVENT_REJECTED, error %d\n", event->status);
+		DEBUG(DEBUG_INFO, ("cm event handler: %s", ibw_lasterr));
+		conn = talloc_get_type(cma_id->context, struct ibw_conn);
+		if (conn) {
+			/* must be done BEFORE connstate */
+			if ((rc=rdma_ack_cm_event(event)))
+				DEBUG(DEBUG_ERR, ("reject/rdma_ack_cm_event failed with %d\n", rc));
+			event = NULL; /* not to touch cma_id or conn */
+			conn->state = IBWC_ERROR;
+			/* it should free the conn */
+			pctx->connstate_func(NULL, conn);
+		}
+		break; /* this is not strictly an error */
+
+	case RDMA_CM_EVENT_DISCONNECTED:
+		DEBUG(DEBUG_DEBUG, ("RDMA_CM_EVENT_DISCONNECTED\n"));
+		if ((rc=rdma_ack_cm_event(event)))
+			DEBUG(DEBUG_ERR, ("disc/rdma_ack_cm_event failed with %d\n", rc));
+		event = NULL; /* don't ack more */
+
+		if (cma_id!=pctx->cm_id) {
+			DEBUG(DEBUG_ERR, ("client DISCONNECT event cm_id=%p\n", cma_id));
+			conn = talloc_get_type(cma_id->context, struct ibw_conn);
+			conn->state = IBWC_DISCONNECTED;
+			pctx->connstate_func(NULL, conn);
+		}
+		break;
+
+	case RDMA_CM_EVENT_DEVICE_REMOVAL:
+		sprintf(ibw_lasterr, "cma detected device removal!\n");
+		goto error;
+
+	default:
+		sprintf(ibw_lasterr, "unknown event %d\n", event->event);
+		goto error;
+	}
+
+	if (event!=NULL && (rc=rdma_ack_cm_event(event))) {
+		sprintf(ibw_lasterr, "rdma_ack_cm_event failed with %d\n", rc);
+		goto error;
+	}
+
+	return;
+error:
+	DEBUG(DEBUG_ERR, ("cm event handler: %s", ibw_lasterr));
+
+	if (event!=NULL) {
+		if (cma_id!=NULL && cma_id!=pctx->cm_id) {
+			conn = talloc_get_type(cma_id->context, struct ibw_conn);
+			if (conn) {
+				conn->state = IBWC_ERROR;
+				pctx->connstate_func(NULL, conn);
+			}
+		} else {
+			ctx->state = IBWS_ERROR;
+			pctx->connstate_func(ctx, NULL);
+		}
+
+		if ((rc=rdma_ack_cm_event(event))!=0) {
+			DEBUG(DEBUG_ERR, ("rdma_ack_cm_event failed with %d\n", rc));
+		}
+	}
+
+	return;
+}
+
+static void ibw_event_handler_verbs(struct event_context *ev,
+	struct fd_event *fde, uint16_t flags, void *private_data)
+{
+	struct ibw_conn	*conn = talloc_get_type(private_data, struct ibw_conn);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+
+	struct ibv_wc wc;
+	int rc;
+	struct ibv_cq *ev_cq;
+	void          *ev_ctx;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_event_handler_verbs(%u)\n", (uint32_t)flags));
+
+	/* TODO: check whether if it's good to have more channels here... */
+	rc = ibv_get_cq_event(pconn->verbs_channel, &ev_cq, &ev_ctx);
+	if (rc) {
+		sprintf(ibw_lasterr, "Failed to get cq_event with %d\n", rc);
+		goto error;
+	}
+	if (ev_cq != pconn->cq) {
+		sprintf(ibw_lasterr, "ev_cq(%p) != pconn->cq(%p)\n", ev_cq, pconn->cq);
+		goto error;
+	}
+	rc = ibv_req_notify_cq(pconn->cq, 0);
+	if (rc) {
+		sprintf(ibw_lasterr, "Couldn't request CQ notification (%d)\n", rc);
+		goto error;
+	}
+
+	while((rc=ibv_poll_cq(pconn->cq, 1, &wc))==1) {
+		if (wc.status) {
+			sprintf(ibw_lasterr, "cq completion failed status=%d, opcode=%d, rc=%d\n",
+				wc.status, wc.opcode, rc);
+			goto error;
+		}
+
+		switch(wc.opcode) {
+		case IBV_WC_SEND:
+			DEBUG(DEBUG_DEBUG, ("send completion\n"));
+			if (ibw_wc_send(conn, &wc))
+				goto error;
+			break;
+
+		case IBV_WC_RDMA_WRITE:
+			DEBUG(DEBUG_DEBUG, ("rdma write completion\n"));
+			break;
+	
+		case IBV_WC_RDMA_READ:
+			DEBUG(DEBUG_DEBUG, ("rdma read completion\n"));
+			break;
+
+		case IBV_WC_RECV:
+			DEBUG(DEBUG_DEBUG, ("recv completion\n"));
+			if (ibw_wc_recv(conn, &wc))
+				goto error;
+			break;
+
+		default:
+			sprintf(ibw_lasterr, "unknown completion %d\n", wc.opcode);
+			goto error;
+		}
+	}
+	if (rc!=0) {
+		sprintf(ibw_lasterr, "ibv_poll_cq error %d\n", rc);
+		goto error;
+	}
+
+	ibv_ack_cq_events(pconn->cq, 1);
+
+	return;
+error:
+	ibv_ack_cq_events(pconn->cq, 1);
+
+	DEBUG(DEBUG_ERR, (ibw_lasterr));
+	
+	if (conn->state!=IBWC_ERROR) {
+		conn->state = IBWC_ERROR;
+		pctx->connstate_func(NULL, conn);
+	}
+}
+
+static int ibw_process_queue(struct ibw_conn *conn)
+{
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct ibw_ctx_priv *pctx;
+	struct ibw_wr	*p;
+	int	rc;
+	uint32_t	msg_size;
+
+	if (pconn->queue==NULL)
+		return 0; /* NOP */
+
+	p = pconn->queue;
+
+	/* we must have at least 1 fragment to send */
+	assert(p->queued_ref_cnt>0);
+	p->queued_ref_cnt--;
+
+	pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	msg_size = (p->queued_ref_cnt) ? pctx->opts.recv_bufsize : p->queued_rlen;
+
+	assert(p->queued_msg!=NULL);
+	assert(msg_size!=0);
+
+	DEBUG(DEBUG_DEBUG, ("ibw_process_queue refcnt=%d msgsize=%u\n",
+		p->queued_ref_cnt, msg_size));
+
+	rc = ibw_send_packet(conn, p->queued_msg, p, msg_size);
+
+	/* was this the last fragment? */
+	if (p->queued_ref_cnt) {
+		p->queued_msg += pctx->opts.recv_bufsize;
+	} else {
+		DLIST_REMOVE2(pconn->queue, p, qprev, qnext);
+		p->queued_msg = NULL;
+	}
+
+	return rc;
+}
+
+static int ibw_wc_send(struct ibw_conn *conn, struct ibv_wc *wc)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct ibw_wr	*p;
+	int	send_index;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_wc_send(cmid: %p, wr_id: %u, bl: %u)\n",
+		pconn->cm_id, (uint32_t)wc->wr_id, (uint32_t)wc->byte_len));
+
+	assert(pconn->cm_id->qp->qp_num==wc->qp_num);
+	assert(wc->wr_id >= pctx->opts.max_recv_wr);
+	send_index = wc->wr_id - pctx->opts.max_recv_wr;
+	pconn->wr_sent--;
+
+	if (send_index < pctx->opts.max_send_wr) {
+		DEBUG(DEBUG_DEBUG, ("ibw_wc_send#1 %u\n", (int)wc->wr_id));
+		p = pconn->wr_index[send_index];
+		if (p->buf_large!=NULL) {
+			if (p->ref_cnt) {
+				/* awaiting more of it... */
+				p->ref_cnt--;
+			} else {
+				ibw_free_mr(&p->buf_large, &p->mr_large);
+				DLIST_REMOVE(pconn->wr_list_used, p);
+				DLIST_ADD(pconn->wr_list_avail, p);
+			}
+		} else { /* nasty - but necessary */
+			DLIST_REMOVE(pconn->wr_list_used, p);
+			DLIST_ADD(pconn->wr_list_avail, p);
+		}
+	} else { /* "extra" request - not optimized */
+		DEBUG(DEBUG_DEBUG, ("ibw_wc_send#2 %u\n", (int)wc->wr_id));
+		for(p=pconn->extra_sent; p!=NULL; p=p->next)
+			if ((p->wr_id + pctx->opts.max_recv_wr)==(int)wc->wr_id)
+				break;
+		if (p==NULL) {
+			sprintf(ibw_lasterr, "failed to find wr_id %d\n", (int)wc->wr_id);
+				return -1;
+		}
+		if (p->ref_cnt) {
+			p->ref_cnt--;
+		} else {
+			ibw_free_mr(&p->buf_large, &p->mr_large);
+			DLIST_REMOVE(pconn->extra_sent, p);
+			DLIST_ADD(pconn->extra_avail, p);
+		}
+	}
+
+	return ibw_process_queue(conn);
+}
+
+static int ibw_append_to_part(struct ibw_conn_priv *pconn,
+	struct ibw_part *part, char **pp, uint32_t add_len, int info)
+{
+	DEBUG(DEBUG_DEBUG, ("ibw_append_to_part: cmid=%p, (bs=%u, len=%u, tr=%u), al=%u, i=%u\n",
+		pconn->cm_id, part->bufsize, part->len, part->to_read, add_len, info));
+
+	/* allocate more if necessary - it's an "evergrowing" buffer... */
+	if (part->len + add_len > part->bufsize) {
+		if (part->buf==NULL) {
+			assert(part->len==0);
+			part->buf = talloc_size(pconn, add_len);
+			if (part->buf==NULL) {
+				sprintf(ibw_lasterr, "recv talloc_size error (%u) #%d\n",
+					add_len, info);
+				return -1;
+			}
+			part->bufsize = add_len;
+		} else {
+			part->buf = talloc_realloc_size(pconn,
+				part->buf, part->len + add_len);
+			if (part->buf==NULL) {
+				sprintf(ibw_lasterr, "recv realloc error (%u + %u) #%d\n",
+					part->len, add_len, info);
+				return -1;
+			}
+		}
+		part->bufsize = part->len + add_len;
+	}
+
+	/* consume pp */
+	memcpy(part->buf + part->len, *pp, add_len);
+	*pp += add_len;
+	part->len += add_len;
+	part->to_read -= add_len;
+
+	return 0;
+}
+
+static int ibw_wc_mem_threshold(struct ibw_conn_priv *pconn,
+	struct ibw_part *part, uint32_t threshold)
+{
+	DEBUG(DEBUG_DEBUG, ("ibw_wc_mem_threshold: cmid=%p, (bs=%u, len=%u, tr=%u), thr=%u\n",
+		pconn->cm_id, part->bufsize, part->len, part->to_read, threshold));
+
+	if (part->bufsize > threshold) {
+		DEBUG(DEBUG_DEBUG, ("ibw_wc_mem_threshold: cmid=%p, %u > %u\n",
+			pconn->cm_id, part->bufsize, threshold));
+		talloc_free(part->buf);
+		part->buf = talloc_size(pconn, threshold);
+		if (part->buf==NULL) {
+			sprintf(ibw_lasterr, "talloc_size failed\n");
+			return -1;
+		}
+		part->bufsize = threshold;
+	}
+	return 0;
+}
+
+static int ibw_wc_recv(struct ibw_conn *conn, struct ibv_wc *wc)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct ibw_part	*part = &pconn->part;
+	char	*p;
+	uint32_t	remain = wc->byte_len;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_wc_recv: cmid=%p, wr_id: %u, bl: %u\n",
+		pconn->cm_id, (uint32_t)wc->wr_id, remain));
+
+	assert(pconn->cm_id->qp->qp_num==wc->qp_num);
+	assert((int)wc->wr_id < pctx->opts.max_recv_wr);
+	assert(wc->byte_len <= pctx->opts.recv_bufsize);
+
+	p = pconn->buf_recv + ((int)wc->wr_id * pctx->opts.recv_bufsize);
+
+	while(remain) {
+		/* here always true: (part->len!=0 && part->to_read!=0) ||
+			(part->len==0 && part->to_read==0) */
+		if (part->len) { /* is there a partial msg to be continued? */
+			int read_len = (part->to_read<=remain) ? part->to_read : remain;
+			if (ibw_append_to_part(pconn, part, &p, read_len, 421))
+				goto error;
+			remain -= read_len;
+
+			if (part->len<=sizeof(uint32_t) && part->to_read==0) {
+				assert(part->len==sizeof(uint32_t));
+				/* set it again now... */
+				part->to_read = *((uint32_t *)(part->buf)); /* TODO: ntohl */
+				if (part->to_read<sizeof(uint32_t)) {
+					sprintf(ibw_lasterr, "got msglen=%u #2\n", part->to_read);
+					goto error;
+				}
+				part->to_read -= sizeof(uint32_t); /* it's already read */
+			}
+
+			if (part->to_read==0) {
+				if (pctx->receive_func(conn, part->buf, part->len) != 0) {
+					goto error;
+				}
+				part->len = 0; /* tells not having partial data (any more) */
+				if (ibw_wc_mem_threshold(pconn, part, pctx->opts.recv_threshold))
+					goto error;
+			}
+		} else {
+			if (remain>=sizeof(uint32_t)) {
+				uint32_t msglen = *(uint32_t *)p; /* TODO: ntohl */
+				if (msglen<sizeof(uint32_t)) {
+					sprintf(ibw_lasterr, "got msglen=%u\n", msglen);
+					goto error;
+				}
+
+				/* mostly awaited case: */
+				if (msglen<=remain) {
+					if (pctx->receive_func(conn, p, msglen) != 0) {
+						goto error;
+					}
+					p += msglen;
+					remain -= msglen;
+				} else {
+					part->to_read = msglen;
+					/* part->len is already 0 */
+					if (ibw_append_to_part(pconn, part, &p, remain, 422))
+						goto error;
+					remain = 0; /* to be continued ... */
+					/* part->to_read > 0 here */
+				}
+			} else { /* edge case: */
+				part->to_read = sizeof(uint32_t);
+				/* part->len is already 0 */
+				if (ibw_append_to_part(pconn, part, &p, remain, 423))
+					goto error;
+				remain = 0;
+				/* part->to_read > 0 here */
+			}
+		}
+	} /* <remain> is always decreased at least by 1 */
+
+	if (ibw_refill_cq_recv(conn))
+		goto error;
+
+	return 0;
+
+error:
+	DEBUG(DEBUG_ERR, ("ibw_wc_recv error: %s", ibw_lasterr));
+	return -1;
+}
+
+static int ibw_process_init_attrs(struct ibw_initattr *attr, int nattr, struct ibw_opts *opts)
+{
+	int	i;
+	const char *name, *value;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_process_init_attrs: nattr: %d\n", nattr));
+
+	opts->max_send_wr = IBW_MAX_SEND_WR;
+	opts->max_recv_wr = IBW_MAX_RECV_WR;
+	opts->recv_bufsize = IBW_RECV_BUFSIZE;
+	opts->recv_threshold = IBW_RECV_THRESHOLD;
+
+	for(i=0; i<nattr; i++) {
+		name = attr[i].name;
+		value = attr[i].value;
+
+		assert(name!=NULL && value!=NULL);
+		if (strcmp(name, "max_send_wr")==0)
+			opts->max_send_wr = atoi(value);
+		else if (strcmp(name, "max_recv_wr")==0)
+			opts->max_recv_wr = atoi(value);
+		else if (strcmp(name, "recv_bufsize")==0)
+			opts->recv_bufsize = atoi(value);
+		else if (strcmp(name, "recv_threshold")==0)
+			opts->recv_threshold = atoi(value);
+		else {
+			sprintf(ibw_lasterr, "ibw_init: unknown name %s\n", name);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+struct ibw_ctx *ibw_init(struct ibw_initattr *attr, int nattr,
+	void *ctx_userdata,
+	ibw_connstate_fn_t ibw_connstate,
+	ibw_receive_fn_t ibw_receive,
+	struct event_context *ectx)
+{
+	struct ibw_ctx *ctx = talloc_zero(NULL, struct ibw_ctx);
+	struct ibw_ctx_priv *pctx;
+	int	rc;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_init(ctx_userdata: %p, ectx: %p)\n", ctx_userdata, ectx));
+
+	/* initialize basic data structures */
+	memset(ibw_lasterr, 0, IBW_LASTERR_BUFSIZE);
+
+	assert(ctx!=NULL);
+	ibw_lasterr[0] = '\0';
+	talloc_set_destructor(ctx, ibw_ctx_destruct);
+	ctx->ctx_userdata = ctx_userdata;
+
+	pctx = talloc_zero(ctx, struct ibw_ctx_priv);
+	talloc_set_destructor(pctx, ibw_ctx_priv_destruct);
+	ctx->internal = (void *)pctx;
+	assert(pctx!=NULL);
+
+	pctx->connstate_func = ibw_connstate;
+	pctx->receive_func = ibw_receive;
+
+	pctx->ectx = ectx;
+
+	/* process attributes */
+	if (ibw_process_init_attrs(attr, nattr, &pctx->opts))
+		goto cleanup;
+
+	/* init cm */
+	pctx->cm_channel = rdma_create_event_channel();
+	if (!pctx->cm_channel) {
+		sprintf(ibw_lasterr, "rdma_create_event_channel error %d\n", errno);
+		goto cleanup;
+	}
+
+	pctx->cm_channel_event = event_add_fd(pctx->ectx, pctx,
+		pctx->cm_channel->fd, EVENT_FD_READ, ibw_event_handler_cm, ctx);
+
+#if RDMA_USER_CM_MAX_ABI_VERSION >= 2
+	rc = rdma_create_id(pctx->cm_channel, &pctx->cm_id, ctx, RDMA_PS_TCP);
+#else
+	rc = rdma_create_id(pctx->cm_channel, &pctx->cm_id, ctx);
+#endif
+	if (rc) {
+		rc = errno;
+		sprintf(ibw_lasterr, "rdma_create_id error %d\n", rc);
+		goto cleanup;
+	}
+	DEBUG(DEBUG_DEBUG, ("created cm_id %p\n", pctx->cm_id));
+
+	pctx->pagesize = sysconf(_SC_PAGESIZE);
+
+	return ctx;
+	/* don't put code here */
+cleanup:
+	DEBUG(DEBUG_ERR, (ibw_lasterr));
+
+	if (ctx)
+		talloc_free(ctx);
+
+	return NULL;
+}
+
+int ibw_stop(struct ibw_ctx *ctx)
+{
+	struct ibw_ctx_priv *pctx = (struct ibw_ctx_priv *)ctx->internal;
+	struct ibw_conn *p;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_stop\n"));
+
+	for(p=ctx->conn_list; p!=NULL; p=p->next) {
+		if (ctx->state==IBWC_ERROR || ctx->state==IBWC_CONNECTED) {
+			if (ibw_disconnect(p))
+				return -1;
+		}
+	}
+
+	ctx->state = IBWS_STOPPED;
+	pctx->connstate_func(ctx, NULL);
+
+	return 0;
+}
+
+int ibw_bind(struct ibw_ctx *ctx, struct sockaddr_in *my_addr)
+{
+	struct ibw_ctx_priv *pctx = (struct ibw_ctx_priv *)ctx->internal;
+	int	rc;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_bind: addr=%s, port=%u\n",
+		inet_ntoa(my_addr->sin_addr), ntohs(my_addr->sin_port)));
+	rc = rdma_bind_addr(pctx->cm_id, (struct sockaddr *) my_addr);
+	if (rc) {
+		sprintf(ibw_lasterr, "rdma_bind_addr error %d\n", rc);
+		DEBUG(DEBUG_ERR, (ibw_lasterr));
+		return rc;
+	}
+	DEBUG(DEBUG_DEBUG, ("rdma_bind_addr successful\n"));
+
+	return 0;
+}
+
+int ibw_listen(struct ibw_ctx *ctx, int backlog)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(ctx->internal, struct ibw_ctx_priv);
+	int	rc;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_listen\n"));
+	rc = rdma_listen(pctx->cm_id, backlog);
+	if (rc) {
+		sprintf(ibw_lasterr, "rdma_listen failed: %d\n", rc);
+		DEBUG(DEBUG_ERR, (ibw_lasterr));
+		return rc;
+	}
+
+	return 0;
+}
+
+int ibw_accept(struct ibw_ctx *ctx, struct ibw_conn *conn, void *conn_userdata)
+{
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct rdma_conn_param	conn_param;
+	int	rc;
+
+	DEBUG(DEBUG_DEBUG, ("ibw_accept: cmid=%p\n", pconn->cm_id));
+	conn->conn_userdata = conn_userdata;
+
+	memset(&conn_param, 0, sizeof(struct rdma_conn_param));
+	conn_param.responder_resources = 1;
+	conn_param.initiator_depth = 1;
+	rc = rdma_accept(pconn->cm_id, &conn_param);
+	if (rc) {
+		sprintf(ibw_lasterr, "rdma_accept failed %d\n", rc);
+		DEBUG(DEBUG_ERR, (ibw_lasterr));
+		return -1;;
+	}
+
+	pconn->is_accepted = 1;
+
+	/* continued at RDMA_CM_EVENT_ESTABLISHED */
+
+	return 0;
+}
+
+int ibw_connect(struct ibw_conn *conn, struct sockaddr_in *serv_addr, void *conn_userdata)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = NULL;
+	int	rc;
+
+	assert(conn!=NULL);
+
+	conn->conn_userdata = conn_userdata;
+	pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	DEBUG(DEBUG_DEBUG, ("ibw_connect: addr=%s, port=%u\n", inet_ntoa(serv_addr->sin_addr),
+		ntohs(serv_addr->sin_port)));
+
+	/* clean previous - probably half - initialization */
+	if (ibw_conn_priv_destruct(pconn)) {
+		DEBUG(DEBUG_ERR, ("ibw_connect/ibw_pconn_destruct failed for cm_id=%p\n", pconn->cm_id));
+		return -1;
+	}
+
+	/* init cm */
+#if RDMA_USER_CM_MAX_ABI_VERSION >= 2
+	rc = rdma_create_id(pctx->cm_channel, &pconn->cm_id, conn, RDMA_PS_TCP);
+#else
+	rc = rdma_create_id(pctx->cm_channel, &pconn->cm_id, conn);
+#endif
+	if (rc) {
+		rc = errno;
+		sprintf(ibw_lasterr, "ibw_connect/rdma_create_id error %d\n", rc);
+		talloc_free(conn);
+		return -1;
+	}
+	DEBUG(DEBUG_DEBUG, ("ibw_connect: rdma_create_id succeeded, cm_id=%p\n", pconn->cm_id));
+
+	rc = rdma_resolve_addr(pconn->cm_id, NULL, (struct sockaddr *) serv_addr, 2000);
+	if (rc) {
+		sprintf(ibw_lasterr, "rdma_resolve_addr error %d\n", rc);
+		DEBUG(DEBUG_ERR, (ibw_lasterr));
+		talloc_free(conn);
+		return -1;
+	}
+
+	/* continued at RDMA_CM_EVENT_ADDR_RESOLVED */
+
+	return 0;
+}
+
+int ibw_disconnect(struct ibw_conn *conn)
+{
+	int	rc;
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+
+	DEBUG(DEBUG_DEBUG, ("ibw_disconnect: cmid=%p\n", pconn->cm_id));
+
+	assert(pconn!=NULL);
+
+	switch(conn->state) {
+	case IBWC_ERROR:
+		ibw_conn_priv_destruct(pconn); /* do this here right now */
+		break;
+	case IBWC_CONNECTED:
+		rc = rdma_disconnect(pconn->cm_id);
+		if (rc) {
+			sprintf(ibw_lasterr, "ibw_disconnect failed with %d\n", rc);
+			DEBUG(DEBUG_ERR, (ibw_lasterr));
+			return rc;
+		}
+		break;
+	default:
+		DEBUG(DEBUG_DEBUG, ("invalid state for disconnect: %d\n", conn->state));
+		break;
+	}
+
+	return 0;
+}
+
+int ibw_alloc_send_buf(struct ibw_conn *conn, void **buf, void **key, uint32_t len)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct ibw_wr *p = pconn->wr_list_avail;
+
+	if (p!=NULL) {
+		DEBUG(DEBUG_DEBUG, ("ibw_alloc_send_buf#1: cmid=%p, len=%d\n", pconn->cm_id, len));
+
+		DLIST_REMOVE(pconn->wr_list_avail, p);
+		DLIST_ADD(pconn->wr_list_used, p);
+
+		if (len <= pctx->opts.recv_bufsize) {
+			*buf = (void *)p->buf;
+		} else {
+			p->buf_large = ibw_alloc_mr(pctx, pconn, len, &p->mr_large);
+			if (p->buf_large==NULL) {
+				sprintf(ibw_lasterr, "ibw_alloc_mr#1 failed\n");
+				goto error;
+			}
+			*buf = (void *)p->buf_large;
+		}
+		/* p->wr_id is already filled in ibw_init_memory */
+	} else {
+		DEBUG(DEBUG_DEBUG, ("ibw_alloc_send_buf#2: cmid=%p, len=%d\n", pconn->cm_id, len));
+		/* not optimized */
+		p = pconn->extra_avail;
+		if (!p) {
+			p = pconn->extra_avail = talloc_zero(pconn, struct ibw_wr);
+			talloc_set_destructor(p, ibw_wr_destruct);
+			if (p==NULL) {
+				sprintf(ibw_lasterr, "talloc_zero failed (emax: %u)\n", pconn->extra_max);
+				goto error;
+			}
+			p->wr_id = pctx->opts.max_send_wr + pconn->extra_max;
+			pconn->extra_max++;
+			switch(pconn->extra_max) {
+				case 1: DEBUG(DEBUG_INFO, ("warning: queue performed\n")); break;
+				case 10: DEBUG(DEBUG_INFO, ("warning: queue reached 10\n")); break;
+				case 100: DEBUG(DEBUG_INFO, ("warning: queue reached 100\n")); break;
+				case 1000: DEBUG(DEBUG_INFO, ("warning: queue reached 1000\n")); break;
+				default: break;
+			}
+		}
+
+		p->buf_large = ibw_alloc_mr(pctx, pconn, len, &p->mr_large);
+		if (p->buf_large==NULL) {
+			sprintf(ibw_lasterr, "ibw_alloc_mr#2 failed\n");
+			goto error;
+		}
+		*buf = (void *)p->buf_large;
+
+		DLIST_REMOVE(pconn->extra_avail, p);
+		/* we don't have prepared index for this, so that
+		 * we will have to find this by wr_id later on */
+		DLIST_ADD(pconn->extra_sent, p);
+	}
+
+	*key = (void *)p;
+
+	return 0;
+error:
+	DEBUG(DEBUG_ERR, ("ibw_alloc_send_buf error: %s", ibw_lasterr));
+	return -1;
+}
+
+
+static int ibw_send_packet(struct ibw_conn *conn, void *buf, struct ibw_wr *p, uint32_t len)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	int	rc;
+
+	/* can we send it right now? */
+	if (pconn->wr_sent<pctx->opts.max_send_wr) {
+		struct ibv_send_wr *bad_wr;
+		struct ibv_sge list = {
+			.addr 	= (uintptr_t)buf,
+			.length = len,
+			.lkey 	= pconn->mr_send->lkey
+		};
+		struct ibv_send_wr wr = {
+			.wr_id 	    = p->wr_id + pctx->opts.max_recv_wr,
+			.sg_list    = &list,
+			.num_sge    = 1,
+			.opcode     = IBV_WR_SEND,
+			.send_flags = IBV_SEND_SIGNALED,
+		};
+
+		if (p->buf_large==NULL) {
+			DEBUG(DEBUG_DEBUG, ("ibw_send#normal(cmid: %p, wrid: %u, n: %d)\n",
+				pconn->cm_id, (uint32_t)wr.wr_id, len));
+		} else {
+			DEBUG(DEBUG_DEBUG, ("ibw_send#large(cmid: %p, wrid: %u, n: %d)\n",
+				pconn->cm_id, (uint32_t)wr.wr_id, len));
+			list.lkey = p->mr_large->lkey;
+		}
+
+		rc = ibv_post_send(pconn->cm_id->qp, &wr, &bad_wr);
+		if (rc) {
+			sprintf(ibw_lasterr, "ibv_post_send error %d (%d)\n",
+				rc, pconn->wr_sent);
+			goto error;
+		}
+
+		pconn->wr_sent++;
+
+		return rc;
+	} /* else put the request into our own queue: */
+
+	DEBUG(DEBUG_DEBUG, ("ibw_send#queued(cmid: %p, len: %u)\n", pconn->cm_id, len));
+
+	/* TODO: clarify how to continue when state==IBWC_STOPPED */
+
+	/* to be sent by ibw_wc_send */
+	/* regardless "normal" or [a part of] "large" packet */
+	if (!p->queued_ref_cnt) {
+		DLIST_ADD_END2(pconn->queue, p, struct ibw_wr *,
+			qprev, qnext); /* TODO: optimize */
+		p->queued_msg = buf;
+	}
+	p->queued_ref_cnt++;
+	p->queued_rlen = len; /* last wins; see ibw_wc_send */
+
+	return 0;
+error:
+	DEBUG(DEBUG_ERR, (ibw_lasterr));
+	return -1;
+}
+
+int ibw_send(struct ibw_conn *conn, void *buf, void *key, uint32_t len)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_wr *p = talloc_get_type(key, struct ibw_wr);
+	int	rc;
+
+	assert(len>=sizeof(uint32_t));
+	assert((*((uint32_t *)buf)==len)); /* TODO: htonl */
+
+	if (len > pctx->opts.recv_bufsize) {
+		struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+		int	rlen = len;
+		char	*packet = (char *)buf;
+		uint32_t	recv_bufsize = pctx->opts.recv_bufsize;
+
+		DEBUG(DEBUG_DEBUG, ("ibw_send#frag(cmid: %p, buf: %p, len: %u)\n",
+			pconn->cm_id, buf, len));
+
+		/* single threaded => no race here: */
+		assert(p->ref_cnt==0);
+		while(rlen > recv_bufsize) {
+			rc = ibw_send_packet(conn, packet, p, recv_bufsize);
+			if (rc)
+				return rc;
+			packet += recv_bufsize;
+			rlen -= recv_bufsize;
+			p->ref_cnt++; /* not good to have it in ibw_send_packet */
+		}
+		if (rlen) {
+			rc = ibw_send_packet(conn, packet, p, rlen);
+			p->ref_cnt++; /* not good to have it in ibw_send_packet */
+		}
+		p->ref_cnt--; /* for the same handling */
+	} else {
+		assert(p->ref_cnt==0);
+		assert(p->queued_ref_cnt==0);
+
+		rc = ibw_send_packet(conn, buf, p, len);
+	}
+	return rc;
+}
+
+int ibw_cancel_send_buf(struct ibw_conn *conn, void *buf, void *key)
+{
+	struct ibw_ctx_priv *pctx = talloc_get_type(conn->ctx->internal, struct ibw_ctx_priv);
+	struct ibw_conn_priv *pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
+	struct ibw_wr *p = talloc_get_type(key, struct ibw_wr);
+
+	assert(p!=NULL);
+	assert(buf!=NULL);
+	assert(conn!=NULL);
+
+	if (p->buf_large!=NULL)
+		ibw_free_mr(&p->buf_large, &p->mr_large);
+
+	/* parallel case */
+	if (p->wr_id < pctx->opts.max_send_wr) {
+		DEBUG(DEBUG_DEBUG, ("ibw_cancel_send_buf#1 %u", (int)p->wr_id));
+		DLIST_REMOVE(pconn->wr_list_used, p);
+		DLIST_ADD(pconn->wr_list_avail, p);
+	} else { /* "extra" packet */
+		DEBUG(DEBUG_DEBUG, ("ibw_cancel_send_buf#2 %u", (int)p->wr_id));
+		DLIST_REMOVE(pconn->extra_sent, p);
+		DLIST_ADD(pconn->extra_avail, p);
+	}
+
+	return 0;
+}
+
+const char *ibw_getLastError(void)
+{
+	return ibw_lasterr;
+}

Added: branches/ctdb/squeeze-backports/ib/ibwrapper.h
===================================================================
--- branches/ctdb/squeeze-backports/ib/ibwrapper.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/ibwrapper.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,218 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Wrap Infiniband calls.
+ *
+ * Copyright (C) Sven Oehme <oehmes at de.ibm.com> 2006
+ *
+ * Major code contributions by Peter Somogyi <psomogyi at gamax.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Server communication state */
+enum ibw_state_ctx {
+	IBWS_INIT = 0, /* ctx start - after ibw_init */
+	IBWS_READY, /* after ibw_bind & ibw_listen */
+	IBWS_CONNECT_REQUEST, /* after [IBWS_READY + incoming request] */
+		/* => [(ibw_accept)IBWS_READY | (ibw_disconnect)STOPPED | ERROR] */
+	IBWS_STOPPED, /* normal stop <= ibw_disconnect+(IBWS_READY | IBWS_CONNECT_REQUEST) */
+	IBWS_ERROR /* abnormal state; ibw_stop must be called after this */
+};
+
+/* Connection state */
+struct ibw_ctx {
+	void *ctx_userdata; /* see ibw_init */
+
+	enum ibw_state_ctx state;
+	void *internal;
+
+	struct ibw_conn *conn_list; /* 1st elem of double linked list */
+};
+
+enum ibw_state_conn {
+	IBWC_INIT = 0, /* conn start - internal state */
+	IBWC_CONNECTED, /* after ibw_accept or ibw_connect */
+	IBWC_DISCONNECTED, /* after ibw_disconnect */
+	IBWC_ERROR
+};
+
+struct ibw_conn {
+	struct ibw_ctx *ctx;
+	enum ibw_state_conn state;
+
+	void *conn_userdata; /* see ibw_connect and ibw_accept */
+	void *internal;
+
+	struct ibw_conn *prev, *next;
+};
+
+/*
+ * (name, value) pair for array param of ibw_init
+ */
+struct ibw_initattr {
+	const char *name;
+	const char *value;
+};
+
+/*
+ * Callback function definition which should inform you about
+ * connection state change
+ * This callback is invoked whenever server or client connection changes.
+ * Both <conn> and <ctx> can be NULL if their state didn't change.
+ * Return nonzero on error.
+ */
+typedef int (*ibw_connstate_fn_t)(struct ibw_ctx *ctx, struct ibw_conn *conn);
+
+/*
+ * Callback function definition which should process incoming packets
+ * This callback is invoked whenever any message arrives.
+ * Return nonzero on error.
+ *
+ * Important: you mustn't store buf pointer for later use.
+ * Process its contents before returning.
+ */
+typedef int (*ibw_receive_fn_t)(struct ibw_conn *conn, void *buf, int n);
+
+/*
+ * settings: array of (name, value) pairs
+ * where name is one of:
+ *      max_send_wr [default is 256]
+ *      max_recv_wr [default is 1024]
+ * <...>
+ *
+ * Must be called _ONCE_ for each node.
+ *
+ * max_msg_size is the maximum size of a message
+ * (max_send_wr + max_recv_wr) * max_msg_size bytes allocated per connection
+ *
+ * returns non-NULL on success
+ *
+ * talloc_free must be called for the result in IBWS_STOPPED;
+ *    it will close resources by destructor
+ *    connections(ibw_conn *) must have been closed prior talloc_free
+ */
+struct ibw_ctx *ibw_init(struct ibw_initattr *attr, int nattr,
+	void *ctx_userdata,
+	ibw_connstate_fn_t ibw_connstate,
+	ibw_receive_fn_t ibw_receive,
+	struct event_context *ectx);
+
+/*
+ * Must be called in states of (IBWS_ERROR, IBWS_READY, IBWS_CONNECT_REQUEST)
+ *
+ * It will send out disconnect requests and free up ibw_conn structures.
+ * The ctx->state will transit to IBWS_STOPPED after every conn are disconnected.
+ * During that time, you mustn't send/recv/disconnect any more.
+ * Only after ctx->state=IBWS_STOPPED you can talloc_free the ctx.
+ */
+int ibw_stop(struct ibw_ctx *ctx);
+
+/*************** connection initiation - like stream sockets *****/
+
+/*
+ * works like socket bind
+ * needs a normal internet address here
+ *
+ * return 0 on success
+ */
+int ibw_bind(struct ibw_ctx *ctx, struct sockaddr_in *my_addr);
+
+/*
+ * works like socket listen
+ * non-blocking
+ * enables accepting incoming connections (after IBWS_READY)
+ * (it doesn't touch ctx->state by itself)
+ *
+ * returns 0 on success
+ */
+int ibw_listen(struct ibw_ctx *ctx, int backlog);
+
+/*
+ * works like socket accept
+ * initializes a connection to a client
+ * must be called when state=IBWS_CONNECT_REQUEST
+ *
+ * returns 0 on success
+ *
+ * You have +1 waiting here: you will get ibw_conn (having the
+ * same <conn_userdata> member) structure in ibw_connstate_fn_t.
+ *
+ * Important: you won't get remote IP address (only internal conn info)
+ */
+int ibw_accept(struct ibw_ctx *ctx, struct ibw_conn *conn, void *conn_userdata);
+
+/*
+ * Create a new connection structure
+ * available for queueing ibw_send
+ *
+ * <parent> is needed to be notified by talloc destruct action.
+ */
+struct ibw_conn *ibw_conn_new(struct ibw_ctx *ctx, TALLOC_CTX *mem_ctx);
+
+/*
+ * Needs a normal internet address here
+ * can be called within IBWS_READY|IBWS_CONNECT_REQUEST
+ *
+ * returns non-NULL on success
+ *
+ * You have +1 waiting here: you will get ibw_conn (having the
+ * same <conn_userdata> member) structure in ibw_connstate_fn_t.
+ */
+int ibw_connect(struct ibw_conn *conn, struct sockaddr_in *serv_addr, void *conn_userdata);
+
+/*
+ * Sends out a disconnect request.
+ * You should process fds after calling this function
+ * and then process it with ibw_process_event normally
+ * until you get conn->state = IBWC_DISCONNECTED
+ *
+ * You mustn't talloc_free <conn> yet right after this,
+ * first wait for IBWC_DISCONNECTED.
+ */
+int ibw_disconnect(struct ibw_conn *conn);
+
+/************ Infiniband specific event loop wrapping ******************/
+
+/*
+ * You have to use this buf to fill in before send.
+ * It's just to avoid memcpy.in ibw_send.
+ * Use the same (buf, key) pair with ibw_send.
+ * Don't use more space than maxsize (see ibw_init).
+ *
+ * Returns 0 on success.
+ */
+int ibw_alloc_send_buf(struct ibw_conn *conn, void **buf, void **key, uint32_t len);
+
+/*
+ * Send the message in one
+ * Can be invoked any times (should fit into buffers) and at any time
+ * (in conn->state=IBWC_CONNECTED)
+ * n must be less or equal than max_msg_size (see ibw_init)
+ *
+ * You mustn't use (buf, key) any more for sending.
+ */
+int ibw_send(struct ibw_conn *conn, void *buf, void *key, uint32_t len);
+
+/*
+ * Call this after ibw_alloc_send_buf
+ * when you won't call ibw_send for (buf, key)
+ * You mustn't use (buf, key) any more.
+ */
+int ibw_cancel_send_buf(struct ibw_conn *conn, void *buf, void *key);
+
+/*
+ * Retrieves the last error
+ * result: always non-zero, mustn't be freed (static)
+ */
+const char *ibw_getLastError(void);

Added: branches/ctdb/squeeze-backports/ib/ibwrapper_internal.h
===================================================================
--- branches/ctdb/squeeze-backports/ib/ibwrapper_internal.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/ibwrapper_internal.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,126 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Wrap Infiniband calls.
+ *
+ * Copyright (C) Sven Oehme <oehmes at de.ibm.com> 2006
+ *
+ * Major code contributions by Peter Somogyi <psomogyi at gamax.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+struct ibw_opts {
+	uint32_t	max_send_wr;
+	uint32_t	max_recv_wr;
+	uint32_t	recv_bufsize;
+	uint32_t	recv_threshold;
+};
+
+struct ibw_wr {
+	char	*buf; /* initialized in ibw_init_memory once per connection */
+	int	wr_id; /* position in wr_index list; also used as wr id */
+
+	char	*buf_large; /* allocated specially for "large" message */
+	struct ibv_mr *mr_large;
+	int	ref_cnt; /* reference count for ibw_wc_send to know when to release */
+
+	char	*queued_msg; /* set at ibw_send - can be different than above */
+	int	queued_ref_cnt; /* instead of adding the same to the queue again */
+	uint32_t	queued_rlen; /* last wins when queued_ref_cnt>0; or simple msg size */
+
+	struct ibw_wr *next, *prev; /* in wr_list_avail or wr_list_used */
+				/* or extra_sent or extra_avail */
+	struct ibw_wr *qnext, *qprev; /* in queue */
+};
+
+struct ibw_ctx_priv {
+	struct event_context *ectx;
+
+	struct ibw_opts opts;
+
+	struct rdma_cm_id	*cm_id; /* server cm id */
+
+	struct rdma_event_channel *cm_channel;
+	struct fd_event *cm_channel_event;
+
+	ibw_connstate_fn_t connstate_func; /* see ibw_init */
+	ibw_receive_fn_t receive_func; /* see ibw_init */
+
+	long	pagesize; /* sysconf result for memalign */
+};
+
+struct ibw_part {
+	char *buf; /* talloced memory buffer */
+	uint32_t bufsize; /* allocated size of buf - always grows */
+	uint32_t len; /* message part length */
+	uint32_t to_read; /* 4 or *((uint32_t)buf) if len>=sizeof(uint32_t) */
+};
+
+struct ibw_conn_priv {
+	struct ibv_comp_channel *verbs_channel;
+	struct fd_event *verbs_channel_event;
+
+	struct rdma_cm_id *cm_id; /* client's cm id */
+	struct ibv_pd	*pd;
+	int	is_accepted;
+
+	struct ibv_cq	*cq; /* qp is in cm_id */
+
+	char *buf_send; /* max_send_wr * avg_send_size */
+	struct ibv_mr *mr_send;
+	struct ibw_wr *wr_list_avail;
+	struct ibw_wr *wr_list_used;
+	struct ibw_wr **wr_index; /* array[0..(qsize-1)] of (ibw_wr *) */
+	int	wr_sent; /* # of send wrs in the CQ */
+
+	struct ibw_wr *extra_sent;
+	struct ibw_wr *extra_avail;
+	int	extra_max; /* max wr_id in the queue */
+
+	struct ibw_wr *queue;
+
+	/* buf_recv is a ring buffer */
+	char *buf_recv; /* max_recv_wr * avg_recv_size */
+	struct ibv_mr *mr_recv;
+	int recv_index; /* index of the next recv buffer when refilling */
+	struct ibw_part part;
+};
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define DLIST_REMOVE2(list, p, prev, next) \
+do { \
+	if ((p) == (list)) { \
+		(list) = (p)->next; \
+		if (list) (list)->prev = NULL; \
+	} else { \
+		if ((p)->prev) (p)->prev->next = (p)->next; \
+		if ((p)->next) (p)->next->prev = (p)->prev; \
+	} \
+	if ((p) != (list)) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+/* hook into the end of the list - needs a tmp pointer */
+#define DLIST_ADD_END2(list, p, type, prev, next) \
+do { \
+		if (!(list)) { \
+			(list) = (p); \
+			(p)->next = (p)->prev = NULL; \
+		} else { \
+			type tmp; \
+			for (tmp = (list); tmp->next; tmp = tmp->next) ; \
+			tmp->next = (p); \
+			(p)->next = NULL; \
+			(p)->prev = tmp; \
+		} \
+} while (0)

Added: branches/ctdb/squeeze-backports/ib/ibwrapper_test.c
===================================================================
--- branches/ctdb/squeeze-backports/ib/ibwrapper_test.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/ib/ibwrapper_test.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,661 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Test the infiniband wrapper.
+ *
+ * Copyright (C) Sven Oehme <oehmes at de.ibm.com> 2006
+ *
+ * Major code contributions by Peter Somogyi <psomogyi at gamax.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <malloc.h>
+#include <assert.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "ib/ibwrapper.h"
+
+struct ibwtest_ctx {
+	int	is_server;
+	char	*id; /* my id */
+
+	struct ibw_initattr *attrs;
+	int	nattrs;
+	char	*opts; /* option string */
+
+	struct sockaddr_in *addrs; /* dynamic array of dest addrs */
+	int	naddrs;
+
+	unsigned int	nsec; /* delta times between messages in nanosec */
+	unsigned int	sleep_usec; /* microsecs to sleep in the main loop to emulate overloading */
+	uint32_t	maxsize; /* maximum variable message size */
+
+	int	cnt;
+	int	nsent;
+
+	int	nmsg; /* number of messages to send (client) */
+
+	int	kill_me;
+	int	stopping;
+	int	error;
+	struct ibw_ctx	*ibwctx;
+
+	struct timeval	start_time, end_time;
+};
+
+struct ibwtest_conn {
+	char	*id;
+};
+
+enum testopcode {
+	TESTOP_SEND_ID = 1,
+	TESTOP_SEND_TEXT = 2,
+	TESTOP_SEND_RND = 3
+};
+
+int ibwtest_connect_everybody(struct ibwtest_ctx *tcx)
+{
+	struct ibw_conn		*conn;
+	struct ibwtest_conn	*tconn = talloc_zero(tcx, struct ibwtest_conn);
+	int	i;
+
+	for(i=0; i<tcx->naddrs; i++) {
+		conn = ibw_conn_new(tcx->ibwctx, tconn);
+		if (ibw_connect(conn, &tcx->addrs[i], tconn)) {
+			fprintf(stderr, "ibw_connect error at %d\n", i);
+			return -1;
+		}
+	}
+	DEBUG(DEBUG_DEBUG, ("sent %d connect request...\n", tcx->naddrs));
+
+	return 0;
+}
+
+int ibwtest_send_id(struct ibw_conn *conn)
+{
+	struct ibwtest_ctx *tcx = talloc_get_type(conn->ctx->ctx_userdata, struct ibwtest_ctx);
+	char *buf;
+	void *key;
+	uint32_t	len;
+
+	DEBUG(DEBUG_DEBUG, ("ibwtest_send_id\n"));
+	len = sizeof(uint32_t)+strlen(tcx->id)+2;
+	if (ibw_alloc_send_buf(conn, (void **)&buf, &key, len)) {
+		DEBUG(DEBUG_ERR, ("send_id: ibw_alloc_send_buf failed\n"));
+		return -1;
+	}
+
+	/* first sizeof(uint32_t) size bytes are for length */
+	*((uint32_t *)buf) = len;
+	buf[sizeof(uint32_t)] = (char)TESTOP_SEND_ID;
+	strcpy(buf+sizeof(uint32_t)+1, tcx->id);
+
+	if (ibw_send(conn, buf, key, len)) {
+		DEBUG(DEBUG_ERR, ("send_id: ibw_send error\n"));
+		return -1;
+	}
+	tcx->nsent++;
+
+	return 0;
+}
+
+int ibwtest_send_test_msg(struct ibwtest_ctx *tcx, struct ibw_conn *conn, const char *msg)
+{
+	char *buf, *p;
+	void *key;
+	uint32_t len;
+
+	if (conn->state!=IBWC_CONNECTED)
+		return 0; /* not yet up */
+
+	len = strlen(msg) + 2 + sizeof(uint32_t);
+	if (ibw_alloc_send_buf(conn, (void **)&buf, &key, len)) {
+		fprintf(stderr, "send_test_msg: ibw_alloc_send_buf failed\n");
+		return -1;
+	}
+
+	*((uint32_t *)buf) = len;
+	p = buf;
+	p += sizeof(uint32_t);
+	p[0] = (char)TESTOP_SEND_TEXT;
+	p++;
+	strcpy(p, msg);
+
+	if (ibw_send(conn, buf, key, len)) {
+		DEBUG(DEBUG_ERR, ("send_test_msg: ibw_send error\n"));
+		return -1;
+	}
+	tcx->nsent++;
+
+	return 0;
+}
+
+unsigned char ibwtest_fill_random(unsigned char *buf, uint32_t size)
+{
+	uint32_t	i = size;
+	unsigned char	sum = 0;
+	unsigned char	value;
+	while(i) {
+		i--;
+		value = (unsigned char)(256.0 * (rand() / (RAND_MAX + 1.0)));
+		buf[i] = value;
+		sum += value;
+	}
+	return sum;
+}
+
+unsigned char ibwtest_get_sum(unsigned char *buf, uint32_t size)
+{
+	uint32_t	i = size;
+	unsigned char	sum = 0;
+
+	while(i) {
+		i--;
+		sum += buf[i];
+	}
+	return sum;
+}
+
+int ibwtest_do_varsize_scenario_conn_size(struct ibwtest_ctx *tcx, struct ibw_conn *conn, uint32_t size)
+{
+	unsigned char *buf;
+	void	*key;
+	uint32_t	len;
+	unsigned char	sum;
+
+	len = sizeof(uint32_t) + 1 + size + 1;
+	if (ibw_alloc_send_buf(conn, (void **)&buf, &key, len)) {
+		DEBUG(DEBUG_ERR, ("varsize/ibw_alloc_send_buf failed\n"));
+		return -1;
+	}
+	*((uint32_t *)buf) = len;
+	buf[sizeof(uint32_t)] = TESTOP_SEND_RND;
+	sum = ibwtest_fill_random(buf + sizeof(uint32_t) + 1, size);
+	buf[sizeof(uint32_t) + 1 + size] = sum;
+	if (ibw_send(conn, buf, key, len)) {
+		DEBUG(DEBUG_ERR, ("varsize/ibw_send failed\n"));
+		return -1;
+	}
+	tcx->nsent++;
+
+	return 0;
+}
+
+int ibwtest_do_varsize_scenario_conn(struct ibwtest_ctx *tcx, struct ibw_conn *conn)
+{
+	uint32_t	size;
+	int	i;
+
+	for(i=0; i<tcx->nmsg; i++)
+	{
+		//size = (uint32_t)((float)(tcx->maxsize) * (rand() / (RAND_MAX + 1.0)));
+		size = (uint32_t)((float)(tcx->maxsize) * ((float)(i+1)/(float)tcx->nmsg));
+		if (ibwtest_do_varsize_scenario_conn_size(tcx, conn, size))
+			return -1;
+	}
+	return 0;
+}
+
+/*int ibwtest_do_varsize_scenario(ibwtest_ctx *tcx)
+{
+	int	rc;
+	struct ibw_conn *conn;
+
+	for(conn=tcx->ibwctx->conn_list; conn!=NULL; conn=conn->next) {
+		if (conn->state==IBWC_CONNECTED) {
+			rc = ibwtest_do_varsize_scenario_conn(tcx, conn);
+			if (rc)
+				tcx->error = rc;
+		}
+	}
+}*/
+
+int ibwtest_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn)
+{
+	struct ibwtest_ctx	*tcx = NULL; /* userdata */
+	struct ibwtest_conn	*tconn = NULL; /* userdata */
+
+	if (ctx) {
+		tcx = talloc_get_type(ctx->ctx_userdata, struct ibwtest_ctx);
+
+		switch(ctx->state) {
+		case IBWS_INIT:
+			DEBUG(DEBUG_DEBUG, ("test IBWS_INIT\n"));
+			break;
+		case IBWS_READY:
+			DEBUG(DEBUG_DEBUG, ("test IBWS_READY\n"));
+			break;
+		case IBWS_CONNECT_REQUEST:
+			DEBUG(DEBUG_DEBUG, ("test IBWS_CONNECT_REQUEST\n"));
+			tconn = talloc_zero(conn, struct ibwtest_conn);
+			if (ibw_accept(ctx, conn, tconn)) {
+				DEBUG(DEBUG_ERR, ("error accepting the connect request\n"));
+			}
+			break;
+		case IBWS_STOPPED:
+			DEBUG(DEBUG_DEBUG, ("test IBWS_STOPPED\n"));
+			tcx->kill_me = 1; /* main loop can exit */
+			break;
+		case IBWS_ERROR:
+			DEBUG(DEBUG_DEBUG, ("test IBWS_ERROR\n"));
+			ibw_stop(tcx->ibwctx);
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+
+	if (conn) {
+		tconn = talloc_get_type(conn->conn_userdata, struct ibwtest_conn);
+		switch(conn->state) {
+		case IBWC_INIT:
+			DEBUG(DEBUG_DEBUG, ("test IBWC_INIT\n"));
+			break;
+		case IBWC_CONNECTED:
+			if (gettimeofday(&tcx->start_time, NULL)) {
+				DEBUG(DEBUG_ERR, ("gettimeofday error %d", errno));
+				return -1;
+			}
+			ibwtest_send_id(conn);
+			break;
+		case IBWC_DISCONNECTED:
+			DEBUG(DEBUG_DEBUG, ("test IBWC_DISCONNECTED\n"));
+			talloc_free(conn);
+			break;
+		case IBWC_ERROR:
+			DEBUG(DEBUG_DEBUG, ("test IBWC_ERROR %s\n", ibw_getLastError()));
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return 0;
+}
+
+int ibwtest_receive_handler(struct ibw_conn *conn, void *buf, int n)
+{
+	struct ibwtest_conn *tconn;
+	enum testopcode op;
+	struct ibwtest_ctx *tcx = talloc_get_type(conn->ctx->ctx_userdata, struct ibwtest_ctx);
+	int	rc = 0;
+
+	assert(conn!=NULL);
+	assert(n>=sizeof(uint32_t)+1);
+	tconn = talloc_get_type(conn->conn_userdata, struct ibwtest_conn);
+
+	op = (enum testopcode)((char *)buf)[sizeof(uint32_t)];
+	if (op==TESTOP_SEND_ID) {
+		tconn->id = talloc_strdup(tconn, ((char *)buf)+sizeof(uint32_t)+1);
+	}
+	if (op==TESTOP_SEND_ID || op==TESTOP_SEND_TEXT) {
+		DEBUG(DEBUG_DEBUG, ("[%d]msg from %s: \"%s\"(%d)\n", op,
+			tconn->id ? tconn->id : "NULL", ((char *)buf)+sizeof(uint32_t)+1, n));
+	}
+
+	if (tcx->is_server) {
+		if (op==TESTOP_SEND_RND) {
+			unsigned char sum;
+			sum = ibwtest_get_sum((unsigned char *)buf + sizeof(uint32_t) + 1,
+				n - sizeof(uint32_t) - 2);
+			DEBUG(DEBUG_DEBUG, ("[%d]msg varsize %u/sum %u from %s\n",
+				op,
+				n - sizeof(uint32_t) - 2,
+				(uint32_t)sum,
+				tconn->id ? tconn->id : "NULL"));
+			if (sum!=((unsigned char *)buf)[n-1]) {
+				DEBUG(DEBUG_ERR, ("ERROR: checksum mismatch %u!=%u\n",
+					(uint32_t)sum, (uint32_t)((unsigned char *)buf)[n-1]));
+				ibw_stop(tcx->ibwctx);
+				goto error;
+			}
+		} else if (op!=TESTOP_SEND_ID) {
+			char *buf2;
+			void *key2;
+
+			/* bounce message regardless what it is */
+			if (ibw_alloc_send_buf(conn, (void **)&buf2, &key2, n)) {
+				fprintf(stderr, "ibw_alloc_send_buf error #2\n");
+				goto error;
+			}
+			memcpy(buf2, buf, n);
+			if (ibw_send(conn, buf2, key2, n)) {
+				fprintf(stderr, "ibw_send error #2\n");
+				goto error;
+			}
+			tcx->nsent++;
+		}
+	} else { /* client: */
+		if (op==TESTOP_SEND_ID && tcx->maxsize) {
+			/* send them in one blow */
+			rc = ibwtest_do_varsize_scenario_conn(tcx, conn);
+		}
+
+		if (tcx->nmsg) {
+			char	msg[26];
+			sprintf(msg, "hello world %d", tcx->nmsg--);
+			rc = ibwtest_send_test_msg(tcx, conn, msg);
+			if (tcx->nmsg==0) {
+				ibw_stop(tcx->ibwctx);
+				tcx->stopping = 1;
+			}
+		}
+	}
+
+	if (rc)
+		tcx->error = rc;
+
+	return rc;
+error:
+	return -1;
+}
+
+void ibwtest_timeout_handler(struct event_context *ev, struct timed_event *te, 
+	struct timeval t, void *private_data)
+{
+	struct ibwtest_ctx *tcx = talloc_get_type(private_data, struct ibwtest_ctx);
+	int	rc;
+
+	if (!tcx->is_server) {
+		struct ibw_conn *conn;
+		char	msg[50];
+
+		/* fill it with something variable... */
+		sprintf(msg, "hello world %d", tcx->cnt++);
+
+		/* send something to everybody... */
+		for(conn=tcx->ibwctx->conn_list; conn!=NULL; conn=conn->next) {
+			if (conn->state==IBWC_CONNECTED) {
+				rc = ibwtest_send_test_msg(tcx, conn, msg);
+				if (rc)
+					tcx->error = rc;
+			}
+		}
+	} /* else allow main loop run */
+}
+
+static struct ibwtest_ctx *testctx = NULL;
+
+void ibwtest_sigint_handler(int sig)
+{
+	DEBUG(DEBUG_ERR, ("got SIGINT\n"));
+	if (testctx) {
+		if (testctx->ibwctx->state==IBWS_READY ||
+			testctx->ibwctx->state==IBWS_CONNECT_REQUEST ||
+			testctx->ibwctx->state==IBWS_ERROR)
+		{
+			if (testctx->stopping) {
+				DEBUG(DEBUG_DEBUG, ("forcing exit...\n"));
+				testctx->kill_me = 1;
+			} else {
+				/* mostly expected case */
+				ibw_stop(testctx->ibwctx);
+				testctx->stopping = 1;
+			}
+		} else
+			testctx->kill_me = 1;
+	}
+}
+
+int ibwtest_parse_attrs(struct ibwtest_ctx *tcx, char *optext,
+	struct ibw_initattr **pattrs, int *nattrs, char op)
+{
+	int	i = 0, n = 1;
+	int	porcess_next = 1;
+	char	*p, *q;
+	struct ibw_initattr *attrs = NULL;
+
+	*pattrs = NULL;
+	for(p = optext; *p!='\0'; p++) {
+		if (*p==',')
+			n++;
+	}
+
+	attrs = (struct ibw_initattr *)talloc_size(tcx,
+		n * sizeof(struct ibw_initattr));
+	for(p = optext; *p!='\0'; p++) {
+		if (porcess_next) {
+			attrs[i].name = p;
+			q = strchr(p, ':');
+			if (q==NULL) {
+				fprintf(stderr, "-%c format error\n", op);
+				return -1;
+			}
+			*q = '\0';
+			attrs[i].value = q + 1;
+
+			porcess_next = 0;
+			i++;
+			p = q; /* ++ at end */
+		}
+		if (*p==',') {
+			*p = '\0'; /* ++ at end */
+			porcess_next = 1;
+		}
+	}
+	*pattrs = attrs;
+	*nattrs = n;
+
+	return 0;
+}
+
+static int ibwtest_get_address(const char *address, struct in_addr *addr)
+{
+	if (inet_pton(AF_INET, address, addr) <= 0) {
+		struct hostent *he = gethostbyname(address);
+		if (he == NULL || he->h_length > sizeof(*addr)) {
+			DEBUG(DEBUG_ERR, ("invalid nework address '%s'\n", address));
+			return -1;
+		}
+		memcpy(addr, he->h_addr, he->h_length);
+	}
+	return 0;
+}
+
+int ibwtest_getdests(struct ibwtest_ctx *tcx, char op)
+{
+	int	i;
+	struct ibw_initattr	*attrs = NULL;
+	struct sockaddr_in	*p;
+	char	*tmp;
+
+	tmp = talloc_strdup(tcx, optarg);
+	if (tmp == NULL) return -1;
+	/* hack to reuse the above ibw_initattr parser */
+	if (ibwtest_parse_attrs(tcx, tmp, &attrs, &tcx->naddrs, op))
+		return -1;
+
+	tcx->addrs = talloc_size(tcx,
+		tcx->naddrs * sizeof(struct sockaddr_in));
+	for(i=0; i<tcx->naddrs; i++) {
+		p = tcx->addrs + i;
+		p->sin_family = AF_INET;
+		if (ibwtest_get_address(attrs[i].name, &p->sin_addr))
+			return -1;
+		p->sin_port = htons(atoi(attrs[i].value));
+	}
+
+	return 0;
+}
+
+int ibwtest_init_server(struct ibwtest_ctx *tcx)
+{
+	if (tcx->naddrs!=1) {
+		fprintf(stderr, "incorrect number of addrs(%d!=1)\n", tcx->naddrs);
+		return -1;
+	}
+
+	if (ibw_bind(tcx->ibwctx, &tcx->addrs[0])) {
+		DEBUG(DEBUG_ERR, ("ERROR: ibw_bind failed\n"));
+		return -1;
+	}
+	
+	if (ibw_listen(tcx->ibwctx, 1)) {
+		DEBUG(DEBUG_ERR, ("ERROR: ibw_listen failed\n"));
+		return -1;
+	}
+
+	/* continued at IBWS_READY */
+	return 0;
+}
+
+void ibwtest_usage(struct ibwtest_ctx *tcx, char *name)
+{
+	printf("Usage:\n");
+	printf("\t%s -i <id> -o {name:value} -d {addr:port} -t nsec -s\n", name);
+	printf("\t-i <id> is a free text, acting as a server id, max 23 chars [mandatory]\n");
+	printf("\t-o name1:value1,name2:value2,... is a list of (name, value) pairs\n");
+	printf("\t-a addr1:port1,addr2:port2,... is a list of destination ip addresses\n");
+	printf("\t-t nsec delta time between sends in nanosec [default %d]\n", tcx->nsec);
+	printf("\t\t send message periodically and endless when nsec is non-zero\n");
+	printf("\t-s server mode (you have to give exactly one -d address:port in this case)\n");
+	printf("\t-n number of messages to send [default %d]\n", tcx->nmsg);
+	printf("\t-l usec time to sleep in the main loop [default %d]\n", tcx->sleep_usec);
+	printf("\t-v max variable msg size in bytes [default %d], 0=don't send var. size\n", tcx->maxsize);
+	printf("\t-d LogLevel [default %d]\n", LogLevel);	
+	printf("Press ctrl+C to stop the program.\n");
+}
+
+int main(int argc, char *argv[])
+{
+	int	rc, op;
+	int	result = 1;
+	struct tevent_context *ev = NULL;
+	struct ibwtest_ctx *tcx = NULL;
+	float	usec;
+
+	tcx = talloc_zero(NULL, struct ibwtest_ctx);
+	memset(tcx, 0, sizeof(struct ibwtest_ctx));
+	tcx->nsec = 0;
+	tcx->nmsg = 1000;
+	LogLevel = 0;
+
+	/* here is the only case we can't avoid using global... */
+	testctx = tcx;
+	signal(SIGINT, ibwtest_sigint_handler);
+	srand((unsigned)time(NULL));
+
+	while ((op=getopt(argc, argv, "i:o:d:m:st:n:l:v:a:")) != -1) {
+		switch (op) {
+		case 'i':
+			tcx->id = talloc_strdup(tcx, optarg);
+			break;
+		case 'o':
+			tcx->opts = talloc_strdup(tcx, optarg);
+			if (tcx->opts) goto cleanup;
+			if (ibwtest_parse_attrs(tcx, tcx->opts, &tcx->attrs,
+				&tcx->nattrs, op))
+				goto cleanup;
+			break;
+		case 'a':
+			if (ibwtest_getdests(tcx, op))
+				goto cleanup;
+			break;
+		case 's':
+			tcx->is_server = 1;
+			break;
+		case 't':
+			tcx->nsec = (unsigned int)atoi(optarg);
+			break;
+		case 'n':
+			tcx->nmsg = atoi(optarg);
+			break;
+		case 'l':
+			tcx->sleep_usec = (unsigned int)atoi(optarg);
+			break;
+		case 'v':
+			tcx->maxsize = (unsigned int)atoi(optarg);
+			break;
+		case 'd':
+			LogLevel = atoi(optarg);
+			break;
+		default:
+			fprintf(stderr, "ERROR: unknown option -%c\n", (char)op);
+			ibwtest_usage(tcx, argv[0]);
+			goto cleanup;
+		}
+	}
+	if (tcx->id==NULL) {
+		ibwtest_usage(tcx, argv[0]);
+		goto cleanup;
+	}
+
+	ev = event_context_init(NULL);
+	assert(ev);
+
+	tcx->ibwctx = ibw_init(tcx->attrs, tcx->nattrs,
+		tcx,
+		ibwtest_connstate_handler,
+		ibwtest_receive_handler,
+		ev
+	);
+	if (!tcx->ibwctx)
+		goto cleanup;
+
+	if (tcx->is_server)
+		rc = ibwtest_init_server(tcx);
+	else
+		rc = ibwtest_connect_everybody(tcx);
+	if (rc)
+		goto cleanup;
+
+	while(!tcx->kill_me && !tcx->error) {
+		if (tcx->nsec) {
+			event_add_timed(ev, tcx, timeval_current_ofs(0, tcx->nsec),
+				ibwtest_timeout_handler, tcx);
+		}
+
+		event_loop_once(ev);
+
+		if (tcx->sleep_usec)
+			usleep(tcx->sleep_usec);
+	}
+
+	if (!tcx->is_server && tcx->nsent!=0 && !tcx->error) {
+		if (gettimeofday(&tcx->end_time, NULL)) {
+			DEBUG(DEBUG_ERR, ("gettimeofday error %d\n", errno));
+			goto cleanup;
+		}
+		usec = (tcx->end_time.tv_sec - tcx->start_time.tv_sec) * 1000000 +
+				(tcx->end_time.tv_usec - tcx->start_time.tv_usec);
+		printf("usec: %f, nmsg: %d, usec/nmsg: %f\n",
+			usec, tcx->nsent, usec/(float)tcx->nsent);
+	}
+
+	if (!tcx->error)
+		result = 0; /* everything OK */
+
+cleanup:
+	if (tcx)
+		talloc_free(tcx);
+	if (ev)
+		talloc_free(ev);
+	DEBUG(DEBUG_ERR, ("exited with code %d\n", result));
+	return result;
+}

Added: branches/ctdb/squeeze-backports/include/cmdline.h
===================================================================
--- branches/ctdb/squeeze-backports/include/cmdline.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/include/cmdline.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+
+extern struct poptOption popt_ctdb_cmdline[];
+
+#define POPT_CTDB_CMDLINE { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_ctdb_cmdline, 0, "Common ctdb test options:", NULL },
+
+struct ctdb_context *ctdb_cmdline_init(struct event_context *ev);
+

Added: branches/ctdb/squeeze-backports/include/ctdb.h
===================================================================
--- branches/ctdb/squeeze-backports/include/ctdb.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/include/ctdb.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,893 @@
+/*
+   ctdb database library
+
+   Copyright (C) Ronnie sahlberg 2010
+   Copyright (C) Rusty Russell 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CTDB_H
+#define _CTDB_H
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <tdb.h>
+#include <netinet/in.h>
+#include <ctdb_protocol.h>
+
+/**
+ * ctdb - a library for accessing tdbs controlled by ctdbd
+ *
+ * ctdbd (clustered tdb daemon) is a daemon designed to syncronize TDB
+ * databases across a cluster.  Using this library, you can communicate with
+ * the daemon to access the databases, pass messages across the cluster, and
+ * control the daemon itself.
+ *
+ * The general API is event-driven and asynchronous: you call the
+ * *_send functions, supplying callbacks, then when the ctdbd file
+ * descriptor is usable, call ctdb_service() to perform read from it
+ * and call your callbacks, which use the *_recv functions to unpack
+ * the replies from ctdbd.
+ *
+ * There is also a synchronous wrapper for each function for trivial
+ * programs; these can be found in the section marked "Synchronous API".
+ */
+
+/**
+ * ctdb_log_fn_t - logging function for ctdbd
+ * @log_priv: private (typesafe) arg via ctdb_connect
+ * @severity: syslog-style severity
+ * @format: printf-style format string.
+ * @ap: arguments for formatting.
+ *
+ * The severity passed to log() are as per syslog(3).  In particular,
+ * LOG_DEBUG is used for tracing, LOG_WARNING is used for unusual
+ * conditions which don't necessarily return an error through the API,
+ * LOG_ERR is used for errors such as lost communication with ctdbd or
+ * out-of-memory, LOG_ALERT is used for library usage bugs, LOG_CRIT is
+ * used for libctdb internal consistency checks.
+ *
+ * The log() function can be typesafe: the @log_priv arg to
+ * ctdb_donnect and signature of log() should match.
+ */
+typedef void (*ctdb_log_fn_t)(void *log_priv,
+			      int severity, const char *format, va_list ap);
+
+/**
+ * ctdb_connect - connect to ctdb using the specified domain socket.
+ * @addr: the socket address, or NULL for default
+ * @log: the logging function
+ * @log_priv: the private argument to the logging function.
+ *
+ * Returns a ctdb context if successful or NULL.  Use ctdb_disconnect() to
+ * release the returned ctdb_connection when finished.
+ *
+ * See Also:
+ *	ctdb_log_fn_t, ctdb_log_file()
+ */
+struct ctdb_connection *ctdb_connect(const char *addr,
+				     ctdb_log_fn_t log_fn, void *log_priv);
+
+/**
+ * ctdb_log_file - example logging function
+ *
+ * Logs everything at priority LOG_WARNING or above to the file given (via
+ * the log_priv argument, usually stderr).
+ */
+void ctdb_log_file(FILE *, int, const char *, va_list);
+
+/**
+ * ctdb_log_level - level at which to call logging function
+ *
+ * This variable globally controls filtering on the logging function.
+ * It is initialized to LOG_WARNING, meaning that strange but nonfatal
+ * events, as well as errors and API misuses are reported.
+ *
+ * Set it to LOG_DEBUG to receive all messages.
+ */
+extern int ctdb_log_level;
+
+/**
+ * ctdb_disconnect - close down a connection to ctdbd.
+ * @ctdb: the ctdb connectio returned from ctdb_connect.
+ *
+ * The @ctdb arg will be freed by this call, and must not be used again.
+ */
+void ctdb_disconnect(struct ctdb_connection *ctdb);
+
+/***
+ *
+ *  Asynchronous API
+ *
+ ***/
+
+/**
+ * ctdb_num_active - get the number of active commands
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ *
+ * This command can be used to find the number of active commands we have
+ * issued. An active command is a command we have queued, or sent
+ * to the ctdb daemon but which we have not yet received a reply to.
+ *
+ * See Also:
+ *	ctdb_num_in_flight(), ctdb_num_out_queue()
+ */
+int ctdb_num_active(struct ctdb_connection *ctdb);
+
+/**
+ * ctdb_num_in_flight - get the number of commands in flight.
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ *
+ * This command can be used to find the number of commands we have
+ * sent to the ctdb daemon to which we have not yet received/processed
+ * the reply.
+ *
+ * See Also:
+ *	ctdb_num_out_queue(), ctdb_num_active()
+ */
+int ctdb_num_in_flight(struct ctdb_connection *ctdb);
+
+/**
+ * ctdb_num_out_queue - get the number of commands in the out queue
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ *
+ * This command can be used to find the number of commands we have
+ * queued for delivery to the ctdb daemon but have not yet been
+ * written to the domain socket.
+ *
+ * See Also:
+ *	ctdb_num_in_flight(), ctdb_num_active()
+ */
+int ctdb_num_out_queue(struct ctdb_connection *ctdb);
+
+/**
+ * ctdb_get_fd - get the filedescriptor to select/poll on
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ *
+ * By using poll or select on this file descriptor, you will know when to call
+ * ctdb_service().
+ *
+ * See Also:
+ *	ctdb_which_events(), ctdb_service()
+ */
+int ctdb_get_fd(struct ctdb_connection *ctdb);
+
+/**
+ * ctdb_which_events - determine which events ctdb_service wants to see
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ *
+ * This returns POLLIN, possibly or'd with POLLOUT if there are writes
+ * pending.  You can set this straight into poll.events.
+ *
+ * See Also:
+ *	ctdb_service()
+ */
+int ctdb_which_events(struct ctdb_connection *ctdb);
+
+/**
+ * ctdb_service - service any I/O and callbacks from ctdbd communication
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @revents: which events are available.
+ *
+ * This is the core of the library: it read and writes to the ctdbd
+ * socket.  It may call callbacks registered with the various _send
+ * functions.
+ *
+ * revents is a bitset: POLLIN and/or POLLOUT may be set to indicate
+ * it is worth attempting to read/write the (nonblocking)
+ * filedescriptor respectively.
+ *
+ * Note that the synchronous functions call this internally.
+ * Returns false on catastrophic failure.
+ */
+bool ctdb_service(struct ctdb_connection *ctdb, int revents);
+
+/**
+ * struct ctdb_request - handle for an outstanding request
+ *
+ * This opaque structure returned from various *_send functions gives
+ * you a handle by which you can cancel a request.  You can't do
+ * anything else with it until the request is completed and it is
+ * handed to your callback function.
+ */
+struct ctdb_request;
+
+/**
+ * ctdb_request_free - free a completed request
+ *
+ * This frees a request: you should only call it once it has been
+ * handed to your callback.  For incomplete requests, see ctdb_cancel().
+ */
+void ctdb_request_free(struct ctdb_request *req);
+
+/**
+ * ctdb_callback_t - callback for completed requests.
+ *
+ * This would normally unpack the request using ctdb_*_recv().  You
+ * must free the request using ctdb_request_free().
+ *
+ * Note that due to macro magic, actual your callback can be typesafe:
+ * instead of taking a void *, it can take a type which matches the
+ * actual private parameter.
+ */
+typedef void (*ctdb_callback_t)(struct ctdb_connection *ctdb,
+				struct ctdb_request *req, void *private_data);
+
+/**
+ * struct ctdb_db - connection to a particular open TDB
+ *
+ * This represents a particular open database: you receive it from
+ * ctdb_attachdb or ctdb_attachdb_recv to manipulate a database.
+ *
+ * You have to free the handle with ctdb_detachdb() when finished with it.
+ */
+struct ctdb_db;
+
+/**
+ * ctdb_attachdb_send - open a clustered TDB
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @name: the filename of the database (no /).
+ * @persistent: whether the database is persistent across ctdbd's life
+ * @tdb_flags: the flags to pass to tdb_open.
+ * @callback: the callback when we're attached or failed (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * This function connects to a TDB controlled by ctdbd.  It can create
+ * a new TDB if it does not exist, depending on tdb_flags.  Returns
+ * the pending request, or NULL on error.
+ */
+struct ctdb_request *
+ctdb_attachdb_send(struct ctdb_connection *ctdb,
+		   const char *name, bool persistent, uint32_t tdb_flags,
+		   ctdb_callback_t callback, void *cbdata);
+
+/**
+ * ctdb_attachdb_recv - read an ctdb_attach reply from ctdbd
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request.
+ *
+ * This returns NULL if something went wrong, or otherwise the open database.
+ */
+struct ctdb_db *ctdb_attachdb_recv(struct ctdb_connection *ctdb,
+				   struct ctdb_request *req);
+
+
+/**
+ * struct ctdb_lock - a record lock on a clustered TDB database
+ *
+ * This locks a subset of the database across the entire cluster; it
+ * is the fundamental sychronization element for ctdb.  You cannot have
+ * more than one lock at once.
+ *
+ * You MUST NOT block during holding this lock and MUST release it
+ * quickly by performing ctdb_release_lock(lock).
+ * Do NOT make any system calls that may block while holding the lock.
+ *
+ * Try to release the lock as quickly as possible.
+ */
+struct ctdb_lock;
+
+/**
+ * ctdb_rrl_callback_t - callback for ctdb_readrecordlock_async
+ *
+ * This is not the standard ctdb_callback_t, because there is often no
+ * request required to access a database record (ie. if it is local already).
+ * So the callback is handed the lock directly: it might be NULL if there
+ * was an error obtaining the lock.
+ *
+ * See Also:
+ *	ctdb_readrecordlock_async(), ctdb_readrecordlock()
+ */
+typedef void (*ctdb_rrl_callback_t)(struct ctdb_db *ctdb_db,
+				    struct ctdb_lock *lock,
+				    TDB_DATA data,
+				    void *private_data);
+
+/**
+ * ctdb_readrecordlock_async - read and lock a record
+ * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
+ * @key: the key of the record to lock.
+ * @callback: the callback once the record is locked (typesafe).
+ * @cbdata: the argument to callback()
+ *
+ * This returns true on success.  Commonly, we can obtain the record
+ * immediately and so the callback will be invoked.  Otherwise a request
+ * will be queued to ctdbd for the record.
+ *
+ * If failure is immediate, false is returned.  Otherwise, the callback
+ * may receive a NULL lock arg to indicate asynchronous failure.
+ */
+bool ctdb_readrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key,
+			       ctdb_rrl_callback_t callback, void *cbdata);
+
+/**
+ * ctdb_readonlyrecordlock_async - read and lock a record for read-only access
+ * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
+ * @key: the key of the record to lock.
+ * @callback: the callback once the record is locked (typesafe).
+ * @cbdata: the argument to callback()
+ *
+ * This returns true on success.  Commonly, we can obtain the record
+ * immediately and so the callback will be invoked.  Otherwise a request
+ * will be queued to ctdbd for the record.
+ *
+ * If failure is immediate, false is returned.  Otherwise, the callback
+ * may receive a NULL lock arg to indicate asynchronous failure.
+ */
+bool ctdb_readonlyrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key,
+			       ctdb_rrl_callback_t callback, void *cbdata);
+
+
+/**
+ * ctdb_writerecord - write a locked record in a TDB
+ * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
+ * @lock: the lock from ctdb_readrecordlock/ctdb_readrecordlock_recv
+ * @data: the new data to place in the record.
+ */
+bool ctdb_writerecord(struct ctdb_db *ctdb_db,
+		      struct ctdb_lock *lock, TDB_DATA data);
+
+/**
+ * ctdb_release_lock - release a record lock on a TDB
+ * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
+ * @lock: the lock from ctdb_readrecordlock/ctdb_readrecordlock_async
+ */
+void ctdb_release_lock(struct ctdb_db *ctdb_db, struct ctdb_lock *lock);
+
+
+
+/**
+ * ctdb_traverse_callback_t - callback for ctdb_traverse_async.
+ * return 0 - to continue traverse
+ * return 1 - to abort the traverse
+ *
+ * See Also:
+ *	ctdb_traverse_async()
+ */
+#define TRAVERSE_STATUS_RECORD		0
+#define TRAVERSE_STATUS_FINISHED	1
+#define TRAVERSE_STATUS_ERROR		2
+typedef int (*ctdb_traverse_callback_t)(struct ctdb_connection *ctdb,
+				    struct ctdb_db *ctdb_db,
+				    int status,
+				    TDB_DATA key,
+				    TDB_DATA data,
+				    void *private_data);
+
+/**
+ * ctdb_traverse_async - traverse a database.
+ * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
+ * @callback: the callback once the record is locked (typesafe).
+ * @cbdata: the argument to callback()
+ *
+ * This returns true on success.
+ * when successfull, the callback will be invoked for each record
+ * until the traversal is finished.
+ *
+ * status == 
+ * TRAVERSE_STATUS_RECORD         key/data contains a record.
+ * TRAVERSE_STATUS_FINISHED       traverse is finished. key/data is undefined.
+ * TRAVERSE_STATUS_ERROR          an error occured during traverse.
+ *                                key/data is undefined.
+ *
+ * If failure is immediate, false is returned.
+ */
+bool ctdb_traverse_async(struct ctdb_db *ctdb_db,
+			 ctdb_traverse_callback_t callback, void *cbdata);
+
+/**
+ * ctdb_message_fn_t - messaging callback for ctdb messages
+ *
+ * ctdbd provides a simple messaging API; you can register for a particular
+ * 64-bit id on which you want to send messages, and send to other ids.
+ *
+ * See Also:
+ *	ctdb_set_message_handler_send()
+ */
+typedef void (*ctdb_message_fn_t)(struct ctdb_connection *,
+				  uint64_t srvid, TDB_DATA data, void *);
+
+/**
+ * ctdb_set_message_handler_send - register for messages to a srvid
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @srvid: the 64 bit identifier for our messages.
+ * @handler: the callback when we receive such a message (typesafe)
+ * @handler_data: the argument to handler()
+ * @callback: the callback when ctdb replies to our message (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * Note: our callback will always be called before handler.
+ *
+ * See Also:
+ *	ctdb_set_message_handler_recv(), ctdb_remove_message_handler_send()
+ */
+struct ctdb_request *
+ctdb_set_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
+			      ctdb_message_fn_t handler,
+			      void *handler_data,
+			      ctdb_callback_t callback,
+			      void *cbdata);
+
+/**
+ * ctdb_set_message_handler_recv - read a set_message_handler result
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request
+ *
+ * If this returns true, the registered handler may be called from the next
+ * ctdb_service().  If this returns false, the registration failed.
+ */
+bool ctdb_set_message_handler_recv(struct ctdb_connection *ctdb,
+				   struct ctdb_request *handle);
+
+/**
+ * ctdb_remove_message_handler_send - unregister for messages to a srvid
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @srvid: the 64 bit identifier for our messages.
+ * @handler: the callback when we receive such a message (typesafe)
+ * @handler_data: the argument to handler()
+ * @callback: the callback when ctdb replies to our message (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * This undoes a successful ctdb_set_message_handler or
+ * ctdb_set_message_handler_recv.
+ */
+struct ctdb_request *
+ctdb_remove_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
+				 ctdb_message_fn_t handler, void *handler_data,
+				 ctdb_callback_t callback, void *cbdata);
+
+/**
+ * ctdb_remove_message_handler_recv - read a remove_message_handler result
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request
+ *
+ * After this returns true, the registered handler will no longer be called.
+ * If this returns false, the de-registration failed.
+ */
+bool ctdb_remove_message_handler_recv(struct ctdb_connection *ctdb,
+				      struct ctdb_request *req);
+
+
+/**
+ * ctdb_send_message - send a message via ctdbd
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @pnn: the physical node number to send to
+ * @srvid: the 64 bit identifier for this message type.
+ * @data: the data to send
+ *
+ * This allows arbitrary messages to be sent across the cluster to those
+ * listening (via ctdb_set_message_handler et al).
+ *
+ * This queues a message to be sent: you will need to call
+ * ctdb_service() to actually send the message.  There is no callback
+ * because there is no acknowledgement.
+ *
+ * See Also:
+ *	ctdb_getpnn_send(), ctdb_getpnn()
+ */
+bool ctdb_send_message(struct ctdb_connection *ctdb, uint32_t pnn, uint64_t srvid, TDB_DATA data);
+
+/**
+ * ctdb_getpnn_send - read the pnn number of a node.
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @callback: the callback when ctdb replies to our message (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ */
+struct ctdb_request *
+ctdb_getpnn_send(struct ctdb_connection *ctdb,
+		 uint32_t destnode,
+		 ctdb_callback_t callback,
+		 void *cbdata);
+/**
+ * ctdb_getpnn_recv - read an ctdb_getpnn reply from ctdbd
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request.
+ * @pnn: a pointer to the pnn to fill in
+ *
+ * This returns false if something went wrong, or otherwise fills in pnn.
+ */
+bool ctdb_getpnn_recv(struct ctdb_connection *ctdb,
+		      struct ctdb_request *req, uint32_t *pnn);
+
+
+/**
+ * ctdb_getnodemap_send - read the nodemap number from a node.
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @callback: the callback when ctdb replies to our message (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ */
+struct ctdb_request *
+ctdb_getnodemap_send(struct ctdb_connection *ctdb,
+		 uint32_t destnode,
+		 ctdb_callback_t callback,
+		 void *cbdata);
+/**
+ * ctdb_getnodemap_recv - read an ctdb_getnodemap reply from ctdbd
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request.
+ * @nodemap: a pointer to the returned nodemap structure
+ *
+ * This returns false if something went wrong.
+ * If the command failed, it guarantees to set nodemap to NULL.
+ * A non-NULL value for nodemap means the command was successful.
+ *
+ * A non-NULL value of the nodemap must be release released/freed
+ * by ctdb_free_nodemap().
+ */
+bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb,
+		      struct ctdb_request *req, struct ctdb_node_map **nodemap);
+
+/**
+ * ctdb_getpublicips_send - read the public ip list from a node.
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @callback: the callback when ctdb replies to our message (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * This control returns the list of public ips known to the local node.
+ * Deamons only know about those ips that are listed in the local
+ * public addresses file, which means the returned list of ips may
+ * be only a subset of all ips across the entire cluster.
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ */
+struct ctdb_request *
+ctdb_getpublicips_send(struct ctdb_connection *ctdb,
+		 uint32_t destnode,
+		 ctdb_callback_t callback,
+		 void *cbdata);
+/**
+ * ctdb_getpublicips_recv - read the public ip list from a node
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request.
+ * @ips: a pointer to the returned public ip list
+ *
+ * This returns false if something went wrong.
+ * If the command failed, it guarantees to set ips to NULL.
+ * A non-NULL value for nodemap means the command was successful.
+ *
+ * A non-NULL value of the nodemap must be release released/freed
+ * by ctdb_free_publicips().
+ */
+bool ctdb_getpublicips_recv(struct ctdb_connection *ctdb,
+		      struct ctdb_request *req, struct ctdb_all_public_ips **ips);
+
+
+/**
+ * ctdb_getrecmaster_send - read the recovery master of a node
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @callback: the callback when ctdb replies to our message (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ */
+struct ctdb_request *
+ctdb_getrecmaster_send(struct ctdb_connection *ctdb,
+			uint32_t destnode,
+			ctdb_callback_t callback, void *cbdata);
+
+/**
+ * ctdb_getrecmaster_recv - read an ctdb_getrecmaster reply from ctdbd
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request.
+ * @recmaster: a pointer to the recmaster to fill in
+ *
+ * This returns false if something went wrong, or otherwise fills in
+ * recmaster.
+ */
+bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb,
+			    struct ctdb_request *handle,
+			    uint32_t *recmaster);
+
+/**
+ * ctdb_getrecmode_send - read the recovery mode of a node
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @callback: the callback when ctdb replies to our message (typesafe)
+ * @cbdata: the argument to callback()
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ */
+struct ctdb_request *
+ctdb_getrecmode_send(struct ctdb_connection *ctdb,
+		     uint32_t destnode,
+		     ctdb_callback_t callback, void *cbdata);
+
+/**
+ * ctdb_getrecmode_recv - read an ctdb_getrecmode reply from ctdbd
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the completed request.
+ * @recmode: a pointer to the recmode to fill in
+ *
+ * This returns false if something went wrong, or otherwise fills in
+ * recmode.
+ */
+bool ctdb_getrecmode_recv(struct ctdb_connection *ctdb,
+			  struct ctdb_request *handle,
+			  uint32_t *recmode);
+
+/**
+ * ctdb_cancel - cancel an uncompleted request
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @req: the uncompleted request.
+ *
+ * This cancels a request, returning true.  You may not cancel a
+ * request which has already been completed (ie. once its callback has
+ * been called); you should simply use ctdb_request_free() in that case.
+ */
+void ctdb_cancel(struct ctdb_connection *ctdb, struct ctdb_request *req);
+
+/***
+ *
+ *  Synchronous API
+ *
+ ***/
+
+/**
+ * ctdb_attachdb - open a clustered TDB (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @name: the filename of the database (no /).
+ * @persistent: whether the database is persistent across ctdbd's life
+ * @tdb_flags: the flags to pass to tdb_open.
+ *
+ * Do a ctdb_attachdb_send and wait for it to complete.
+ * Returns NULL on failure.
+ */
+struct ctdb_db *ctdb_attachdb(struct ctdb_connection *ctdb,
+			      const char *name, bool persistent,
+			      uint32_t tdb_flags);
+
+/**
+ * ctdb_detachdb - close a clustered TDB.
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @db: the database from ctdb_attachdb/ctdb_attachdb_send
+ *
+ * Closes a clustered tdb.
+ */
+void ctdb_detachdb(struct ctdb_connection *ctdb, struct ctdb_db *db);
+
+/**
+ * ctdb_readrecordlock - read and lock a record (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv.
+ * @key: the key of the record to lock.
+ * @req: a pointer to the request, if one is needed.
+ *
+ * Do a ctdb_readrecordlock_send and wait for it to complete.
+ * Returns NULL on failure.
+ */
+struct ctdb_lock *ctdb_readrecordlock(struct ctdb_connection *ctdb,
+				      struct ctdb_db *ctdb_db, TDB_DATA key,
+				      TDB_DATA *data);
+
+
+/**
+ * ctdb_set_message_handler - register for messages to a srvid (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @srvid: the 64 bit identifier for our messages.
+ * @handler: the callback when we receive such a message (typesafe)
+ * @cbdata: the argument to handler()
+ *
+ * If this returns true, the message handler can be called from any
+ * ctdb_service() (which is also called indirectly by other
+ * synchronous functions).  If this returns false, the registration
+ * failed.
+ */
+bool ctdb_set_message_handler(struct ctdb_connection *ctdb, uint64_t srvid,
+			      ctdb_message_fn_t handler, void *cbdata);
+
+
+/**
+ * ctdb_remove_message_handler - deregister for messages (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @srvid: the 64 bit identifier for our messages.
+ * @handler: the callback when we receive such a message (typesafe)
+ * @handler_data: the argument to handler()
+ *
+ * If this returns true, the message handler will no longer be called.
+ * If this returns false, the deregistration failed.
+ */
+bool ctdb_remove_message_handler(struct ctdb_connection *ctdb, uint64_t srvid,
+				 ctdb_message_fn_t handler, void *handler_data);
+
+/**
+ * ctdb_getpnn - read the pnn number of a node (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @pnn: a pointer to the pnn to fill in
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ *
+ * Returns true and fills in *pnn on success.
+ */
+bool ctdb_getpnn(struct ctdb_connection *ctdb,
+		 uint32_t destnode,
+		 uint32_t *pnn);
+
+/**
+ * ctdb_getrecmaster - read the recovery master of a node (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @recmaster: a pointer to the recmaster to fill in
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ *
+ * Returns true and fills in *recmaster on success.
+ */
+bool ctdb_getrecmaster(struct ctdb_connection *ctdb,
+		       uint32_t destnode,
+		       uint32_t *recmaster);
+
+
+/**
+ * ctdb_getrecmode - read the recovery mode of a node (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @recmode: a pointer to the recmode to fill in
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ *
+ * Returns true and fills in *recmode on success.
+ */
+bool ctdb_getrecmode(struct ctdb_connection *ctdb,
+		     uint32_t destnode,
+		     uint32_t *recmode);
+
+
+/**
+ * ctdb_getnodemap - read the nodemap from a node (synchronous)
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @nodemap: a pointer to the nodemap to fill in
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ *
+ * Returns true and fills in *nodemap on success.
+ * A non-NULL nodemap must be freed by calling ctdb_free_nodemap.
+ */
+bool ctdb_getnodemap(struct ctdb_connection *ctdb,
+		     uint32_t destnode, struct ctdb_node_map **nodemap);
+
+/*
+ * This function is used to release/free the nodemap structure returned
+ * by ctdb_getnodemap() and ctdb_getnodemap_recv()
+ */
+void ctdb_free_nodemap(struct ctdb_node_map *nodemap);
+
+
+/**
+ * ctdb_getpublicips - read the public ip list from a node.
+ * @ctdb: the ctdb_connection from ctdb_connect.
+ * @destnode: the destination node (see below)
+ * @ips: a pointer to the returned public ip list
+ *
+ * This control returns the list of public ips known to the local node.
+ * Deamons only know about those ips that are listed in the local
+ * public addresses file, which means the returned list of ips may
+ * be only a subset of all ips across the entire cluster.
+ *
+ * There are several special values for destnode, detailed in
+ * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the
+ * local ctdbd.
+ *
+ * This returns false if something went wrong.
+ * If the command failed, it guarantees to set ips to NULL.
+ * A non-NULL value for nodemap means the command was successful.
+ *
+ * A non-NULL value of the nodemap must be release released/freed
+ * by ctdb_free_publicips().
+ */
+bool ctdb_getpublicips(struct ctdb_connection *ctdb,
+		     uint32_t destnode, struct ctdb_all_public_ips **ips);
+
+/*
+ * This function is used to release/free the public ip structure returned
+ * by ctdb_getpublicips() and ctdb_getpublicips_recv()
+ */
+void ctdb_free_publicips(struct ctdb_all_public_ips *ips);
+
+
+/* These ugly macro wrappers make the callbacks typesafe. */
+#include <ctdb_typesafe_cb.h>
+#define ctdb_sendcb(cb, cbdata)						\
+	 typesafe_cb_preargs(void, (cb), (cbdata),			\
+			     struct ctdb_connection *, struct ctdb_request *)
+
+#define ctdb_msgcb(cb, cbdata)						\
+	typesafe_cb_preargs(void, (cb), (cbdata),			\
+			    struct ctdb_connection *, uint64_t, TDB_DATA)
+
+#define ctdb_connect(addr, log, logpriv)				\
+	ctdb_connect((addr),						\
+		     typesafe_cb_postargs(void, (log), (logpriv),	\
+					  int, const char *, va_list),	\
+		     (logpriv))
+
+#define ctdb_set_message_handler(ctdb, srvid, handler, hdata)		\
+	ctdb_set_message_handler((ctdb), (srvid),			\
+				 ctdb_msgcb((handler), (hdata)), (hdata))
+
+#define ctdb_remove_message_handler(ctdb, srvid, handler, hdata)	\
+	ctdb_remove_message_handler((ctdb), (srvid),			\
+				    ctdb_msgcb((handler), (hdata)), (hdata))
+
+#define ctdb_attachdb_send(ctdb, name, persistent, tdb_flags, cb, cbdata) \
+	ctdb_attachdb_send((ctdb), (name), (persistent), (tdb_flags),	\
+			   ctdb_sendcb((cb), (cbdata)), (cbdata))
+
+#define ctdb_readrecordlock_async(_ctdb_db, key, cb, cbdata)		\
+	ctdb_readrecordlock_async((_ctdb_db), (key),			\
+		typesafe_cb_preargs(void, (cb), (cbdata),		\
+				    struct ctdb_db *, struct ctdb_lock *, \
+				    TDB_DATA), (cbdata))
+
+#define ctdb_set_message_handler_send(ctdb, srvid, handler, hdata, cb, cbdata) \
+	ctdb_set_message_handler_send((ctdb), (srvid),			\
+				      ctdb_msgcb((handler), (hdata)), (hdata), \
+				      ctdb_sendcb((cb), (cbdata)), (cbdata))
+
+#define ctdb_remove_message_handler_send(ctdb, srvid, handler, hdata, cb, cbdata) \
+	ctdb_remove_message_handler_send((ctdb), (srvid),		\
+	      ctdb_msgcb((handler), (hdata)), (hdata),			\
+	      ctdb_sendcb((cb), (cbdata)), (cbdata))
+
+#define ctdb_getpnn_send(ctdb, destnode, cb, cbdata)			\
+	ctdb_getpnn_send((ctdb), (destnode),				\
+			 ctdb_sendcb((cb), (cbdata)), (cbdata))
+
+#define ctdb_getrecmaster_send(ctdb, destnode, cb, cbdata)		\
+	ctdb_getrecmaster_send((ctdb), (destnode),			\
+			       ctdb_sendcb((cb), (cbdata)), (cbdata))
+
+#define ctdb_getrecmode_send(ctdb, destnode, cb, cbdata)		\
+	ctdb_getrecmode_send((ctdb), (destnode),			\
+			       ctdb_sendcb((cb), (cbdata)), (cbdata))
+
+#define ctdb_getnodemap_send(ctdb, destnode, cb, cbdata)		\
+	ctdb_getnodemap_send((ctdb), (destnode),			\
+			 ctdb_sendcb((cb), (cbdata)), (cbdata))
+
+#define ctdb_getpublicips_send(ctdb, destnode, cb, cbdata)		\
+	ctdb_getpublicips_send((ctdb), (destnode),			\
+			 ctdb_sendcb((cb), (cbdata)), (cbdata))
+
+#endif

Added: branches/ctdb/squeeze-backports/include/ctdb_client.h
===================================================================
--- branches/ctdb/squeeze-backports/include/ctdb_client.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/include/ctdb_client.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,614 @@
+/*
+   ctdb database library: old client interface
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CTDB_CLIENT_H
+#define _CTDB_CLIENT_H
+#include <ctdb_protocol.h>
+
+enum control_state {CTDB_CONTROL_WAIT, CTDB_CONTROL_DONE, CTDB_CONTROL_ERROR, CTDB_CONTROL_TIMEOUT};
+
+struct ctdb_client_control_state {
+	struct ctdb_context *ctdb;
+	uint32_t reqid;
+	int32_t status;
+	TDB_DATA outdata;
+	enum control_state state;
+	char *errormsg;
+	struct ctdb_req_control *c;
+
+	/* if we have a callback registered for the completion (or failure) of
+	   this control
+	   if a callback is used, it MUST talloc_free the cb_data passed to it
+	*/
+	struct {
+		void (*fn)(struct ctdb_client_control_state *);
+		void *private_data;
+	} async;
+};
+
+struct ctdb_client_notify_register {
+	uint64_t srvid;
+	uint32_t len;
+	uint8_t notify_data[1];
+};
+
+struct ctdb_client_notify_deregister {
+	uint64_t srvid;
+};
+
+struct tevent_context;
+
+/*
+  initialise ctdb subsystem
+*/
+struct ctdb_context *ctdb_init(struct tevent_context *ev);
+
+/*
+  choose the transport
+*/
+int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport);
+
+/*
+  set the directory for the local databases
+*/
+int ctdb_set_tdb_dir(struct ctdb_context *ctdb, const char *dir);
+int ctdb_set_tdb_dir_persistent(struct ctdb_context *ctdb, const char *dir);
+int ctdb_set_tdb_dir_state(struct ctdb_context *ctdb, const char *dir);
+
+/*
+  set some flags
+*/
+void ctdb_set_flags(struct ctdb_context *ctdb, unsigned flags);
+
+/*
+  tell ctdb what address to listen on, in transport specific format
+*/
+int ctdb_set_address(struct ctdb_context *ctdb, const char *address);
+
+int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname);
+const char *ctdb_get_socketname(struct ctdb_context *ctdb);
+
+/*
+  tell ctdb what nodes are available. This takes a filename, which will contain
+  1 node address per line, in a transport specific format
+*/
+int ctdb_set_nlist(struct ctdb_context *ctdb, const char *nlist);
+
+/*
+  Check that a specific ip address exists in the node list and returns
+  the id for the node or -1
+*/
+int ctdb_ip_to_nodeid(struct ctdb_context *ctdb, const char *nodeip);
+
+/*
+  start the ctdb protocol
+*/
+int ctdb_start(struct ctdb_context *ctdb);
+int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork, bool use_syslog, const char *public_address_list);
+
+/*
+  attach to a ctdb database
+*/
+struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb,
+				    struct timeval timeout,
+				    const char *name,
+				    bool persistent,
+				    uint32_t tdb_flags);
+
+
+/*
+  find an attached ctdb_db handle given a name
+ */
+struct ctdb_db_context *ctdb_db_handle(struct ctdb_context *ctdb, const char *name);
+
+/*
+  error string for last ctdb error
+*/
+const char *ctdb_errstr(struct ctdb_context *);
+
+/* a ctdb call function */
+typedef int (*ctdb_fn_t)(struct ctdb_call_info *);
+
+/*
+  setup a ctdb call function
+*/
+int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id);
+
+
+
+/*
+  make a ctdb call. The associated ctdb call function will be called on the DMASTER
+  for the given record
+*/
+int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call);
+
+/*
+  initiate an ordered ctdb cluster shutdown
+  this function will never return
+*/
+void ctdb_shutdown(struct ctdb_context *ctdb);
+
+/* return pnn of this node */
+uint32_t ctdb_get_pnn(struct ctdb_context *ctdb);
+
+/*
+  return the number of nodes
+*/
+uint32_t ctdb_get_num_nodes(struct ctdb_context *ctdb);
+
+/* setup a handler for ctdb messages */
+typedef void (*ctdb_msg_fn_t)(struct ctdb_context *, uint64_t srvid,
+				  TDB_DATA data, void *);
+int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
+			     ctdb_msg_fn_t handler,
+			     void *private_data);
+int ctdb_client_remove_message_handler(struct ctdb_context *ctdb,
+				       uint64_t srvid, void *private_data);
+
+
+int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call);
+struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call);
+int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call);
+
+/* send a ctdb message */
+int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t pnn,
+		      uint64_t srvid, TDB_DATA data);
+
+
+/*
+   Fetch a ctdb record from a remote node
+ . Underneath this will force the
+   dmaster for the record to be moved to the local node.
+*/
+struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
+					   TDB_DATA key, TDB_DATA *data);
+
+struct ctdb_record_handle *ctdb_fetch_readonly_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data, int read_only);
+
+int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data);
+
+int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
+	       TDB_DATA key, TDB_DATA *data);
+
+int ctdb_register_message_handler(struct ctdb_context *ctdb,
+				  TALLOC_CTX *mem_ctx,
+				  uint64_t srvid,
+				  ctdb_msg_fn_t handler,
+				  void *private_data);
+
+struct ctdb_db_context *find_ctdb_db(struct ctdb_context *ctdb, uint32_t id);
+
+
+struct ctdb_context *ctdb_cmdline_client(struct tevent_context *ev,
+					 struct timeval req_timeout);
+
+struct ctdb_statistics;
+int ctdb_ctrl_statistics(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_statistics *status);
+
+int ctdb_ctrl_shutdown(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+
+struct ctdb_vnn_map;
+int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb,
+		struct timeval timeout, uint32_t destnode,
+		TALLOC_CTX *mem_ctx, struct ctdb_vnn_map **vnnmap);
+int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb,
+		struct timeval timeout, uint32_t destnode,
+		TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *vnnmap);
+
+/* table that contains a list of all dbids on a node
+ */
+struct ctdb_dbid_map {
+	uint32_t num;
+	struct ctdb_dbid {
+		uint32_t dbid;
+#define CTDB_DB_FLAGS_PERSISTENT	0x01
+#define CTDB_DB_FLAGS_READONLY		0x02
+		uint8_t flags;
+	} dbs[1];
+};
+int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb,
+	struct timeval timeout, uint32_t destnode,
+	TALLOC_CTX *mem_ctx, struct ctdb_dbid_map **dbmap);
+
+
+struct ctdb_node_map;
+
+int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb,
+		    struct timeval timeout, uint32_t destnode,
+		    TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap);
+
+int ctdb_ctrl_getnodemapv4(struct ctdb_context *ctdb,
+		    struct timeval timeout, uint32_t destnode,
+		    TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap);
+
+int ctdb_ctrl_reload_nodes_file(struct ctdb_context *ctdb,
+		    struct timeval timeout, uint32_t destnode);
+
+struct ctdb_key_list {
+	uint32_t dbid;
+	uint32_t num;
+	TDB_DATA *keys;
+	struct ctdb_ltdb_header *headers;
+	TDB_DATA *data;
+};
+
+int ctdb_ctrl_pulldb(
+       struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
+       uint32_t lmaster, TALLOC_CTX *mem_ctx,
+       struct timeval timeout, TDB_DATA *outdata);
+
+struct ctdb_client_control_state *ctdb_ctrl_pulldb_send(
+       struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
+       uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout);
+
+int ctdb_ctrl_pulldb_recv(
+       struct ctdb_context *ctdb,
+       TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state,
+       TDB_DATA *outdata);
+
+int ctdb_ctrl_pushdb(
+       struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
+       TALLOC_CTX *mem_ctx,
+       struct timeval timeout, TDB_DATA indata);
+
+struct ctdb_client_control_state *ctdb_ctrl_pushdb_send(
+       struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid,
+       TALLOC_CTX *mem_ctx, struct timeval timeout,
+       TDB_DATA indata);
+
+int ctdb_ctrl_pushdb_recv(
+       struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+       struct ctdb_client_control_state *state);
+
+
+int ctdb_ctrl_copydb(struct ctdb_context *ctdb,
+	struct timeval timeout, uint32_t sourcenode,
+	uint32_t destnode, uint32_t dbid, uint32_t lmaster,
+	TALLOC_CTX *mem_ctx);
+
+int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **path);
+int ctdb_ctrl_getdbname(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **name);
+int ctdb_ctrl_getdbhealth(struct ctdb_context *ctdb,
+			  struct timeval timeout,
+			  uint32_t destnode,
+			  uint32_t dbid, TALLOC_CTX *mem_ctx,
+			  const char **reason);
+int ctdb_ctrl_createdb(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const char *name, bool persistent);
+
+int ctdb_ctrl_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid);
+
+int ctdb_ctrl_ping(struct ctdb_context *ctdb, uint32_t destnode);
+
+int ctdb_ctrl_get_config(struct ctdb_context *ctdb);
+
+int ctdb_ctrl_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t *level);
+int ctdb_ctrl_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t level);
+
+/*
+  change dmaster for all keys in the database to the new value
+ */
+int ctdb_ctrl_setdmaster(struct ctdb_context *ctdb,
+	struct timeval timeout, uint32_t destnode,
+	TALLOC_CTX *mem_ctx, uint32_t dbid, uint32_t dmaster);
+
+/*
+  write a record on a specific db (this implicitely updates dmaster of the record to locally be the vnn of the node where the control is executed on)
+ */
+int ctdb_ctrl_write_record(struct ctdb_context *ctdb, uint32_t destnode, TALLOC_CTX *mem_ctx, uint32_t dbid, TDB_DATA key, TDB_DATA data);
+
+#define CTDB_RECOVERY_NORMAL		0
+#define CTDB_RECOVERY_ACTIVE		1
+
+/*
+  get the recovery mode of a remote node
+ */
+int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmode);
+
+struct ctdb_client_control_state *ctdb_ctrl_getrecmode_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_getrecmode_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmode);
+
+
+/*
+  set the recovery mode of a remote node
+ */
+int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmode);
+/*
+  get the monitoring mode of a remote node
+ */
+int ctdb_ctrl_getmonmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *monmode);
+
+/*
+  set the monitoring mode of a remote node to active
+ */
+int ctdb_ctrl_enable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+
+/*
+  set the monitoring mode of a remote node to disabled
+ */
+int ctdb_ctrl_disable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+
+
+/*
+  get the recovery master of a remote node
+ */
+int ctdb_ctrl_getrecmaster(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmaster);
+
+struct ctdb_client_control_state *ctdb_ctrl_getrecmaster_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_getrecmaster_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmaster);
+
+
+
+/*
+  set the recovery master of a remote node
+ */
+int ctdb_ctrl_setrecmaster(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmaster);
+
+uint32_t *ctdb_get_connected_nodes(struct ctdb_context *ctdb,
+				   struct timeval timeout,
+				   TALLOC_CTX *mem_ctx,
+				   uint32_t *num_nodes);
+
+int ctdb_statistics_reset(struct ctdb_context *ctdb, uint32_t destnode);
+
+int ctdb_set_logfile(struct ctdb_context *ctdb, const char *logfile, bool use_syslog);
+
+typedef int (*ctdb_traverse_func)(struct ctdb_context *, TDB_DATA, TDB_DATA, void *);
+int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *private_data);
+
+int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p);
+int ctdb_dump_db(struct ctdb_db_context *ctdb_db, FILE *f);
+
+/*
+  get the pid of a ctdb daemon
+ */
+int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *pid);
+
+int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout,
+			uint32_t destnode);
+int ctdb_ctrl_freeze_priority(struct ctdb_context *ctdb, struct timeval timeout,
+			      uint32_t destnode, uint32_t priority);
+
+struct ctdb_client_control_state *
+ctdb_ctrl_freeze_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+		      struct timeval timeout, uint32_t destnode,
+		      uint32_t priority);
+
+int ctdb_ctrl_freeze_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+			struct ctdb_client_control_state *state);
+
+int ctdb_ctrl_thaw_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t priority);
+int ctdb_ctrl_thaw(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_getpnn(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_get_tunable(struct ctdb_context *ctdb,
+			  struct timeval timeout,
+			  uint32_t destnode,
+			  const char *name, uint32_t *value);
+
+int ctdb_ctrl_set_tunable(struct ctdb_context *ctdb,
+			  struct timeval timeout,
+			  uint32_t destnode,
+			  const char *name, uint32_t value);
+
+int ctdb_ctrl_list_tunables(struct ctdb_context *ctdb,
+			    struct timeval timeout,
+			    uint32_t destnode,
+			    TALLOC_CTX *mem_ctx,
+			    const char ***list, uint32_t *count);
+
+int ctdb_ctrl_modflags(struct ctdb_context *ctdb,
+		       struct timeval timeout,
+		       uint32_t destnode,
+		       uint32_t set, uint32_t clear);
+
+enum ctdb_server_id_type {
+	SERVER_TYPE_SAMBA=1,
+	SERVER_TYPE_NFSD=2,
+	SERVER_TYPE_ISCSID=3
+};
+
+struct ctdb_server_id {
+	enum ctdb_server_id_type type;
+	uint32_t pnn;
+	uint32_t server_id;
+};
+
+struct ctdb_server_id_list {
+	uint32_t num;
+	struct ctdb_server_id server_ids[1];
+};
+
+
+int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb,
+		struct timeval timeout,
+		struct ctdb_server_id *id);
+int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb,
+		struct timeval timeout,
+		struct ctdb_server_id *id);
+int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb,
+		struct timeval timeout, uint32_t destnode,
+		struct ctdb_server_id *id, uint32_t *status);
+int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb,
+		TALLOC_CTX *mem_ctx,
+		struct timeval timeout, uint32_t destnode,
+		struct ctdb_server_id_list **svid_list);
+
+struct ctdb_uptime {
+	struct timeval current_time;
+	struct timeval ctdbd_start_time;
+	struct timeval last_recovery_started;
+	struct timeval last_recovery_finished;
+};
+
+/*
+  struct for tcp_client control
+  this is an ipv4 only version of this structure used by samba
+  samba will later be migrated over to use the
+  ctdb_control_tcp_addr structure instead
+ */
+struct ctdb_control_tcp {
+	struct sockaddr_in src; // samba uses this
+	struct sockaddr_in dest;// samba uses this
+};
+/* new style structure */
+struct ctdb_control_tcp_addr {
+	ctdb_sock_addr src;
+	ctdb_sock_addr dest;
+};
+
+int ctdb_socket_connect(struct ctdb_context *ctdb);
+
+/*
+  get the uptime of a remote node
+ */
+int ctdb_ctrl_uptime(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_uptime **uptime);
+
+struct ctdb_client_control_state *ctdb_ctrl_uptime_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_uptime_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, struct ctdb_uptime **uptime);
+
+int ctdb_ctrl_end_recovery(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_getreclock(struct ctdb_context *ctdb,
+	struct timeval timeout, uint32_t destnode,
+	TALLOC_CTX *mem_ctx, const char **reclock);
+int ctdb_ctrl_setreclock(struct ctdb_context *ctdb,
+	struct timeval timeout, uint32_t destnode,
+	const char *reclock);
+
+
+uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb,
+				struct ctdb_node_map *node_map,
+				TALLOC_CTX *mem_ctx,
+				bool include_self);
+uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
+				struct ctdb_node_map *node_map,
+				TALLOC_CTX *mem_ctx,
+				bool include_self);
+uint32_t *list_of_vnnmap_nodes(struct ctdb_context *ctdb,
+				struct ctdb_vnn_map *vnn_map,
+				TALLOC_CTX *mem_ctx,
+				bool include_self);
+uint32_t *list_of_active_nodes_except_pnn(struct ctdb_context *ctdb,
+				struct ctdb_node_map *node_map,
+				TALLOC_CTX *mem_ctx,
+				uint32_t pnn);
+
+int ctdb_read_pnn_lock(int fd, int32_t pnn);
+
+/*
+  get capabilities of a remote node
+ */
+int ctdb_ctrl_getcapabilities(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *capabilities);
+
+struct ctdb_client_control_state *ctdb_ctrl_getcapabilities_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_getcapabilities_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *capabilities);
+
+
+int32_t ctdb_ctrl_transaction_active(struct ctdb_context *ctdb,
+				     uint32_t destnode,
+				     uint32_t db_id);
+
+struct ctdb_marshall_buffer *ctdb_marshall_add(TALLOC_CTX *mem_ctx,
+					       struct ctdb_marshall_buffer *m,
+					       uint64_t db_id,
+					       uint32_t reqid,
+					       TDB_DATA key,
+					       struct ctdb_ltdb_header *header,
+					       TDB_DATA data);
+TDB_DATA ctdb_marshall_finish(struct ctdb_marshall_buffer *m);
+
+struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *ctdb_db,
+						       TALLOC_CTX *mem_ctx);
+int ctdb_transaction_fetch(struct ctdb_transaction_handle *h,
+			   TALLOC_CTX *mem_ctx,
+			   TDB_DATA key, TDB_DATA *data);
+int ctdb_transaction_store(struct ctdb_transaction_handle *h,
+			   TDB_DATA key, TDB_DATA data);
+int ctdb_transaction_commit(struct ctdb_transaction_handle *h);
+
+int ctdb_ctrl_recd_ping(struct ctdb_context *ctdb);
+
+int switch_from_server_to_client(struct ctdb_context *ctdb, const char *fmt,
+				 ...);
+
+int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb,
+		    struct timeval timeout, uint32_t destnode,
+		    TALLOC_CTX *mem_ctx, enum ctdb_eventscript_call type,
+		    struct ctdb_scripts_wire **script_status);
+
+
+struct debug_levels {
+	int32_t	level;
+	const char *description;
+};
+extern struct debug_levels debug_levels[];
+
+const char *get_debug_by_level(int32_t level);
+int32_t get_debug_by_desc(const char *desc);
+
+int ctdb_ctrl_stop_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+int ctdb_ctrl_continue_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode);
+
+int ctdb_ctrl_setnatgwstate(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t natgwstate);
+int ctdb_ctrl_setlmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t lmasterrole);
+int ctdb_ctrl_setrecmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmasterrole);
+
+int ctdb_ctrl_enablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script);
+int ctdb_ctrl_disablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script);
+
+struct ctdb_ban_time {
+	uint32_t pnn;
+	uint32_t time;
+};
+
+int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_ban_time *bantime);
+int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_ban_time **bantime);
+
+struct ctdb_db_priority {
+	uint32_t db_id;
+	uint32_t priority;
+};
+
+int ctdb_ctrl_set_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_db_priority *db_prio);
+int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t db_id, uint32_t *priority);
+
+int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_statistics_wire **stats);
+
+
+
+struct ctdb_client_control_state *
+ctdb_ctrl_updaterecord_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data);
+
+int ctdb_ctrl_updaterecord_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state);
+
+int
+ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data);
+
+
+struct ctdb_client_control_state *
+ctdb_ctrl_set_db_readonly_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid);
+int ctdb_ctrl_set_db_readonly_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state);
+int ctdb_ctrl_set_db_readonly(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid);
+
+#endif /* _CTDB_CLIENT_H */

Added: branches/ctdb/squeeze-backports/include/ctdb_private.h
===================================================================
--- branches/ctdb/squeeze-backports/include/ctdb_private.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/include/ctdb_private.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1471 @@
+/* 
+   ctdb database library
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CTDB_PRIVATE_H
+#define _CTDB_PRIVATE_H
+
+#include "ctdb_client.h"
+#include <sys/socket.h>
+
+/*
+  recovery daemon memdump reply address
+ */
+struct rd_memdump_reply {
+	uint32_t pnn;
+	uint64_t srvid;
+};
+
+/*
+  description for a TAKEOVER_RUN message reply address
+ */
+struct takeover_run_reply {
+	uint32_t pnn;
+	uint64_t srvid;
+};
+
+/*
+ * pid of the ctdbd daemon
+ */
+extern pid_t ctdbd_pid;
+
+/*
+  a tcp connection description
+  also used by tcp_add and tcp_remove controls
+ */
+struct ctdb_tcp_connection {
+	ctdb_sock_addr src_addr;
+	ctdb_sock_addr dst_addr;
+};
+
+/* the wire representation for a tcp tickle array */
+struct ctdb_tcp_wire_array {
+	uint32_t num;
+	struct ctdb_tcp_connection connections[1];
+};	
+
+/* the list of tcp tickles used by get/set tcp tickle list */
+struct ctdb_control_tcp_tickle_list {
+	ctdb_sock_addr addr;
+	struct ctdb_tcp_wire_array tickles;
+};
+
+/*
+  array of tcp connections
+ */
+struct ctdb_tcp_array {
+	uint32_t num;
+	struct ctdb_tcp_connection *connections;
+};	
+
+
+/* all tunable variables go in here */
+struct ctdb_tunable {
+	uint32_t max_redirect_count;
+	uint32_t seqnum_interval; /* unit is ms */
+	uint32_t control_timeout;
+	uint32_t traverse_timeout;
+	uint32_t keepalive_interval;
+	uint32_t keepalive_limit;
+	uint32_t recover_timeout;
+	uint32_t recover_interval;
+	uint32_t election_timeout;
+	uint32_t takeover_timeout;
+	uint32_t monitor_interval;
+	uint32_t tickle_update_interval;
+	uint32_t script_timeout;
+	uint32_t script_timeout_count; /* allow dodgy scripts to hang this many times in a row before we mark the node unhealthy */
+	uint32_t script_unhealthy_on_timeout; /* obsolete */
+	uint32_t recovery_grace_period;
+	uint32_t recovery_ban_period;
+	uint32_t database_hash_size;
+	uint32_t database_max_dead;
+	uint32_t rerecovery_timeout;
+	uint32_t enable_bans;
+	uint32_t deterministic_public_ips;
+	uint32_t reclock_ping_period;
+	uint32_t no_ip_failback;
+	uint32_t disable_ip_failover;
+	uint32_t verbose_memory_names;
+	uint32_t recd_ping_timeout;
+	uint32_t recd_ping_failcount;
+	uint32_t log_latency_ms;
+	uint32_t reclock_latency_ms;
+	uint32_t recovery_drop_all_ips;
+	uint32_t verify_recovery_lock;
+	uint32_t vacuum_default_interval;
+	uint32_t vacuum_max_run_time;
+	uint32_t repack_limit;
+	uint32_t vacuum_limit;
+	uint32_t vacuum_min_interval;
+	uint32_t vacuum_max_interval;
+	uint32_t max_queue_depth_drop_msg;
+	uint32_t use_status_events_for_monitoring;
+	uint32_t allow_unhealthy_db_read;
+	uint32_t stat_history_interval;
+	uint32_t deferred_attach_timeout;
+	uint32_t vacuum_fast_path_count;
+	uint32_t lcp2_public_ip_assignment;
+	uint32_t allow_client_db_attach;
+};
+
+/*
+  an installed ctdb remote call
+*/
+struct ctdb_registered_call {
+	struct ctdb_registered_call *next, *prev;
+	uint32_t id;
+	ctdb_fn_t fn;
+};
+
+/*
+  this address structure might need to be generalised later for some
+  transports
+*/
+struct ctdb_address {
+	const char *address;
+	int port;
+};
+
+/*
+  check that a pnn is valid
+ */
+#define ctdb_validate_pnn(ctdb, pnn) (((uint32_t)(pnn)) < (ctdb)->num_nodes)
+
+
+/* called from the queue code when a packet comes in. Called with data==NULL
+   on error */
+typedef void (*ctdb_queue_cb_fn_t)(uint8_t *data, size_t length,
+				   void *private_data);
+
+/* used for callbacks in ctdb_control requests */
+typedef void (*ctdb_control_callback_fn_t)(struct ctdb_context *,
+					   int32_t status, TDB_DATA data, 
+					   const char *errormsg,
+					   void *private_data);
+/*
+  structure describing a connected client in the daemon
+ */
+struct ctdb_client {
+	struct ctdb_context *ctdb;
+	int fd;
+	struct ctdb_queue *queue;
+	uint32_t client_id;
+	pid_t pid;
+	struct ctdb_tcp_list *tcp_list;
+	uint32_t db_id;
+	uint32_t num_persistent_updates;
+	struct ctdb_client_notify_list *notify;
+};
+
+struct ctdb_iface;
+
+/* state associated with a public ip address */
+struct ctdb_vnn {
+	struct ctdb_vnn *prev, *next;
+
+	struct ctdb_iface *iface;
+	const char **ifaces;
+	ctdb_sock_addr public_address;
+	uint8_t public_netmask_bits;
+
+	/* the node number that is serving this public address, if any. 
+	   If no node serves this ip it is set to -1 */
+	int32_t pnn;
+
+	/* List of clients to tickle for this public address */
+	struct ctdb_tcp_array *tcp_array;
+
+	/* whether we need to update the other nodes with changes to our list
+	   of connected clients */
+	bool tcp_update_needed;
+
+	/* a context to hang sending gratious arp events off */
+	TALLOC_CTX *takeover_ctx;
+
+	struct ctdb_kill_tcp *killtcp;
+};
+
+/*
+  state associated with one node
+*/
+struct ctdb_node {
+	struct ctdb_context *ctdb;
+	struct ctdb_address address;
+	const char *name; /* for debug messages */
+	void *private_data; /* private to transport */
+	uint32_t pnn;
+	uint32_t flags;
+
+	/* used by the dead node monitoring */
+	uint32_t dead_count;
+	uint32_t rx_cnt;
+	uint32_t tx_cnt;
+
+	/* used to track node capabilities, is only valid/tracked inside the
+	   recovery daemon.
+	*/
+	uint32_t capabilities;
+
+	/* a list of controls pending to this node, so we can time them out quickly
+	   if the node becomes disconnected */
+	struct daemon_control_state *pending_controls;
+
+	/* used by the recovery daemon when distributing ip addresses 
+	   across the nodes.  it needs to know which public ip's can be handled
+	   by each node.
+	*/
+	struct ctdb_all_public_ips *known_public_ips;
+	struct ctdb_all_public_ips *available_public_ips;
+	/* used by the recovery dameon to track when a node should be banned */
+	struct ctdb_banning_state *ban_state; 
+};
+
+/*
+  transport specific methods
+*/
+struct ctdb_methods {
+	int (*initialise)(struct ctdb_context *); /* initialise transport structures */	
+	int (*start)(struct ctdb_context *); /* start the transport */
+	int (*add_node)(struct ctdb_node *); /* setup a new node */	
+	int (*connect_node)(struct ctdb_node *); /* connect to node */
+	int (*queue_pkt)(struct ctdb_node *, uint8_t *data, uint32_t length);
+	void *(*allocate_pkt)(TALLOC_CTX *mem_ctx, size_t );
+	void (*shutdown)(struct ctdb_context *); /* shutdown transport */
+	void (*restart)(struct ctdb_node *); /* stop and restart the connection */
+};
+
+/*
+  transport calls up to the ctdb layer
+*/
+struct ctdb_upcalls {
+	/* recv_pkt is called when a packet comes in */
+	void (*recv_pkt)(struct ctdb_context *, uint8_t *data, uint32_t length);
+
+	/* node_dead is called when an attempt to send to a node fails */
+	void (*node_dead)(struct ctdb_node *);
+
+	/* node_connected is called when a connection to a node is established */
+	void (*node_connected)(struct ctdb_node *);
+};
+
+/* list of message handlers - needs to be changed to a more efficient data
+   structure so we can find a message handler given a srvid quickly */
+struct ctdb_message_list {
+	struct ctdb_context *ctdb;
+	struct ctdb_message_list *next, *prev;
+	uint64_t srvid;
+	ctdb_msg_fn_t message_handler;
+	void *message_private;
+};
+
+/* additional data required for the daemon mode */
+struct ctdb_daemon_data {
+	int sd;
+	char *name;
+	struct ctdb_queue *queue;
+};
+
+
+#define CTDB_UPDATE_STAT(ctdb, counter, value) \
+	{										\
+		if (value > ctdb->statistics.counter) {					\
+			ctdb->statistics.counter = c->hopcount;				\
+		}									\
+		if (value > ctdb->statistics_current.counter) {				\
+			ctdb->statistics_current.counter = c->hopcount;			\
+		}									\
+	}
+
+#define CTDB_INCREMENT_STAT(ctdb, counter) \
+	{										\
+		ctdb->statistics.counter++;						\
+		ctdb->statistics_current.counter++;					\
+	}
+
+#define CTDB_DECREMENT_STAT(ctdb, counter) \
+	{										\
+		if (ctdb->statistics.counter > 0)					\
+			ctdb->statistics.counter--;					\
+		if (ctdb->statistics_current.counter > 0)				\
+			ctdb->statistics_current.counter--;				\
+	}
+
+#define CTDB_UPDATE_RECLOCK_LATENCY(ctdb, name, counter, value) \
+	{										\
+		if (value > ctdb->statistics.counter.max)					\
+			ctdb->statistics.counter.max = value;				\
+		if (value > ctdb->statistics_current.counter.max)				\
+			ctdb->statistics_current.counter.max = value;			\
+											\
+		if (ctdb->statistics.counter.num == 0 || value < ctdb->statistics.counter.min)	\
+			ctdb->statistics.counter.min = value;				\
+		if (ctdb->statistics_current.counter.num == 0 || value < ctdb->statistics_current.counter.min)	\
+			ctdb->statistics_current.counter.min = value;			\
+											\
+		ctdb->statistics.counter.total += value;					\
+		ctdb->statistics_current.counter.total += value;				\
+											\
+		ctdb->statistics.counter.num++;						\
+		ctdb->statistics_current.counter.num++;					\
+											\
+		if (ctdb->tunable.reclock_latency_ms != 0) {				\
+			if (value*1000 > ctdb->tunable.reclock_latency_ms) {		\
+				DEBUG(DEBUG_ERR, ("High RECLOCK latency %fs for operation %s\n", value, name));	\
+			}								\
+		}									\
+	}
+
+
+#define CTDB_UPDATE_LATENCY(ctdb, db, operation, counter, t) \
+	{										\
+		double l = timeval_elapsed(&t);						\
+											\
+		if (l > ctdb->statistics.counter.max)					\
+			ctdb->statistics.counter.max = l;				\
+		if (l > ctdb->statistics_current.counter.max)				\
+			ctdb->statistics_current.counter.max = l;			\
+											\
+		if (ctdb->statistics.counter.num == 0 || l < ctdb->statistics.counter.min)	\
+			ctdb->statistics.counter.min = l;				\
+		if (ctdb->statistics_current.counter.num == 0 || l < ctdb->statistics_current.counter.min)	\
+			ctdb->statistics_current.counter.min = l;			\
+											\
+		ctdb->statistics.counter.total += l;					\
+		ctdb->statistics_current.counter.total += l;				\
+											\
+		ctdb->statistics.counter.num++;						\
+		ctdb->statistics_current.counter.num++;					\
+											\
+		if (ctdb->tunable.log_latency_ms !=0) {					\
+			if (l*1000 > ctdb->tunable.log_latency_ms) {			\
+				DEBUG(DEBUG_WARNING, ("High latency %.6fs for operation %s on database %s\n", l, operation, db->db_name));\
+			}								\
+		}									\
+	}
+
+
+
+
+
+#define INVALID_GENERATION 1
+/* table that contains the mapping between a hash value and lmaster
+ */
+struct ctdb_vnn_map {
+	uint32_t generation;
+	uint32_t size;
+	uint32_t *map;
+};
+
+/* 
+   a wire representation of the vnn map
+ */
+struct ctdb_vnn_map_wire {
+	uint32_t generation;
+	uint32_t size;
+	uint32_t map[1];
+};
+
+/* a structure that contains the elements required for the write record
+   control
+*/
+struct ctdb_write_record {
+	uint32_t dbid;
+	uint32_t keylen;
+	uint32_t datalen;
+	unsigned char blob[1];
+};
+
+enum ctdb_freeze_mode {CTDB_FREEZE_NONE, CTDB_FREEZE_PENDING, CTDB_FREEZE_FROZEN};
+
+#define CTDB_MONITORING_ACTIVE		0
+#define CTDB_MONITORING_DISABLED	1
+
+/* The different capabilities of the ctdb daemon. */
+#define CTDB_CAP_RECMASTER		0x00000001
+#define CTDB_CAP_LMASTER		0x00000002
+/* This capability is set if CTDB_LVS_PUBLIC_IP is set */
+#define CTDB_CAP_LVS			0x00000004
+/* This capability is set if NATGW is enabled */
+#define CTDB_CAP_NATGW			0x00000008
+
+#define NUM_DB_PRIORITIES 3
+/* main state of the ctdb daemon */
+struct ctdb_context {
+	struct tevent_context *ev;
+	struct timeval ctdbd_start_time;
+	struct timeval last_recovery_started;
+	struct timeval last_recovery_finished;
+	uint32_t recovery_mode;
+	TALLOC_CTX *tickle_update_context;
+	TALLOC_CTX *keepalive_ctx;
+	TALLOC_CTX *check_public_ifaces_ctx;
+	struct ctdb_tunable tunable;
+	enum ctdb_freeze_mode freeze_mode[NUM_DB_PRIORITIES+1];
+	struct ctdb_freeze_handle *freeze_handles[NUM_DB_PRIORITIES+1];
+	bool freeze_transaction_started;
+	uint32_t freeze_transaction_id;
+	struct ctdb_address address;
+	const char *name;
+	const char *db_directory;
+	const char *db_directory_persistent;
+	const char *db_directory_state;
+	struct tdb_wrap *db_persistent_health;
+	uint32_t db_persistent_startup_generation;
+	uint64_t db_persistent_check_errors;
+	uint64_t max_persistent_check_errors;
+	const char *transport;
+	char *recovery_lock_file;
+	int recovery_lock_fd;
+	uint32_t pnn; /* our own pnn */
+	uint32_t num_nodes;
+	uint32_t num_connected;
+	unsigned flags;
+	uint32_t capabilities;
+	struct idr_context *idr;
+	int lastid;
+	struct ctdb_node **nodes; /* array of nodes in the cluster - indexed by vnn */
+	struct ctdb_vnn *vnn; /* list of public ip addresses and interfaces */
+	struct ctdb_vnn *single_ip_vnn; /* a structure for the single ip */
+	struct ctdb_iface *ifaces; /* list of local interfaces */
+	char *err_msg;
+	const struct ctdb_methods *methods; /* transport methods */
+	const struct ctdb_upcalls *upcalls; /* transport upcalls */
+	void *private_data; /* private to transport */
+	struct ctdb_db_context *db_list;
+	struct ctdb_message_list *message_list;
+	struct ctdb_daemon_data daemon;
+	struct ctdb_statistics statistics;
+	struct ctdb_statistics statistics_current;
+#define MAX_STAT_HISTORY 100
+	struct ctdb_statistics statistics_history[MAX_STAT_HISTORY];
+	struct ctdb_vnn_map *vnn_map;
+	uint32_t num_clients;
+	uint32_t recovery_master;
+	struct ctdb_call_state *pending_calls;
+	struct ctdb_client_ip *client_ip_list;
+	struct trbt_tree *server_ids; 
+	bool do_setsched;
+	void *saved_scheduler_param;
+	const char *event_script_dir;
+	const char *notification_script;
+	const char *default_public_interface;
+	pid_t ctdbd_pid;
+	pid_t recoverd_pid;
+	pid_t syslogd_pid;
+	bool done_startup;
+	const char *node_ip;
+	struct ctdb_monitor_state *monitor;
+	struct ctdb_log_state *log;
+	int start_as_disabled;
+	int start_as_stopped;
+	bool valgrinding;
+	uint32_t event_script_timeouts; /* counting how many consecutive times an eventscript has timedout */
+	uint32_t *recd_ping_count;
+	TALLOC_CTX *release_ips_ctx; /* a context used to automatically drop all IPs if we fail to recover the node */
+
+	TALLOC_CTX *event_script_ctx;
+
+	struct ctdb_event_script_state *current_monitor;
+	struct ctdb_scripts_wire *last_status[CTDB_EVENT_MAX];
+
+	TALLOC_CTX *banning_ctx;
+
+	struct ctdb_vacuum_child_context *vacuumers;
+
+	/* mapping from pid to ctdb_client * */
+	struct ctdb_client_pid_list *client_pids;
+
+	/* used in the recovery daemon to remember the ip allocation */
+	struct trbt_tree *ip_tree;
+
+	/* Used to defer db attach requests while in recovery mode */
+	struct ctdb_deferred_attach_context *deferred_attach;
+};
+
+struct ctdb_db_context {
+	struct ctdb_db_context *next, *prev;
+	struct ctdb_context *ctdb;
+	uint32_t db_id;
+	uint32_t priority;
+	bool persistent;
+	bool readonly; /* Do we support read-only delegations ? */
+	const char *db_name;
+	const char *db_path;
+	struct tdb_wrap *ltdb;
+	struct tdb_context *rottdb; /* ReadOnly tracking TDB */
+	struct ctdb_registered_call *calls; /* list of registered calls */
+	uint32_t seqnum;
+	struct timed_event *seqnum_update;
+	struct ctdb_traverse_local_handle *traverse;
+	bool transaction_active;
+	struct ctdb_vacuum_handle *vacuum_handle;
+	char *unhealthy_reason;
+	int pending_requests;
+	struct lockwait_handle *lockwait_active;
+	struct lockwait_handle *lockwait_overflow;
+	struct revokechild_handle *revokechild_active;
+	struct ctdb_persistent_state *persistent_state;
+	struct trbt_tree *delete_queue;
+	int (*ctdb_ltdb_store_fn)(struct ctdb_db_context *ctdb_db,
+				  TDB_DATA key,
+				  struct ctdb_ltdb_header *header,
+				  TDB_DATA data);
+
+};
+
+
+#define CTDB_NO_MEMORY(ctdb, p) do { if (!(p)) { \
+          DEBUG(0,("Out of memory for %s at %s\n", #p, __location__)); \
+          ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \
+	  return -1; }} while (0)
+
+#define CTDB_NO_MEMORY_VOID(ctdb, p) do { if (!(p)) { \
+          DEBUG(0,("Out of memory for %s at %s\n", #p, __location__)); \
+          ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \
+	  return; }} while (0)
+
+#define CTDB_NO_MEMORY_NULL(ctdb, p) do { if (!(p)) { \
+          DEBUG(0,("Out of memory for %s at %s\n", #p, __location__)); \
+          ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \
+	  return NULL; }} while (0)
+
+#define CTDB_NO_MEMORY_FATAL(ctdb, p) do { if (!(p)) { \
+          DEBUG(0,("Out of memory for %s at %s\n", #p, __location__)); \
+          ctdb_fatal(ctdb, "Out of memory in " __location__ ); \
+	  }} while (0)
+
+/*
+  structure passed in set_call control
+ */
+struct ctdb_control_set_call {
+	uint32_t db_id;
+	ctdb_fn_t fn;
+	uint32_t id;
+};
+
+/*
+  struct for kill_tcp control
+ */
+struct ctdb_control_killtcp {
+	ctdb_sock_addr src_addr;
+	ctdb_sock_addr dst_addr;
+};
+
+/*
+  struct holding a ctdb_sock_addr and an interface name,
+  used to add/remove public addresses
+ */
+struct ctdb_control_ip_iface {
+	ctdb_sock_addr addr;
+	uint32_t mask;
+	uint32_t len;
+	char iface[1];
+};
+
+/*
+  struct holding a ctdb_sock_addr and an interface name,
+  used for send_gratious_arp
+ */
+struct ctdb_control_gratious_arp {
+	ctdb_sock_addr addr;
+	uint32_t mask;
+	uint32_t len;
+	char iface[1];
+};
+
+/*
+  persistent store control - update this record on all other nodes
+ */
+struct ctdb_control_persistent_store {
+	uint32_t db_id;
+	uint32_t len;
+	uint8_t  data[1];
+};
+
+/*
+  structure used for CTDB_SRVID_NODE_FLAGS_CHANGED
+ */
+struct ctdb_node_flag_change {
+	uint32_t pnn;
+	uint32_t new_flags;
+	uint32_t old_flags;
+};
+
+/*
+  struct for admin setting a ban
+ */
+struct ctdb_ban_info {
+	uint32_t pnn;
+	uint32_t ban_time;
+};
+
+enum call_state {CTDB_CALL_WAIT, CTDB_CALL_DONE, CTDB_CALL_ERROR};
+
+#define CTDB_LMASTER_ANY	0xffffffff
+
+/*
+  state of a in-progress ctdb call
+*/
+struct ctdb_call_state {
+	struct ctdb_call_state *next, *prev;
+	enum call_state state;
+	uint32_t reqid;
+	struct ctdb_req_call *c;
+	struct ctdb_db_context *ctdb_db;
+	const char *errmsg;
+	struct ctdb_call *call;
+	uint32_t generation;
+	struct {
+		void (*fn)(struct ctdb_call_state *);
+		void *private_data;
+	} async;
+};
+
+
+/* used for fetch_lock */
+struct ctdb_fetch_handle {
+	struct ctdb_db_context *ctdb_db;
+	TDB_DATA key;
+	TDB_DATA *data;
+	struct ctdb_ltdb_header header;
+};
+
+/* internal prototypes */
+void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void ctdb_fatal(struct ctdb_context *ctdb, const char *msg);
+bool ctdb_same_address(struct ctdb_address *a1, struct ctdb_address *a2);
+int ctdb_parse_address(struct ctdb_context *ctdb,
+		       TALLOC_CTX *mem_ctx, const char *str,
+		       struct ctdb_address *address);
+bool ctdb_same_ip(const ctdb_sock_addr *ip1, const ctdb_sock_addr *ip2);
+bool ctdb_same_sockaddr(const ctdb_sock_addr *ip1, const ctdb_sock_addr *ip2);
+uint32_t ctdb_hash(const TDB_DATA *key);
+uint32_t ctdb_hash_string(const char *str);
+void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_request_message(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+
+uint32_t ctdb_lmaster(struct ctdb_context *ctdb, const TDB_DATA *key);
+int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db, 
+		    TDB_DATA key, struct ctdb_ltdb_header *header, 
+		    TALLOC_CTX *mem_ctx, TDB_DATA *data);
+int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, 
+		    struct ctdb_ltdb_header *header, TDB_DATA data);
+int ctdb_ltdb_delete(struct ctdb_db_context *ctdb_db, TDB_DATA key);
+int ctdb_ltdb_fetch_with_header(struct ctdb_db_context *ctdb_db, 
+		    TDB_DATA key, struct ctdb_ltdb_header *header, 
+		    TALLOC_CTX *mem_ctx, TDB_DATA *data);
+int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb, 
+			struct ctdb_req_control *c,
+			TDB_DATA recdata);
+int32_t ctdb_control_cancel_persistent_update(struct ctdb_context *ctdb, 
+			struct ctdb_req_control *c,
+			TDB_DATA recdata);
+void ctdb_queue_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_queue_packet_opcode(struct ctdb_context *ctdb, struct ctdb_req_header *hdr, unsigned opcode);
+int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db, 
+			   TDB_DATA key, struct ctdb_req_header *hdr,
+			   void (*recv_pkt)(void *, struct ctdb_req_header *),
+			   void *recv_context, bool ignore_generation);
+int ctdb_ltdb_lock_fetch_requeue(struct ctdb_db_context *ctdb_db, 
+				 TDB_DATA key, struct ctdb_ltdb_header *header, 
+				 struct ctdb_req_header *hdr, TDB_DATA *data,
+				 void (*recv_pkt)(void *, struct ctdb_req_header *),
+				 void *recv_context, bool ignore_generation);
+void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *);
+
+struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db, 
+					     struct ctdb_call *call,
+					     struct ctdb_ltdb_header *header,
+					     TDB_DATA *data);
+
+
+int ctdbd_start(struct ctdb_context *ctdb);
+struct ctdb_call_state *ctdbd_call_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call);
+int ctdbd_call_recv(struct ctdb_call_state *state, struct ctdb_call *call);
+
+/*
+  queue a packet for sending
+*/
+int ctdb_queue_send(struct ctdb_queue *queue, uint8_t *data, uint32_t length);
+
+/*
+  setup the fd used by the queue
+ */
+int ctdb_queue_set_fd(struct ctdb_queue *queue, int fd);
+
+/*
+  setup a packet queue on a socket
+ */
+struct ctdb_queue *ctdb_queue_setup(struct ctdb_context *ctdb,
+				    TALLOC_CTX *mem_ctx, int fd, int alignment,
+				    
+				    ctdb_queue_cb_fn_t callback,
+				    void *private_data, const char *fmt, ...)
+	PRINTF_ATTRIBUTE(7,8);
+
+/*
+  allocate a packet for use in client<->daemon communication
+ */
+struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb,
+					    TALLOC_CTX *mem_ctx, 
+					    enum ctdb_operation operation, 
+					    size_t length, size_t slength,
+					    const char *type);
+#define ctdbd_allocate_pkt(ctdb, mem_ctx, operation, length, type) \
+	(type *)_ctdbd_allocate_pkt(ctdb, mem_ctx, operation, length, sizeof(type), #type)
+
+struct ctdb_req_header *_ctdb_transport_allocate(struct ctdb_context *ctdb,
+						 TALLOC_CTX *mem_ctx, 
+						 enum ctdb_operation operation, 
+						 size_t length, size_t slength,
+						 const char *type);
+#define ctdb_transport_allocate(ctdb, mem_ctx, operation, length, type) \
+	(type *)_ctdb_transport_allocate(ctdb, mem_ctx, operation, length, sizeof(type), #type)
+
+int ctdb_queue_length(struct ctdb_queue *queue);
+
+/*
+  lock a record in the ltdb, given a key
+ */
+int ctdb_ltdb_lock(struct ctdb_db_context *ctdb_db, TDB_DATA key);
+
+/*
+  unlock a record in the ltdb, given a key
+ */
+int ctdb_ltdb_unlock(struct ctdb_db_context *ctdb_db, TDB_DATA key);
+
+
+/*
+  make a ctdb call to the local daemon - async send. Called from client context.
+
+  This constructs a ctdb_call request and queues it for processing. 
+  This call never blocks.
+*/
+struct ctdb_call_state *ctdb_client_call_send(struct ctdb_db_context *ctdb_db, 
+					      struct ctdb_call *call);
+
+/*
+  make a recv call to the local ctdb daemon - called from client context
+
+  This is called when the program wants to wait for a ctdb_call to complete and get the 
+  results. This call will block unless the call has already completed.
+*/
+int ctdb_client_call_recv(struct ctdb_call_state *state, struct ctdb_call *call);
+
+int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t vnn,
+			     uint64_t srvid, TDB_DATA data);
+
+/*
+  send a ctdb message
+*/
+int ctdb_daemon_send_message(struct ctdb_context *ctdb, uint32_t pnn,
+			     uint64_t srvid, TDB_DATA data);
+
+
+struct lockwait_handle *ctdb_lockwait(struct ctdb_db_context *ctdb_db,
+				      TDB_DATA key,
+				      void (*callback)(void *), void *private_data);
+
+struct ctdb_call_state *ctdb_daemon_call_send(struct ctdb_db_context *ctdb_db, 
+					      struct ctdb_call *call);
+
+int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call);
+
+struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctdb_db, 
+						     struct ctdb_call *call, 
+						     struct ctdb_ltdb_header *header);
+
+int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call,
+		    struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx,
+		    TDB_DATA *data, bool updatetdb);
+
+#define ctdb_reqid_find(ctdb, reqid, type)	(type *)_ctdb_reqid_find(ctdb, reqid, #type, __location__)
+
+void ctdb_recv_raw_pkt(void *p, uint8_t *data, uint32_t length);
+
+int ctdb_socket_connect(struct ctdb_context *ctdb);
+void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args);
+
+#define CTDB_BAD_REQID ((uint32_t)-1)
+uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state);
+void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location);
+void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid);
+
+void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+
+int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
+			     uint64_t srvid, uint32_t opcode, uint32_t client_id, uint32_t flags,
+			     TDB_DATA data,
+			     ctdb_control_callback_fn_t callback,
+			     void *private_data);
+
+int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata, 
+			       TDB_DATA *outdata, uint64_t tdb_flags,
+			       bool persistent, uint32_t client_id,
+			       struct ctdb_req_control *c,
+			       bool *async_reply);
+
+int ctdb_daemon_set_call(struct ctdb_context *ctdb, uint32_t db_id,
+			 ctdb_fn_t fn, int id);
+
+int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, 
+		 uint32_t opcode, uint32_t flags, TDB_DATA data, 
+		 TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
+		 struct timeval *timeout, char **errormsg);
+int ctdb_control_recv(struct ctdb_context *ctdb, 
+		struct ctdb_client_control_state *state, 
+		TALLOC_CTX *mem_ctx,
+		TDB_DATA *outdata, int32_t *status, char **errormsg);
+
+struct ctdb_client_control_state *
+ctdb_control_send(struct ctdb_context *ctdb, 
+		uint32_t destnode, uint64_t srvid, 
+		uint32_t opcode, uint32_t flags, TDB_DATA data, 
+		TALLOC_CTX *mem_ctx,
+		struct timeval *timeout,
+		char **errormsg);
+
+
+
+
+#define CHECK_CONTROL_DATA_SIZE(size) do { \
+ if (indata.dsize != size) { \
+	 DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected %u\n", \
+		  opcode, (unsigned)indata.dsize, (unsigned)size));	\
+	 return -1; \
+ } \
+ } while (0)
+
+#define CHECK_CONTROL_MIN_DATA_SIZE(size) do { \
+ if (indata.dsize < size) { \
+	 DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected >= %u\n", \
+		  opcode, (unsigned)indata.dsize, (unsigned)size));	\
+	 return -1; \
+ } \
+ } while (0)
+
+int ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
+int ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
+int ctdb_control_getdbmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
+int ctdb_control_getnodemapv4(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
+int ctdb_control_getnodemap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
+int ctdb_control_writerecord(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata);
+
+
+/* structure used for pulldb control */
+struct ctdb_control_pulldb {
+	uint32_t db_id;
+	uint32_t lmaster;
+};
+
+/* structure used for sending lists of records */
+struct ctdb_marshall_buffer {
+	uint32_t db_id;
+	uint32_t count;
+	uint8_t data[1];
+};
+
+/* set dmaster control structure */
+struct ctdb_control_set_dmaster {
+	uint32_t db_id;
+	uint32_t dmaster;
+};
+
+/*
+  structure for setting a tunable
+ */
+struct ctdb_control_set_tunable {
+	uint32_t value;
+	uint32_t length;
+	uint8_t  name[1];
+};
+
+/*
+  structure for getting a tunable
+ */
+struct ctdb_control_get_tunable {
+	uint32_t length;
+	uint8_t  name[1];
+};
+
+/*
+  structure for listing tunables
+ */
+struct ctdb_control_list_tunable {
+	uint32_t length;
+	/* returns a : separated list of tunable names */
+	uint8_t  data[1];
+};
+
+
+struct ctdb_node_and_flagsv4 {
+	uint32_t pnn;
+	uint32_t flags;
+	struct sockaddr_in sin;
+};
+
+struct ctdb_node_mapv4 {
+	uint32_t num;
+	struct ctdb_node_and_flagsv4 nodes[1];
+};
+
+struct ctdb_control_wipe_database {
+	uint32_t db_id;
+	uint32_t transaction_id;
+};
+
+/*
+  state of a in-progress ctdb call in client
+*/
+struct ctdb_client_call_state {
+	enum call_state state;
+	uint32_t reqid;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_call *call;
+	struct {
+		void (*fn)(struct ctdb_client_call_state *);
+		void *private_data;
+	} async;
+};
+
+
+int32_t ctdb_control_traverse_start(struct ctdb_context *ctdb, TDB_DATA indata, 
+				    TDB_DATA *outdata, uint32_t srcnode, uint32_t client_id);
+int32_t ctdb_control_traverse_all(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata);
+int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata);
+int32_t ctdb_control_traverse_kill(struct ctdb_context *ctdb, TDB_DATA indata, 
+				    TDB_DATA *outdata, uint32_t srcnode);
+
+int ctdb_dispatch_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data);
+
+int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid);
+int ctdb_deregister_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data);
+int daemon_deregister_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid);
+
+int32_t ctdb_ltdb_enable_seqnum(struct ctdb_context *ctdb, uint32_t db_id);
+int32_t ctdb_ltdb_update_seqnum(struct ctdb_context *ctdb, uint32_t db_id, uint32_t srcnode);
+
+struct ctdb_rec_data *ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid,	
+					   TDB_DATA key, struct ctdb_ltdb_header *, TDB_DATA data);
+
+struct ctdb_rec_data *ctdb_marshall_loop_next(struct ctdb_marshall_buffer *m, struct ctdb_rec_data *r,
+					      uint32_t *reqid,
+					      struct ctdb_ltdb_header *header,
+					      TDB_DATA *key, TDB_DATA *data);
+
+int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
+int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_set_dmaster(struct ctdb_context *ctdb, TDB_DATA indata);
+
+int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, 
+				 struct ctdb_req_control *c,
+				 TDB_DATA indata, bool *async_reply,
+				 const char **errormsg);
+void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c,
+				TDB_DATA *outdata, int32_t status, const char *errormsg);
+
+int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply);
+int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority);
+
+int ctdb_start_recoverd(struct ctdb_context *ctdb);
+void ctdb_stop_recoverd(struct ctdb_context *ctdb);
+
+uint32_t ctdb_get_num_active_nodes(struct ctdb_context *ctdb);
+
+void ctdb_disable_monitoring(struct ctdb_context *ctdb);
+void ctdb_enable_monitoring(struct ctdb_context *ctdb);
+void ctdb_stop_monitoring(struct ctdb_context *ctdb);
+void ctdb_start_monitoring(struct ctdb_context *ctdb);
+void ctdb_start_tcp_tickle_update(struct ctdb_context *ctdb);
+void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode);
+void ctdb_start_keepalive(struct ctdb_context *ctdb);
+void ctdb_stop_keepalive(struct ctdb_context *ctdb);
+int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA data, bool *async_reply);
+
+
+void ctdb_daemon_cancel_controls(struct ctdb_context *ctdb, struct ctdb_node *node);
+void ctdb_call_resend_all(struct ctdb_context *ctdb);
+void ctdb_node_dead(struct ctdb_node *node);
+void ctdb_node_connected(struct ctdb_node *node);
+bool ctdb_blocking_freeze(struct ctdb_context *ctdb);
+void ctdb_set_scheduler(struct ctdb_context *ctdb);
+void ctdb_restore_scheduler(struct ctdb_context *ctdb);
+pid_t ctdb_fork(struct ctdb_context *ctdb);
+int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb, 
+				 struct ctdb_req_control *c,
+				 TDB_DATA indata, 
+				 bool *async_reply);
+int32_t ctdb_control_takeover_ipv4(struct ctdb_context *ctdb, 
+				 struct ctdb_req_control *c,
+				 TDB_DATA indata, 
+				 bool *async_reply);
+int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, 
+				 struct ctdb_req_control *c,
+				 TDB_DATA indata, 
+				 bool *async_reply);
+int32_t ctdb_control_release_ipv4(struct ctdb_context *ctdb, 
+				 struct ctdb_req_control *c,
+				 TDB_DATA indata, 
+				 bool *async_reply);
+int32_t ctdb_control_start_recovery(struct ctdb_context *ctdb, 
+				 struct ctdb_req_control *c,
+				 bool *async_reply);
+int32_t ctdb_control_end_recovery(struct ctdb_context *ctdb, 
+				 struct ctdb_req_control *c,
+				 bool *async_reply);
+
+struct ctdb_public_ipv4 {
+	uint32_t pnn;
+	struct sockaddr_in sin;
+};
+
+int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout, 
+			  uint32_t destnode, struct ctdb_public_ip *ip);
+int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout, 
+			 uint32_t destnode, struct ctdb_public_ip *ip);
+
+struct ctdb_all_public_ipsv4 {
+	uint32_t num;
+	struct ctdb_public_ipv4 ips[1];
+};
+
+int32_t ctdb_control_get_public_ipsv4(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata);
+int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata);
+int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb, 
+			     struct timeval timeout,
+			     uint32_t destnode,
+			     TALLOC_CTX *mem_ctx,
+			     struct ctdb_all_public_ips **ips);
+#define CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE 0x00010000
+int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
+				   struct timeval timeout, uint32_t destnode,
+				   TALLOC_CTX *mem_ctx,
+				   uint32_t flags,
+				   struct ctdb_all_public_ips **ips);
+int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb, 
+			struct timeval timeout, uint32_t destnode, 
+			TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips);
+
+#ifdef IFNAMSIZ
+#define CTDB_IFACE_SIZE IFNAMSIZ
+#else
+#define CTDB_IFACE_SIZE 16
+#endif
+
+struct ctdb_control_iface_info {
+	char name[CTDB_IFACE_SIZE+2];
+	uint16_t link_state;
+	uint32_t references;
+};
+
+struct ctdb_control_public_ip_info {
+	struct ctdb_public_ip ip;
+	uint32_t active_idx;
+	uint32_t num;
+	struct ctdb_control_iface_info ifaces[1];
+};
+
+struct ctdb_control_get_ifaces {
+	uint32_t num;
+	struct ctdb_control_iface_info ifaces[1];
+};
+
+int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
+					struct ctdb_req_control *c,
+					TDB_DATA indata,
+					TDB_DATA *outdata);
+int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
+				struct ctdb_req_control *c,
+				TDB_DATA *outdata);
+int32_t ctdb_control_set_iface_link(struct ctdb_context *ctdb,
+				    struct ctdb_req_control *c,
+				    TDB_DATA indata);
+int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
+				 struct timeval timeout, uint32_t destnode,
+				 TALLOC_CTX *mem_ctx,
+				 const ctdb_sock_addr *addr,
+				 struct ctdb_control_public_ip_info **info);
+int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
+			 struct timeval timeout, uint32_t destnode,
+			 TALLOC_CTX *mem_ctx,
+			 struct ctdb_control_get_ifaces **ifaces);
+int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
+			     struct timeval timeout, uint32_t destnode,
+			     TALLOC_CTX *mem_ctx,
+			     const struct ctdb_control_iface_info *info);
+
+/* from takeover/system.c */
+uint32_t uint16_checksum(uint16_t *data, size_t n);
+int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface);
+bool ctdb_sys_have_ip(ctdb_sock_addr *addr);
+bool ctdb_sys_check_iface_exists(const char *iface);
+int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, 
+		      const ctdb_sock_addr *src,
+		      uint32_t seq, uint32_t ack, int rst);
+
+int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist);
+int ctdb_set_single_public_ip(struct ctdb_context *ctdb,
+			      const char *iface,
+			      const char *ip);
+int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script);
+int ctdb_set_event_script_dir(struct ctdb_context *ctdb, const char *script_dir);
+int ctdb_set_notification_script(struct ctdb_context *ctdb, const char *script);
+int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap);
+
+int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, 
+				TDB_DATA indata);
+int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tcp_update_needed);
+int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn);
+int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
+int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata);
+
+void ctdb_takeover_client_destructor_hook(struct ctdb_client *client);
+int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_eventscript_call call);
+int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_eventscript_call call,
+			   const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+int ctdb_event_script_callback(struct ctdb_context *ctdb, 
+			       TALLOC_CTX *mem_ctx,
+			       void (*callback)(struct ctdb_context *, int, void *),
+			       void *private_data,
+			       bool from_user,
+			       enum ctdb_eventscript_call call,
+			       const char *fmt, ...) PRINTF_ATTRIBUTE(7,8);
+void ctdb_release_all_ips(struct ctdb_context *ctdb);
+
+void set_nonblocking(int fd);
+void set_close_on_exec(int fd);
+
+bool ctdb_recovery_lock(struct ctdb_context *ctdb, bool keep);
+
+int ctdb_set_recovery_lock_file(struct ctdb_context *ctdb, const char *file);
+
+int32_t ctdb_control_get_tunable(struct ctdb_context *ctdb, TDB_DATA indata, 
+				 TDB_DATA *outdata);
+int32_t ctdb_control_set_tunable(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_list_tunables(struct ctdb_context *ctdb, TDB_DATA *outdata);
+int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
+int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb, TDB_DATA indata);
+
+void ctdb_tunables_set_defaults(struct ctdb_context *ctdb);
+
+int32_t ctdb_control_modflags(struct ctdb_context *ctdb, TDB_DATA indata);
+
+int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb, 
+			       struct timeval timeout, 
+			       uint32_t destnode,
+			       struct ctdb_tunable *tunables);
+
+int ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority);
+
+bool parse_ip_mask(const char *s, const char *iface, ctdb_sock_addr *addr, unsigned *mask);
+bool parse_ip_port(const char *s, ctdb_sock_addr *addr);
+bool parse_ip(const char *s, const char *iface, unsigned port, ctdb_sock_addr *addr);
+bool parse_ipv4(const char *s, unsigned port, struct sockaddr_in *sin);
+ 
+
+int ctdb_sys_open_capture_socket(const char *iface, void **private_data);
+int ctdb_sys_close_capture_socket(void *private_data);
+int ctdb_sys_read_tcp_packet(int s, void *private_data, ctdb_sock_addr *src, ctdb_sock_addr *dst, uint32_t *ack_seq, uint32_t *seq);
+
+int ctdb_ctrl_killtcp(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      struct ctdb_control_killtcp *killtcp);
+
+int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      struct ctdb_control_ip_iface *pub);
+
+int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      struct ctdb_control_ip_iface *pub);
+
+int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      ctdb_sock_addr *addr,
+		      const char *ifname);
+
+int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb, 
+		      struct timeval timeout, 
+		      uint32_t destnode,
+		      TALLOC_CTX *mem_ctx,
+		      ctdb_sock_addr *addr,
+		      struct ctdb_control_tcp_tickle_list **list);
+
+
+int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb, 
+		      uint32_t client_id,
+		      TDB_DATA indata);
+int32_t ctdb_control_check_server_id(struct ctdb_context *ctdb, 
+		      TDB_DATA indata);
+int32_t ctdb_control_unregister_server_id(struct ctdb_context *ctdb, 
+		      TDB_DATA indata);
+int32_t ctdb_control_get_server_id_list(struct ctdb_context *ctdb, 
+		      TDB_DATA *outdata);
+int32_t ctdb_control_uptime(struct ctdb_context *ctdb, 
+		      TDB_DATA *outdata);
+
+int ctdb_attach_databases(struct ctdb_context *ctdb);
+
+int32_t ctdb_control_persistent_store(struct ctdb_context *ctdb, 
+				      struct ctdb_req_control *c, 
+				      TDB_DATA recdata, bool *async_reply);
+int32_t ctdb_control_update_record(struct ctdb_context *ctdb, 
+				   struct ctdb_req_control *c, TDB_DATA recdata, 
+				   bool *async_reply);
+int32_t ctdb_control_trans2_commit(struct ctdb_context *ctdb, 
+				   struct ctdb_req_control *c, 
+				   TDB_DATA recdata, bool *async_reply);
+
+int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
+				   struct ctdb_req_control *c,
+				   TDB_DATA recdata, bool *async_reply);
+
+void ctdb_persistent_finish_trans3_commits(struct ctdb_context *ctdb);
+
+int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id);
+int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id);
+int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb);
+int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_db_set_healthy(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_db_get_health(struct ctdb_context *ctdb,
+				   TDB_DATA indata,
+				   TDB_DATA *outdata);
+
+
+int ctdb_vacuum(struct ctdb_context *ctdb, int argc, const char **argv);
+int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv);
+
+void ctdb_block_signal(int signum);
+void ctdb_unblock_signal(int signum);
+int32_t ctdb_monitoring_mode(struct ctdb_context *ctdb);
+int ctdb_set_child_logging(struct ctdb_context *ctdb);
+void ctdb_lockdown_memory(struct ctdb_context *ctdb);
+
+typedef void (*client_async_callback)(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data);
+
+struct client_async_data {
+	enum ctdb_controls opcode;
+	bool dont_log_errors;
+	uint32_t count;
+	uint32_t fail_count;
+	client_async_callback callback;
+	client_async_callback fail_callback;
+	void *callback_data;
+};
+void ctdb_client_async_add(struct client_async_data *data, struct ctdb_client_control_state *state);
+int ctdb_client_async_wait(struct ctdb_context *ctdb, struct client_async_data *data);
+int ctdb_client_async_control(struct ctdb_context *ctdb,
+				enum ctdb_controls opcode,
+				uint32_t *nodes,
+			      	uint64_t srvid,
+				struct timeval timeout,
+				bool dont_log_errors,
+				TDB_DATA data,
+			      	client_async_callback client_callback,
+			        client_async_callback fail_callback,
+				void *callback_data);
+
+void ctdb_load_nodes_file(struct ctdb_context *ctdb);
+
+int ctdb_control_reload_nodes_file(struct ctdb_context *ctdb, uint32_t opcode);
+
+int32_t ctdb_dump_memory(struct ctdb_context *ctdb, TDB_DATA *outdata);
+int32_t ctdb_control_get_capabilities(struct ctdb_context *ctdb, TDB_DATA *outdata);
+
+int32_t ctdb_control_trans2_finished(struct ctdb_context *ctdb, 
+				     struct ctdb_req_control *c);
+int32_t ctdb_control_trans2_error(struct ctdb_context *ctdb, 
+				  struct ctdb_req_control *c);
+int32_t ctdb_control_trans2_active(struct ctdb_context *ctdb,
+				   struct ctdb_req_control *c,
+				   uint32_t db_id);
+
+char *ctdb_addr_to_str(ctdb_sock_addr *addr);
+unsigned ctdb_addr_to_port(ctdb_sock_addr *addr);
+void ctdb_canonicalize_ip(const ctdb_sock_addr *ip, ctdb_sock_addr *cip);
+
+int32_t ctdb_control_recd_ping(struct ctdb_context *ctdb);
+int32_t ctdb_control_set_recmaster(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata);
+
+extern int script_log_level;
+extern bool fast_start;
+
+int32_t ctdb_control_get_event_script_status(struct ctdb_context *ctdb,
+					     uint32_t call_type,
+					     TDB_DATA *outdata);
+
+int ctdb_log_event_script_output(struct ctdb_context *ctdb, char *str, uint16_t len);
+int ctdb_ctrl_report_recd_lock_latency(struct ctdb_context *ctdb, struct timeval timeout, double latency);
+
+int32_t ctdb_control_stop_node(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply);
+int32_t ctdb_control_continue_node(struct ctdb_context *ctdb);
+
+void ctdb_stop_vacuuming(struct ctdb_context *ctdb);
+int ctdb_vacuum_init(struct ctdb_db_context *ctdb_db);
+
+int32_t ctdb_control_enable_script(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_disable_script(struct ctdb_context *ctdb, TDB_DATA indata);
+
+int32_t ctdb_local_node_got_banned(struct ctdb_context *ctdb);
+int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata);
+int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata);
+void ctdb_ban_self(struct ctdb_context *ctdb);
+
+int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata);
+
+int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata);
+
+int start_syslog_daemon(struct ctdb_context *ctdb);
+
+/* Where to send the log messages back to */
+struct ctdb_get_log_addr {
+	uint32_t pnn;
+	uint64_t srvid;
+	int32_t level;
+};
+
+extern int log_ringbuf_size;
+
+int32_t ctdb_control_get_log(struct ctdb_context *ctdb, TDB_DATA addr);
+int32_t ctdb_control_clear_log(struct ctdb_context *ctdb);
+
+
+struct ctdb_log_state *ctdb_fork_with_logging(TALLOC_CTX *mem_ctx,
+					      struct ctdb_context *ctdb,
+					      const char *log_prefix,
+					      void (*logfn)(const char *, uint16_t, void *),
+					      void *logfn_private, pid_t *pid);
+
+int32_t ctdb_control_process_exists(struct ctdb_context *ctdb, pid_t pid);
+struct ctdb_client *ctdb_find_client_by_pid(struct ctdb_context *ctdb, pid_t pid);
+
+int32_t ctdb_control_get_db_seqnum(struct ctdb_context *ctdb,
+				   TDB_DATA indata,
+				   TDB_DATA *outdata);
+
+int ctdb_load_persistent_health(struct ctdb_context *ctdb,
+				struct ctdb_db_context *ctdb_db);
+int ctdb_update_persistent_health(struct ctdb_context *ctdb,
+				  struct ctdb_db_context *ctdb_db,
+				  const char *reason,/* NULL means healthy */
+				  int num_healthy_nodes);
+int ctdb_recheck_persistent_health(struct ctdb_context *ctdb);
+
+void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event);
+
+void ctdb_fault_setup(void);
+
+int verify_remote_ip_allocation(struct ctdb_context *ctdb, 
+				struct ctdb_all_public_ips *ips);
+int update_ip_assignment_tree(struct ctdb_context *ctdb,
+				struct ctdb_public_ip *ip);
+
+int ctdb_init_tevent_logging(struct ctdb_context *ctdb);
+
+int ctdb_statistics_init(struct ctdb_context *ctdb);
+
+int32_t ctdb_control_get_stat_history(struct ctdb_context *ctdb,
+				      struct ctdb_req_control *c,
+				      TDB_DATA *outdata);
+
+int ctdb_deferred_drop_all_ips(struct ctdb_context *ctdb);
+
+int ctdb_process_deferred_attach(struct ctdb_context *ctdb);
+
+/**
+ * structure to pass to a schedule_for_deletion_control
+ */
+struct ctdb_control_schedule_for_deletion {
+	uint32_t db_id;
+	struct ctdb_ltdb_header hdr;
+	uint32_t keylen;
+	uint8_t key[1]; /* key[] */
+};
+
+int32_t ctdb_control_schedule_for_deletion(struct ctdb_context *ctdb,
+					   TDB_DATA indata);
+
+
+int32_t ctdb_local_schedule_for_deletion(struct ctdb_db_context *ctdb_db,
+					 const struct ctdb_ltdb_header *hdr,
+					 TDB_DATA key);
+
+struct ctdb_ltdb_header *ctdb_header_from_record_handle(struct ctdb_record_handle *h);
+
+/* For unit testing ctdb_transaction.c. */
+struct ctdb_public_ip_list {
+	struct ctdb_public_ip_list *next;
+	uint32_t pnn;
+	ctdb_sock_addr addr;
+};
+uint32_t ip_distance(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2);
+uint32_t ip_distance_2_sum(ctdb_sock_addr *ip,
+			   struct ctdb_public_ip_list *ips,
+			   int pnn);
+uint32_t lcp2_imbalance(struct ctdb_public_ip_list * all_ips, int pnn);
+void lcp2_init(struct ctdb_context * tmp_ctx,
+	       struct ctdb_node_map * nodemap,
+	       uint32_t mask,
+	       struct ctdb_public_ip_list *all_ips,
+	       uint32_t **lcp2_imbalances,
+	       bool **newly_healthy);
+void lcp2_allocate_unassigned(struct ctdb_context *ctdb,
+			      struct ctdb_node_map *nodemap,
+			      uint32_t mask,
+			      struct ctdb_public_ip_list *all_ips,
+			      uint32_t *lcp2_imbalances);
+bool lcp2_failback(struct ctdb_context *ctdb,
+		   struct ctdb_node_map *nodemap,
+		   uint32_t mask,
+		   struct ctdb_public_ip_list *all_ips,
+		   uint32_t *lcp2_imbalances,
+		   bool *newly_healthy);
+void ctdb_takeover_run_core(struct ctdb_context *ctdb,
+			    struct ctdb_node_map *nodemap,
+			    struct ctdb_public_ip_list **all_ips_p);
+
+int ctdb_trackingdb_add_pnn(struct ctdb_context *ctdb, TDB_DATA *data, uint32_t pnn);
+
+typedef void (*ctdb_trackingdb_cb)(struct ctdb_context *ctdb, uint32_t pnn, void *private_data);
+
+void ctdb_trackingdb_traverse(struct ctdb_context *ctdb, TDB_DATA data, ctdb_trackingdb_cb cb, void *private_data);
+
+int ctdb_start_revoke_ro_record(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data);
+
+typedef void (*deferred_requeue_fn)(void *call_context, struct ctdb_req_header *hdr);
+
+int ctdb_add_revoke_deferred_call(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_req_header *hdr, deferred_requeue_fn fn, void *call_context);
+
+int ctdb_set_db_readonly(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db);
+
+#endif

Added: branches/ctdb/squeeze-backports/include/ctdb_protocol.h
===================================================================
--- branches/ctdb/squeeze-backports/include/ctdb_protocol.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/include/ctdb_protocol.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,643 @@
+/*
+   ctdb database library
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CTDB_PROTOCOL_H
+#define _CTDB_PROTOCOL_H
+
+/* location of daemon socket */
+#define CTDB_PATH	"/tmp/ctdb.socket"
+
+/* default ctdb port number */
+#define CTDB_PORT 4379
+
+/* we must align packets to ensure ctdb works on all architectures (eg. sparc) */
+#define CTDB_DS_ALIGNMENT 8
+
+
+#define CTDB_NULL_FUNC                  0xFF000001
+#define CTDB_FETCH_FUNC                 0xFF000002
+#define CTDB_FETCH_WITH_HEADER_FUNC     0xFF000003
+
+
+struct ctdb_call {
+	int call_id;
+	TDB_DATA key;
+	TDB_DATA call_data;
+	TDB_DATA reply_data;
+	uint32_t status;
+#define CTDB_IMMEDIATE_MIGRATION		0x00000001
+#define CTDB_CALL_FLAG_VACUUM_MIGRATION		0x00000002
+#define CTDB_WANT_READONLY			0x00000004
+	uint32_t flags;
+};
+
+/*
+  structure passed to a ctdb call backend function
+*/
+struct ctdb_call_info {
+	TDB_DATA key;          /* record key */
+	struct ctdb_ltdb_header *header;
+	TDB_DATA record_data;  /* current data in the record */
+	TDB_DATA *new_data;    /* optionally updated record data */
+	TDB_DATA *call_data;   /* optionally passed from caller */
+	TDB_DATA *reply_data;  /* optionally returned by function */
+	uint32_t status;       /* optional reply status - defaults to zero */
+};
+
+#define CTDB_ERR_INVALID 1
+#define CTDB_ERR_NOMEM 2
+
+/*
+  ctdb flags
+*/
+#define CTDB_FLAG_TORTURE      (1<<1)
+
+/*
+   a message handler ID meaning "give me all messages"
+ */
+#define CTDB_SRVID_ALL (~(uint64_t)0)
+
+/*
+  srvid type : RECOVERY
+*/
+#define CTDB_SRVID_RECOVERY	0xF100000000000000LL
+
+/*
+   a message handler ID meaning that the cluster has been reconfigured
+ */
+#define CTDB_SRVID_RECONFIGURE 0xF200000000000000LL
+
+/*
+   a message handler ID meaning that an IP address has been released
+ */
+#define CTDB_SRVID_RELEASE_IP 0xF300000000000000LL
+
+/*
+   a message handler ID meaning that an IP address has been taken
+ */
+#define CTDB_SRVID_TAKE_IP 0xF301000000000000LL
+
+/*
+   a message ID to set the node flags in the recovery daemon
+ */
+#define CTDB_SRVID_SET_NODE_FLAGS 0xF400000000000000LL
+
+/*
+   a message ID to ask the recovery daemon to update the expected node
+   assignment for a public ip
+ */
+#define CTDB_SRVID_RECD_UPDATE_IP 0xF500000000000000LL
+
+/*
+  a message to tell the recovery daemon to fetch a set of records
+ */
+#define CTDB_SRVID_VACUUM_FETCH 0xF700000000000000LL
+
+/*
+  a message to tell the recovery daemon to write a talloc memdump
+  to the log
+ */
+#define CTDB_SRVID_MEM_DUMP 0xF800000000000000LL
+
+/*
+   a message ID to get the recovery daemon to push the node flags out
+ */
+#define CTDB_SRVID_PUSH_NODE_FLAGS 0xF900000000000000LL
+
+/*
+   a message ID to get the recovery daemon to reload the nodes file
+ */
+#define CTDB_SRVID_RELOAD_NODES 0xFA00000000000000LL
+
+/*
+   a message ID to get the recovery daemon to perform a takeover run
+ */
+#define CTDB_SRVID_TAKEOVER_RUN 0xFB00000000000000LL
+
+/* A message id to ask the recovery daemon to temporarily disable the
+   public ip checks
+*/
+#define CTDB_SRVID_DISABLE_IP_CHECK  0xFC00000000000000LL
+
+/* A dummy port used for sending back ipreallocate resposnes to the main
+   daemon
+*/
+#define CTDB_SRVID_TAKEOVER_RUN_RESPONSE  0xFD00000000000000LL
+
+/* A range of ports reserved for samba (top 32 bits)
+ * All ports matching the 32 top bits are reserved for exclusive use by
+ * CIFS server
+ */
+#define CTDB_SRVID_SAMBA_NOTIFY  0xFE00000000000000LL
+#define CTDB_SRVID_SAMBA_RANGE   0xFE00000000000000LL
+
+/* A range of ports reserved for a CTDB NFS server (top 32 bits)
+ * All ports matching the 32 top bits are reserved for exclusive use by
+ * NFS server
+ */
+#define CTDB_SRVID_NFSD_RANGE  0xFE01000000000000LL
+
+/* A range of ports reserved for a CTDB ISCSI server (top 32 bits)
+ * All ports matching the 32 top bits are reserved for exclusive use by
+ * ISCSI server
+ */
+#define CTDB_SRVID_ISCSID_RANGE  0xFE02000000000000LL
+
+/* A range of ports reserved for testing (top 32 bits)
+ * All ports matching the 32 top bits are reserved for exclusive use by
+ * test applications
+ */
+#define CTDB_SRVID_TEST_RANGE  0xFE03000000000000LL
+
+/* Range of ports reserved for traversals */
+#define CTDB_SRVID_TRAVERSE_RANGE  0xFE04000000000000LL
+
+/* used on the domain socket, send a pdu to the local daemon */
+#define CTDB_CURRENT_NODE     0xF0000001
+/* send a broadcast to all nodes in the cluster, active or not */
+#define CTDB_BROADCAST_ALL    0xF0000002
+/* send a broadcast to all nodes in the current vnn map */
+#define CTDB_BROADCAST_VNNMAP 0xF0000003
+/* send a broadcast to all connected nodes */
+#define CTDB_BROADCAST_CONNECTED 0xF0000004
+
+/* the key used for transaction locking on persistent databases */
+#define CTDB_TRANSACTION_LOCK_KEY "__transaction_lock__"
+
+/* the key used to store persistent db sequence number */
+#define CTDB_DB_SEQNUM_KEY "__db_sequence_number__"
+
+#define MONITOR_SCRIPT_OK      0
+#define MONITOR_SCRIPT_TIMEOUT 1
+
+#define MAX_SCRIPT_NAME 31
+#define MAX_SCRIPT_OUTPUT 511
+struct ctdb_script_wire {
+	char name[MAX_SCRIPT_NAME+1];
+	struct timeval start;
+	struct timeval finished;
+	int32_t status;
+	char output[MAX_SCRIPT_OUTPUT+1];
+};
+
+struct ctdb_scripts_wire {
+	uint32_t num_scripts;
+	struct ctdb_script_wire scripts[1];
+};
+
+/* different calls to event scripts. */
+enum ctdb_eventscript_call {
+	CTDB_EVENT_INIT,		/* CTDB starting up: no args */
+	CTDB_EVENT_SETUP,		/* CTDB starting up after transport is readdy: no args. */
+	CTDB_EVENT_STARTUP,		/* CTDB starting up after initial recovery: no args. */
+	CTDB_EVENT_START_RECOVERY,	/* CTDB recovery starting: no args. */
+	CTDB_EVENT_RECOVERED,		/* CTDB recovery finished: no args. */
+	CTDB_EVENT_TAKE_IP,		/* IP taken: interface, IP address, netmask bits. */
+	CTDB_EVENT_RELEASE_IP,		/* IP released: interface, IP address, netmask bits. */
+	CTDB_EVENT_STOPPED,		/* This node is stopped: no args. */
+	CTDB_EVENT_MONITOR,		/* Please check if service is healthy: no args. */
+	CTDB_EVENT_STATUS,		/* Report service status: no args. */
+	CTDB_EVENT_SHUTDOWN,		/* CTDB shutting down: no args. */
+	CTDB_EVENT_RELOAD,		/* magic */
+	CTDB_EVENT_UPDATE_IP,		/* IP updating: old interface, new interface, IP address, netmask bits. */
+	CTDB_EVENT_IPREALLOCATED,	/* when a takeover_run() completes */
+	CTDB_EVENT_MAX
+};
+
+/* Mapping from enum to names. */
+extern const char *ctdb_eventscript_call_names[];
+
+/*
+  operation IDs
+*/
+enum ctdb_operation {
+	CTDB_REQ_CALL           = 0,
+	CTDB_REPLY_CALL         = 1,
+	CTDB_REQ_DMASTER        = 2,
+	CTDB_REPLY_DMASTER      = 3,
+	CTDB_REPLY_ERROR        = 4,
+	CTDB_REQ_MESSAGE        = 5,
+	/* #6 removed */
+	CTDB_REQ_CONTROL        = 7,
+	CTDB_REPLY_CONTROL      = 8,
+	CTDB_REQ_KEEPALIVE      = 9,
+};
+
+#define CTDB_MAGIC 0x43544442 /* CTDB */
+#define CTDB_VERSION 1
+
+enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS          = 0,
+		    CTDB_CONTROL_STATISTICS              = 1,
+		    /* #2 removed */
+		    CTDB_CONTROL_PING                    = 3,
+		    CTDB_CONTROL_GETDBPATH               = 4,
+		    CTDB_CONTROL_GETVNNMAP               = 5,
+		    CTDB_CONTROL_SETVNNMAP               = 6,
+		    CTDB_CONTROL_GET_DEBUG               = 7,
+		    CTDB_CONTROL_SET_DEBUG               = 8,
+		    CTDB_CONTROL_GET_DBMAP               = 9,
+		    CTDB_CONTROL_GET_NODEMAPv4           = 10, /* obsolete */
+		    CTDB_CONTROL_SET_DMASTER             = 11,
+		    /* #12 removed */
+		    CTDB_CONTROL_PULL_DB                 = 13,
+		    CTDB_CONTROL_PUSH_DB                 = 14,
+		    CTDB_CONTROL_GET_RECMODE             = 15,
+		    CTDB_CONTROL_SET_RECMODE             = 16,
+		    CTDB_CONTROL_STATISTICS_RESET        = 17,
+		    CTDB_CONTROL_DB_ATTACH               = 18,
+		    CTDB_CONTROL_SET_CALL                = 19,
+		    CTDB_CONTROL_TRAVERSE_START          = 20,
+		    CTDB_CONTROL_TRAVERSE_ALL            = 21,
+		    CTDB_CONTROL_TRAVERSE_DATA           = 22,
+		    CTDB_CONTROL_REGISTER_SRVID          = 23,
+		    CTDB_CONTROL_DEREGISTER_SRVID        = 24,
+		    CTDB_CONTROL_GET_DBNAME              = 25,
+		    CTDB_CONTROL_ENABLE_SEQNUM           = 26,
+		    CTDB_CONTROL_UPDATE_SEQNUM           = 27,
+		    /* #28 removed */
+		    CTDB_CONTROL_DUMP_MEMORY             = 29,
+		    CTDB_CONTROL_GET_PID                 = 30,
+		    CTDB_CONTROL_GET_RECMASTER           = 31,
+		    CTDB_CONTROL_SET_RECMASTER           = 32,
+		    CTDB_CONTROL_FREEZE                  = 33,
+		    CTDB_CONTROL_THAW                    = 34,
+		    CTDB_CONTROL_GET_PNN                 = 35,
+		    CTDB_CONTROL_SHUTDOWN                = 36,
+		    CTDB_CONTROL_GET_MONMODE             = 37,
+		    /* #38 removed */
+		    /* #39 removed */
+		    /* #40 removed */
+		    /* #41 removed */
+		    CTDB_CONTROL_TAKEOVER_IPv4           = 42, /* obsolete */
+		    CTDB_CONTROL_RELEASE_IPv4            = 43, /* obsolete */
+		    CTDB_CONTROL_TCP_CLIENT              = 44,
+		    CTDB_CONTROL_TCP_ADD                 = 45,
+		    CTDB_CONTROL_TCP_REMOVE              = 46,
+		    CTDB_CONTROL_STARTUP                 = 47,
+		    CTDB_CONTROL_SET_TUNABLE             = 48,
+		    CTDB_CONTROL_GET_TUNABLE             = 49,
+		    CTDB_CONTROL_LIST_TUNABLES           = 50,
+		    CTDB_CONTROL_GET_PUBLIC_IPSv4        = 51, /* obsolete */
+		    CTDB_CONTROL_MODIFY_FLAGS            = 52,
+		    CTDB_CONTROL_GET_ALL_TUNABLES        = 53,
+		    CTDB_CONTROL_KILL_TCP                = 54,
+		    CTDB_CONTROL_GET_TCP_TICKLE_LIST     = 55,
+		    CTDB_CONTROL_SET_TCP_TICKLE_LIST     = 56,
+		    CTDB_CONTROL_REGISTER_SERVER_ID	 = 57,
+		    CTDB_CONTROL_UNREGISTER_SERVER_ID	 = 58,
+		    CTDB_CONTROL_CHECK_SERVER_ID	 = 59,
+		    CTDB_CONTROL_GET_SERVER_ID_LIST	 = 60,
+		    CTDB_CONTROL_DB_ATTACH_PERSISTENT    = 61,
+		    CTDB_CONTROL_PERSISTENT_STORE        = 62,
+		    CTDB_CONTROL_UPDATE_RECORD           = 63,
+		    CTDB_CONTROL_SEND_GRATIOUS_ARP       = 64,
+		    CTDB_CONTROL_TRANSACTION_START       = 65,
+		    CTDB_CONTROL_TRANSACTION_COMMIT      = 66,
+		    CTDB_CONTROL_WIPE_DATABASE           = 67,
+		    /* #68 removed */
+		    CTDB_CONTROL_UPTIME                  = 69,
+		    CTDB_CONTROL_START_RECOVERY          = 70,
+		    CTDB_CONTROL_END_RECOVERY            = 71,
+		    CTDB_CONTROL_RELOAD_NODES_FILE       = 72,
+		    /* #73 removed */
+		    CTDB_CONTROL_TRY_DELETE_RECORDS      = 74,
+		    CTDB_CONTROL_ENABLE_MONITOR          = 75,
+		    CTDB_CONTROL_DISABLE_MONITOR         = 76,
+		    CTDB_CONTROL_ADD_PUBLIC_IP           = 77,
+		    CTDB_CONTROL_DEL_PUBLIC_IP           = 78,
+		    CTDB_CONTROL_RUN_EVENTSCRIPTS        = 79,
+		    CTDB_CONTROL_GET_CAPABILITIES	 = 80,
+		    CTDB_CONTROL_START_PERSISTENT_UPDATE = 81,
+		    CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE= 82,
+		    CTDB_CONTROL_TRANS2_COMMIT           = 83,
+		    CTDB_CONTROL_TRANS2_FINISHED         = 84,
+		    CTDB_CONTROL_TRANS2_ERROR            = 85,
+		    CTDB_CONTROL_TRANS2_COMMIT_RETRY     = 86,
+		    CTDB_CONTROL_RECD_PING		 = 87,
+		    CTDB_CONTROL_RELEASE_IP              = 88,
+		    CTDB_CONTROL_TAKEOVER_IP             = 89,
+		    CTDB_CONTROL_GET_PUBLIC_IPS          = 90,
+		    CTDB_CONTROL_GET_NODEMAP             = 91,
+		    CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS = 96,
+		    CTDB_CONTROL_TRAVERSE_KILL		 = 97,
+		    CTDB_CONTROL_RECD_RECLOCK_LATENCY    = 98,
+		    CTDB_CONTROL_GET_RECLOCK_FILE        = 99,
+		    CTDB_CONTROL_SET_RECLOCK_FILE        = 100,
+		    CTDB_CONTROL_STOP_NODE               = 101,
+		    CTDB_CONTROL_CONTINUE_NODE           = 102,
+		    CTDB_CONTROL_SET_NATGWSTATE          = 103,
+		    CTDB_CONTROL_SET_LMASTERROLE         = 104,
+		    CTDB_CONTROL_SET_RECMASTERROLE       = 105,
+		    CTDB_CONTROL_ENABLE_SCRIPT           = 107,
+		    CTDB_CONTROL_DISABLE_SCRIPT          = 108,
+		    CTDB_CONTROL_SET_BAN_STATE           = 109,
+		    CTDB_CONTROL_GET_BAN_STATE           = 110,
+		    CTDB_CONTROL_SET_DB_PRIORITY         = 111,
+		    CTDB_CONTROL_GET_DB_PRIORITY         = 112,
+		    CTDB_CONTROL_TRANSACTION_CANCEL      = 113,
+		    CTDB_CONTROL_REGISTER_NOTIFY         = 114,
+		    CTDB_CONTROL_DEREGISTER_NOTIFY       = 115,
+		    CTDB_CONTROL_TRANS2_ACTIVE           = 116,
+		    CTDB_CONTROL_GET_LOG		 = 117,
+		    CTDB_CONTROL_CLEAR_LOG		 = 118,
+		    CTDB_CONTROL_TRANS3_COMMIT           = 119,
+		    CTDB_CONTROL_GET_DB_SEQNUM           = 120,
+		    CTDB_CONTROL_DB_SET_HEALTHY		 = 121,
+		    CTDB_CONTROL_DB_GET_HEALTH		 = 122,
+		    CTDB_CONTROL_GET_PUBLIC_IP_INFO	 = 123,
+		    CTDB_CONTROL_GET_IFACES		 = 124,
+		    CTDB_CONTROL_SET_IFACE_LINK_STATE	 = 125,
+		    CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE  = 126,
+		    CTDB_CONTROL_GET_STAT_HISTORY	 = 127,
+		    CTDB_CONTROL_SCHEDULE_FOR_DELETION   = 128,
+		    CTDB_CONTROL_SET_DB_READONLY	 = 129,
+};
+
+/*
+  packet structures
+*/
+struct ctdb_req_header {
+	uint32_t length;
+	uint32_t ctdb_magic;
+	uint32_t ctdb_version;
+	uint32_t generation;
+	uint32_t operation;
+	uint32_t destnode;
+	uint32_t srcnode;
+	uint32_t reqid;
+};
+
+struct ctdb_req_call {
+	struct ctdb_req_header hdr;
+	uint32_t flags;
+	uint32_t db_id;
+	uint32_t callid;
+	uint32_t hopcount;
+	uint32_t keylen;
+	uint32_t calldatalen;
+	uint8_t data[1]; /* key[] followed by calldata[] */
+};
+
+struct ctdb_reply_call {
+	struct ctdb_req_header hdr;
+	uint32_t status;
+	uint32_t datalen;
+	uint8_t  data[1];
+};
+
+struct ctdb_reply_error {
+	struct ctdb_req_header hdr;
+	uint32_t status;
+	uint32_t msglen;
+	uint8_t  msg[1];
+};
+
+struct ctdb_req_dmaster {
+	struct ctdb_req_header hdr;
+	uint32_t db_id;
+	uint64_t rsn;
+	uint32_t dmaster;
+	uint32_t keylen;
+	uint32_t datalen;
+	uint8_t  data[1];
+};
+
+struct ctdb_reply_dmaster {
+	struct ctdb_req_header hdr;
+	uint32_t db_id;
+	uint64_t rsn;
+	uint32_t keylen;
+	uint32_t datalen;
+	uint8_t  data[1];
+};
+
+struct ctdb_req_message {
+	struct ctdb_req_header hdr;
+	uint64_t srvid;
+	uint32_t datalen;
+	uint8_t data[1];
+};
+
+struct ctdb_req_getdbpath {
+	struct ctdb_req_header hdr;
+	uint32_t db_id;
+};
+
+struct ctdb_reply_getdbpath {
+	struct ctdb_req_header hdr;
+	uint32_t datalen;
+	uint8_t data[1];
+};
+
+struct ctdb_req_control {
+	struct ctdb_req_header hdr;
+	uint32_t opcode;
+	uint32_t pad;
+	uint64_t srvid;
+	uint32_t client_id;
+#define CTDB_CTRL_FLAG_NOREPLY   1
+#define CTDB_CTRL_FLAG_OPCODE_SPECIFIC   0xFFFF0000
+	uint32_t flags;
+	uint32_t datalen;
+	uint8_t data[1];
+};
+
+struct ctdb_reply_control {
+	struct ctdb_req_header hdr;
+	int32_t  status;
+	uint32_t datalen;
+	uint32_t errorlen;
+	uint8_t data[1];
+};
+
+struct ctdb_req_keepalive {
+	struct ctdb_req_header hdr;
+};
+
+
+/* types of failures possible from TRANS2_COMMIT */
+enum ctdb_trans2_commit_error {
+	CTDB_TRANS2_COMMIT_SUCCESS=0, /* all nodes committed successfully */
+	CTDB_TRANS2_COMMIT_TIMEOUT=1, /* at least one node timed out */
+	CTDB_TRANS2_COMMIT_ALLFAIL=2, /* all nodes failed the commit */
+	CTDB_TRANS2_COMMIT_SOMEFAIL=3 /* some nodes failed the commit, some allowed it */
+};
+
+/*
+  the extended header for records in the ltdb
+*/
+struct ctdb_ltdb_header {
+	uint64_t rsn;
+	uint32_t dmaster;
+	uint32_t reserved1;
+#define CTDB_REC_FLAG_DEFAULT			0x00000000
+#define CTDB_REC_FLAG_MIGRATED_WITH_DATA	0x00010000
+#define CTDB_REC_FLAG_VACUUM_MIGRATED		0x00020000
+#define CTDB_REC_FLAG_AUTOMATIC			0x00040000
+#define CTDB_REC_RO_HAVE_DELEGATIONS		0x01000000
+#define CTDB_REC_RO_HAVE_READONLY		0x02000000
+#define CTDB_REC_RO_REVOKING_READONLY		0x04000000
+#define CTDB_REC_RO_REVOKE_COMPLETE		0x08000000
+	uint32_t flags;
+};
+
+
+/*
+  definitions for different socket structures
+ */
+typedef struct sockaddr_in ctdb_addr_in;
+typedef struct sockaddr_in6 ctdb_addr_in6;
+typedef union {
+	struct sockaddr sa;
+	ctdb_addr_in	ip;
+	ctdb_addr_in6	ip6;
+} ctdb_sock_addr;
+
+/*
+   A structure describing a single node, its flags and its address
+*/
+struct ctdb_node_and_flags {
+	uint32_t pnn;
+	uint32_t flags;
+	ctdb_sock_addr addr;
+};
+
+
+/*
+   Structure used for a nodemap. 
+   The nodemap is the structure containing a list of all nodes
+   known to the cluster and their associated flags.
+*/
+struct ctdb_node_map {
+	uint32_t num;
+	struct ctdb_node_and_flags nodes[1];
+};
+
+/*
+ * Node flags
+ */
+#define NODE_FLAGS_DISCONNECTED		0x00000001 /* node isn't connected */
+#define NODE_FLAGS_UNHEALTHY  		0x00000002 /* monitoring says node is unhealthy */
+#define NODE_FLAGS_PERMANENTLY_DISABLED	0x00000004 /* administrator has disabled node */
+#define NODE_FLAGS_BANNED		0x00000008 /* recovery daemon has banned the node */
+#define NODE_FLAGS_DELETED		0x00000010 /* this node has been deleted */
+#define NODE_FLAGS_STOPPED		0x00000020 /* this node has been stopped */
+#define NODE_FLAGS_DISABLED		(NODE_FLAGS_UNHEALTHY|NODE_FLAGS_PERMANENTLY_DISABLED)
+#define NODE_FLAGS_INACTIVE		(NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)
+
+
+struct ctdb_public_ip {
+	uint32_t pnn;
+	ctdb_sock_addr addr;
+};
+
+struct ctdb_all_public_ips {
+	uint32_t num;
+	struct ctdb_public_ip ips[1];
+};
+
+
+struct latency_counter {
+	int num;
+	double min;
+	double max;
+	double total;
+};
+
+/*
+  structure used to pass record data between the child and parent
+ */
+struct ctdb_rec_data {
+	uint32_t length;
+	uint32_t reqid;
+	uint32_t keylen;
+	uint32_t datalen;
+	uint8_t  data[1];
+};
+
+struct ctdb_traverse_start {
+	uint32_t db_id;
+	uint32_t reqid;
+	uint64_t srvid;
+};
+
+/*
+  ctdb statistics information
+ */
+struct ctdb_statistics {
+	uint32_t num_clients;
+	uint32_t frozen;
+	uint32_t recovering;
+	uint32_t client_packets_sent;
+	uint32_t client_packets_recv;
+	uint32_t node_packets_sent;
+	uint32_t node_packets_recv;
+	uint32_t keepalive_packets_sent;
+	uint32_t keepalive_packets_recv;
+	struct {
+		uint32_t req_call;
+		uint32_t reply_call;
+		uint32_t req_dmaster;
+		uint32_t reply_dmaster;
+		uint32_t reply_error;
+		uint32_t req_message;
+		uint32_t req_control;
+		uint32_t reply_control;
+	} node;
+	struct {
+		uint32_t req_call;
+		uint32_t req_message;
+		uint32_t req_control;
+	} client;
+	struct {
+		uint32_t call;
+		uint32_t control;
+		uint32_t traverse;
+	} timeouts;
+	struct {
+		struct latency_counter ctdbd;
+		struct latency_counter recd;
+	} reclock;
+	uint32_t total_calls;
+	uint32_t pending_calls;
+	uint32_t lockwait_calls;
+	uint32_t pending_lockwait_calls;
+	uint32_t childwrite_calls;
+	uint32_t pending_childwrite_calls;
+	uint32_t memory_used;
+	uint32_t __last_counter; /* hack for control_statistics_all */
+	uint32_t max_hop_count;
+	struct latency_counter call_latency;
+	struct latency_counter lockwait_latency;
+	struct latency_counter childwrite_latency;
+	uint32_t num_recoveries;
+	struct timeval statistics_start_time;
+	struct timeval statistics_current_time;
+};
+
+/*
+ * wire format for statistics history
+ */
+struct ctdb_statistics_wire {
+	uint32_t num;
+	struct ctdb_statistics stats[1];
+};
+
+
+#endif

Added: branches/ctdb/squeeze-backports/include/ctdb_typesafe_cb.h
===================================================================
--- branches/ctdb/squeeze-backports/include/ctdb_typesafe_cb.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/include/ctdb_typesafe_cb.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,177 @@
+#ifndef CCAN_CAST_IF_TYPE_H
+#define CCAN_CAST_IF_TYPE_H
+
+#if (__GNUC__ >= 3)
+#define HAVE_TYPEOF 1
+#define HAVE_BUILTIN_CHOOSE_EXPR 1
+#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1
+#endif
+
+#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
+/**
+ * cast_if_type - only cast an expression if test matches a given type
+ * @desttype: the type to cast to
+ * @expr: the expression to cast
+ * @test: the expression to test
+ * @oktype: the type we allow
+ *
+ * This macro is used to create functions which allow multiple types.
+ * The result of this macro is used somewhere that a @desttype type is
+ * expected: if @expr was of type @oktype, it will be cast to
+ * @desttype type.  As a result, if @expr is any type other than
+ * @oktype or @desttype, a compiler warning will be issued.
+ *
+ * This macro can be used in static initializers.
+ *
+ * This is merely useful for warnings: if the compiler does not
+ * support the primitives required for cast_if_type(), it becomes an
+ * unconditional cast, and the @test and @oktype argument is not used.  In
+ * particular, this means that @oktype can be a type which uses
+ * the "typeof": it will not be evaluated if typeof is not supported.
+ *
+ * Example:
+ *	// We can take either an unsigned long or a void *.
+ *	void _set_some_value(void *val);
+ *	#define set_some_value(e)			\
+ *		_set_some_value(cast_if_type(void *, (e), (e), unsigned long))
+ */
+#define cast_if_type(desttype, expr, test, oktype)			\
+__builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(test):0), oktype), \
+			(desttype)(expr), (expr))
+#else
+#define cast_if_type(desttype, expr, test, oktype) ((desttype)(expr))
+#endif
+
+/**
+ * cast_if_any - only cast an expression if it is one of the three given types
+ * @desttype: the type to cast to
+ * @expr: the expression to cast
+ * @test: the expression to test
+ * @ok1: the first type we allow
+ * @ok2: the second type we allow
+ * @ok3: the third type we allow
+ *
+ * This is a convenient wrapper for multiple cast_if_type() calls.  You can
+ * chain them inside each other (ie. use cast_if_any() for expr) if you need
+ * more than 3 arguments.
+ *
+ * Example:
+ *	// We can take either a long, unsigned long, void * or a const void *.
+ *	void _set_some_value(void *val);
+ *	#define set_some_value(expr)					\
+ *		_set_some_value(cast_if_any(void *, (expr), (expr),	\
+ *					    long, unsigned long, const void *))
+ */
+#define cast_if_any(desttype, expr, test, ok1, ok2, ok3)		\
+	cast_if_type(desttype,						\
+		     cast_if_type(desttype,				\
+				  cast_if_type(desttype, (expr), (test), ok1), \
+				  ok2),					\
+		     ok3)
+
+/**
+ * typesafe_cb - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * If a callback function takes a single argument, this macro does
+ * appropriate casts to a function which takes a single void * argument if the
+ * callback provided matches the @arg (or a const or volatile version).
+ *
+ * It is assumed that @arg is of pointer type: usually @arg is passed
+ * or assigned to a void * elsewhere anyway.
+ *
+ * Example:
+ *	void _register_callback(void (*fn)(void *arg), void *arg);
+ *	#define register_callback(fn, arg) \
+ *		_register_callback(typesafe_cb(void, (fn), (arg)), (arg))
+ */
+#define typesafe_cb(rtype, fn, arg)			\
+	cast_if_type(rtype (*)(void *), (fn), (fn)(arg), rtype)
+
+/**
+ * typesafe_cb_const - cast a const callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * If a callback function takes a single argument, this macro does appropriate
+ * casts to a function which takes a single const void * argument if the
+ * callback provided matches the @arg.
+ *
+ * It is assumed that @arg is of pointer type: usually @arg is passed
+ * or assigned to a void * elsewhere anyway.
+ *
+ * Example:
+ *	void _register_callback(void (*fn)(const void *arg), const void *arg);
+ *	#define register_callback(fn, arg) \
+ *		_register_callback(typesafe_cb_const(void, (fn), (arg)), (arg))
+ */
+#define typesafe_cb_const(rtype, fn, arg)				\
+	sizeof((fn)((const void *)0)),					\
+		cast_if_type(rtype (*)(const void *),			\
+			     (fn), (fn)(arg), rtype (*)(typeof(arg)))
+
+/**
+ * typesafe_cb_preargs - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * before the @arg.
+ *
+ * Example:
+ *	void _register_callback(void (*fn)(int, void *arg), void *arg);
+ *	#define register_callback(fn, arg) \
+ *		_register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
+ *				   (arg))
+ */
+#define typesafe_cb_preargs(rtype, fn, arg, ...)			\
+	cast_if_type(rtype (*)(__VA_ARGS__, void *), (fn), (fn),	\
+		     rtype (*)(__VA_ARGS__, typeof(arg)))
+/**
+ * typesafe_cb_postargs - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * after the @arg.
+ *
+ * Example:
+ *	void _register_callback(void (*fn)(void *arg, int), void *arg);
+ *	#define register_callback(fn, arg) \
+ *		_register_callback(typesafe_cb_postargs(void, (fn), (arg), int),\
+ *				   (arg))
+ */
+#define typesafe_cb_postargs(rtype, fn, arg, ...)			\
+	cast_if_type(rtype (*)(void *, __VA_ARGS__), (fn), (fn),	\
+		     rtype (*)(typeof(arg), __VA_ARGS__))
+/**
+ * typesafe_cb_cmp - cast a compare function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument(s) to hand to the compare function.
+ *
+ * If a callback function takes two matching-type arguments, this macro does
+ * appropriate casts to a function which takes two const void * arguments if
+ * the callback provided takes two a const pointers to @arg.
+ *
+ * It is assumed that @arg is of pointer type: usually @arg is passed
+ * or assigned to a void * elsewhere anyway.  Note also that the type
+ * arg points to must be defined.
+ *
+ * Example:
+ *	void _my_qsort(void *base, size_t nmemb, size_t size,
+ *		       int (*cmp)(const void *, const void *));
+ *	#define my_qsort(base, nmemb, cmpfn) \
+ *		_my_qsort((base), (nmemb), sizeof(*(base)), \
+ *			  typesafe_cb_cmp(int, (cmpfn), (base)), (arg))
+ */
+#define typesafe_cb_cmp(rtype, cmpfn, arg)				\
+	cast_if_type(rtype (*)(const void *, const void *), (cmpfn),	\
+		     rtype (*)(const typeof(*arg)*, const typeof(*arg)*))
+		     
+#endif /* CCAN_CAST_IF_TYPE_H */

Added: branches/ctdb/squeeze-backports/include/idtree.h
===================================================================
--- branches/ctdb/squeeze-backports/include/idtree.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/include/idtree.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+struct idr_context *idr_init(TALLOC_CTX *mem_ctx);
+int idr_get_new(struct idr_context *idp, void *ptr, int limit);
+int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit);
+int idr_get_new_random(struct idr_context *idp, void *ptr, int limit);
+void *idr_find(struct idr_context *idp, int id);
+int idr_remove(struct idr_context *idp, int id);
+

Added: branches/ctdb/squeeze-backports/include/includes.h
===================================================================
--- branches/ctdb/squeeze-backports/include/includes.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/include/includes.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,60 @@
+#define HAVE_UNIXSOCKET 1
+
+#include "replace.h"
+#include "talloc.h"
+#include "system/wait.h"
+#include "system/network.h"
+#include "tdb.h"
+#include "idtree.h"
+#include "ctdb_client.h"
+
+typedef bool BOOL;
+
+#define True 1
+#define False 0
+
+extern int LogLevel;
+extern int this_log_level;
+
+enum debug_level { 
+	DEBUG_EMERG   = -3, 
+	DEBUG_ALERT   = -2, 
+	DEBUG_CRIT    = -1,
+	DEBUG_ERR     =  0,
+	DEBUG_WARNING =  1,
+	DEBUG_NOTICE  =  2,	
+	DEBUG_INFO    =  3,
+	DEBUG_DEBUG   =  4,
+};
+
+#define DEBUGLVL(lvl) ((lvl) <= LogLevel)
+#define DEBUG(lvl, x) do { this_log_level = (lvl); if ((lvl) < DEBUG_DEBUG) { log_ringbuffer x; } if ((lvl) <= LogLevel) { do_debug x; }} while (0)
+#define DEBUGADD(lvl, x) do { if ((lvl) <= LogLevel) { this_log_level = (lvl); do_debug_add x; }} while (0)
+
+#define _PUBLIC_
+#define _NORETURN_
+#define _PURE_
+
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+
+#ifndef discard_const
+#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
+#endif
+
+struct timeval timeval_zero(void);
+bool timeval_is_zero(const struct timeval *tv);
+struct timeval timeval_current(void);
+struct timeval timeval_set(uint32_t secs, uint32_t usecs);
+int timeval_compare(const struct timeval *tv1, const struct timeval *tv2);
+struct timeval timeval_until(const struct timeval *tv1,
+			     const struct timeval *tv2);
+_PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs);
+double timeval_elapsed(struct timeval *tv);
+double timeval_delta(struct timeval *tv2, struct timeval *tv);
+char **file_lines_load(const char *fname, int *numlines, TALLOC_CTX *mem_ctx);
+char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len);
+_PUBLIC_ const char **str_list_add(const char **list, const char *s);
+_PUBLIC_ int set_blocking(int fd, BOOL set);
+
+#include "lib/util/debug.h"
+#include "lib/util/util.h"

Added: branches/ctdb/squeeze-backports/install-sh
===================================================================
--- branches/ctdb/squeeze-backports/install-sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/install-sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/install-sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/replace/.checker_innocent
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/.checker_innocent	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/.checker_innocent	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,4 @@
+>>>MISTAKE21_create_files_6a9e68ada99a97cb
+>>>MISTAKE21_os2_delete_9b2bfa7f38711d09
+>>>MISTAKE21_os2_delete_2fcc29aaa99a97cb
+>>>SECURITY2_os2_delete_9b2bfa7f1c9396ca

Added: branches/ctdb/squeeze-backports/lib/replace/Makefile.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/Makefile.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/Makefile.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,61 @@
+#!gmake
+#
+CC = @CC@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+includedir = @includedir@
+libdir = @libdir@
+VPATH = @libreplacedir@
+srcdir = @srcdir@
+builddir = @builddir@
+INSTALL = @INSTALL@
+
+.PHONY: test all showflags install installcheck clean distclean realdistclean
+
+CFLAGS=-I. @CFLAGS@
+LDFLAGS=@LDFLAGS@
+
+OBJS = @LIBREPLACEOBJ@
+
+all: showflags libreplace.a testsuite
+
+showflags:
+	@echo 'libreplace will be compiled with flags:'
+	@echo '  CC     = $(CC)'
+	@echo '  CFLAGS = $(CFLAGS)'
+	@echo '  LDFLAGS= $(LDFLAGS)'
+
+install: all
+	mkdir -p $(libdir)
+	$(INSTALL) libreplace.a $(libdir)
+
+libreplace.a: $(OBJS)
+	ar -rcsv $@ $(OBJS)
+
+test: all
+	./testsuite
+
+installcheck: install test
+
+TEST_OBJS = test/testsuite.o test/os2_delete.o test/strptime.o
+
+testsuite: libreplace.a $(TEST_OBJS)
+	$(CC) -o testsuite $(TEST_OBJS) -L. -lreplace $(LDFLAGS)
+
+.c.o:
+	@echo Compiling $*.c
+	@mkdir -p `dirname $@`
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+clean:
+	rm -f *.o test/*.o *.a testsuite
+	rm -f testfile.dat
+
+distclean: clean
+	rm -f *~ */*~
+	rm -f config.log config.status config.h config.cache
+	rm -f Makefile
+
+realdistclean: distclean
+	rm -f configure config.h.in

Added: branches/ctdb/squeeze-backports/lib/replace/README
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,111 @@
+This subsystem ensures that we can always use a certain core set of 
+functions and types, that are either provided by the OS or by replacement 
+functions / definitions in this subsystem. The aim is to try to stick 
+to POSIX functions in here as much as possible. Convenience functions 
+that are available on no platform at all belong in other subsystems
+(such as LIBUTIL).
+
+The following functions are guaranteed:
+
+ftruncate
+strlcpy
+strlcat
+mktime
+rename
+initgroups
+memmove
+strdup
+inet_ntoa
+setlinebuf
+vsyslog
+timegm
+setenv
+unsetenv
+strndup
+strnlen
+waitpid
+seteuid
+setegid
+asprintf
+snprintf
+vasprintf
+vsnprintf
+opendir
+readdir
+telldir
+seekdir
+closedir
+dlopen
+dlclose
+dlsym
+dlerror
+chroot
+bzero
+strerror
+errno
+mkdtemp
+mkstemp (a secure one!)
+pread
+pwrite
+getpass
+readline (the library)
+inet_ntoa
+inet_ntop
+inet_pton
+strtoll
+strtoull
+socketpair
+strptime
+getaddrinfo
+freeaddrinfo
+getnameinfo
+gai_strerror
+getifaddrs
+freeifaddrs
+
+Types:
+bool
+socklen_t
+uint_t
+uint{8,16,32,64}_t
+int{8,16,32,64}_t
+intptr_t
+
+Constants:
+PATH_NAME_MAX
+UINT{16,32,64}_MAX
+INT32_MAX
+RTLD_LAZY
+HOST_NAME_MAX
+UINT16_MAX
+UINT32_MAX
+UINT64_MAX
+CHAR_BIT
+
+Macros:
+va_copy
+__FUNCTION__
+__FILE__
+__LINE__
+__LINESTR__
+__location__
+__STRING
+__STRINGSTRING
+MIN
+MAX
+QSORT_CAST
+ZERO_STRUCT
+ZERO_STRUCTP
+ZERO_STRUCTPN
+ZERO_ARRAY
+ARRAY_SIZE
+PTR_DIFF
+
+Headers:
+stdint.h
+stdbool.h
+
+Prerequisites:
+memset (for bzero)
+syslog (for vsyslog)
+mktemp (for mkstemp and mkdtemp)

Added: branches/ctdb/squeeze-backports/lib/replace/aclocal.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/aclocal.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/aclocal.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+m4_include(libreplace.m4)

Added: branches/ctdb/squeeze-backports/lib/replace/autoconf-2.60.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/autoconf-2.60.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/autoconf-2.60.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,212 @@
+# AC_GNU_SOURCE
+# --------------
+AC_DEFUN([AC_GNU_SOURCE],
+[AH_VERBATIM([_GNU_SOURCE],
+[/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif])dnl
+AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
+AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
+AC_DEFINE([_GNU_SOURCE])
+])
+
+# _AC_C_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST,
+#		ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE)
+# --------------------------------------------------------------
+# Check whether the C compiler accepts features of STANDARD (e.g `c89', `c99')
+# by trying to compile a program of TEST-PROLOGUE and TEST-BODY.  If this fails,
+# try again with each compiler option in the space-separated OPTION-LIST; if one
+# helps, append it to CC.  If eventually successful, run ACTION-IF-AVAILABLE,
+# else ACTION-IF-UNAVAILABLE.
+AC_DEFUN([_AC_C_STD_TRY],
+[AC_MSG_CHECKING([for $CC option to accept ISO ]m4_translit($1, [c], [C]))
+AC_CACHE_VAL(ac_cv_prog_cc_$1,
+[ac_cv_prog_cc_$1=no
+ac_save_CC=$CC
+AC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])])
+for ac_arg in '' $4
+do
+  CC="$ac_save_CC $ac_arg"
+  _AC_COMPILE_IFELSE([], [ac_cv_prog_cc_$1=$ac_arg])
+  test "x$ac_cv_prog_cc_$1" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+])# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_$1" in
+  x)
+    AC_MSG_RESULT([none needed]) ;;
+  xno)
+    AC_MSG_RESULT([unsupported]) ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_$1"
+    AC_MSG_RESULT([$ac_cv_prog_cc_$1]) ;;
+esac
+AS_IF([test "x$ac_cv_prog_cc_$1" != xno], [$5], [$6])
+])# _AC_C_STD_TRY
+
+# _AC_PROG_CC_C99 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])
+# ----------------------------------------------------------------
+# If the C compiler is not in ISO C99 mode by default, try to add an
+# option to output variable CC to make it so.  This macro tries
+# various options that select ISO C99 on some system or another.  It
+# considers the compiler to be in ISO C99 mode if it handles mixed
+# code and declarations, _Bool, inline and restrict.
+AC_DEFUN([_AC_PROG_CC_C99],
+[_AC_C_STD_TRY([c99],
+[[#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+struct incomplete_array
+{
+  int datasize;
+  double data[];
+};
+
+struct named_init {
+  int number;
+  const wchar_t *name;
+  double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict(ccp restrict text)
+{
+  // See if C++-style comments work.
+  // Iterate through items via the restricted pointer.
+  // Also check for declarations in for loops.
+  for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+    continue;
+  return 0;
+}
+
+// Check varargs and va_copy work.
+static void
+test_varargs(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  va_list args_copy;
+  va_copy(args_copy, args);
+
+  const char *str;
+  int number;
+  float fnumber;
+
+  while (*format)
+    {
+      switch (*format++)
+	{
+	case 's': // string
+	  str = va_arg(args_copy, const char *);
+	  break;
+	case 'd': // int
+	  number = va_arg(args_copy, int);
+	  break;
+	case 'f': // float
+	  fnumber = (float) va_arg(args_copy, double);
+	  break;
+	default:
+	  break;
+	}
+    }
+  va_end(args_copy);
+  va_end(args);
+}
+]],
+[[
+  // Check bool and long long datatypes.
+  _Bool success = false;
+  long long int bignum = -1234567890LL;
+  unsigned long long int ubignum = 1234567890uLL;
+
+  // Check restrict.
+  if (test_restrict("String literal") != 0)
+    success = true;
+  char *restrict newvar = "Another string";
+
+  // Check varargs.
+  test_varargs("s, d' f .", "string", 65, 34.234);
+
+  // Check incomplete arrays work.
+  struct incomplete_array *ia =
+    malloc(sizeof(struct incomplete_array) + (sizeof(double) * 10));
+  ia->datasize = 10;
+  for (int i = 0; i < ia->datasize; ++i)
+    ia->data[i] = (double) i * 1.234;
+
+  // Check named initialisers.
+  struct named_init ni = {
+    .number = 34,
+    .name = L"Test wide string",
+    .average = 543.34343,
+  };
+
+  ni.number = 58;
+
+  int dynamic_array[ni.number];
+  dynamic_array[43] = 543;
+
+  // work around unused variable warnings
+  return  bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x';
+]],
+dnl Try
+dnl GCC		-std=gnu99 (unused restrictive modes: -std=c99 -std=iso9899:1999)
+dnl AIX		-qlanglvl=extc99 (unused restrictive mode: -qlanglvl=stdc99)
+dnl Intel ICC	-c99
+dnl IRIX	-c99
+dnl Solaris	(unused because it causes the compiler to assume C99 semantics for
+dnl		library functions, and this is invalid before Solaris 10: -xc99)
+dnl Tru64	-c99
+dnl with extended modes being tried first.
+[[-std=gnu99 -c99 -qlanglvl=extc99]], [$1], [$2])[]dnl
+])# _AC_PROG_CC_C99
+
+# AC_PROG_CC_C99
+# --------------
+AC_DEFUN([AC_PROG_CC_C99],
+[ AC_REQUIRE([AC_PROG_CC])dnl
+  _AC_PROG_CC_C99
+])
+
+# AC_USE_SYSTEM_EXTENSIONS
+# ------------------------
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+m4_ifndef([AC_USE_SYSTEM_EXTENSIONS],[
+AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS],
+[
+  AC_BEFORE([$0], [AC_COMPILE_IFELSE])
+  AC_BEFORE([$0], [AC_RUN_IFELSE])
+
+  AC_REQUIRE([AC_GNU_SOURCE])
+  AC_REQUIRE([AC_AIX])
+  AC_REQUIRE([AC_MINIX])
+
+  AH_VERBATIM([__EXTENSIONS__],
+[/* Enable extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif])
+  AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
+    [ac_cv_safe_to_define___extensions__],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM([
+#	  define __EXTENSIONS__ 1
+	  AC_INCLUDES_DEFAULT])],
+       [ac_cv_safe_to_define___extensions__=yes],
+       [ac_cv_safe_to_define___extensions__=no])])
+  test $ac_cv_safe_to_define___extensions__ = yes &&
+    AC_DEFINE([__EXTENSIONS__])
+  AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+])
+])

Added: branches/ctdb/squeeze-backports/lib/replace/autogen.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/autogen.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/autogen.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+autoheader || exit 1
+autoconf || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/lib/replace/autogen.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/replace/config.guess
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/config.guess	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/config.guess	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1533 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-06-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd | genuineintel)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel at ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/lib/replace/config.guess
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/replace/config.h.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/config.h.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/config.h.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,690 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Whether strndup is broken */
+#undef BROKEN_STRNDUP
+
+/* Whether strnlen is broken */
+#undef BROKEN_STRNLEN
+
+/* Define to 1 if you have the <acl/libacl.h> header file. */
+#undef HAVE_ACL_LIBACL_H
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Whether the bool type is available */
+#undef HAVE_BOOL
+
+/* Define to 1 if you have the `bzero' function. */
+#undef HAVE_BZERO
+
+/* Whether there is a C99 compliant vsnprintf */
+#undef HAVE_C99_VSNPRINTF
+
+/* Define to 1 if you have the `chroot' function. */
+#undef HAVE_CHROOT
+
+/* Define to 1 if you have the `chsize' function. */
+#undef HAVE_CHSIZE
+
+/* Whether or not we have comparison_fn_t */
+#undef HAVE_COMPARISON_FN_T
+
+/* Define to 1 if you have the <compat.h> header file. */
+#undef HAVE_COMPAT_H
+
+/* Define to 1 if you have the <ctype.h> header file. */
+#undef HAVE_CTYPE_H
+
+/* Define to 1 if you have the declaration of `asprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_ASPRINTF
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SNPRINTF
+
+/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VASPRINTF
+
+/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VSNPRINTF
+
+/* Define to 1 if you have the <direct.h> header file. */
+#undef HAVE_DIRECT_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dlclose' function. */
+#undef HAVE_DLCLOSE
+
+/* Define to 1 if you have the `dlerror' function. */
+#undef HAVE_DLERROR
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `dlopen' function. */
+#undef HAVE_DLOPEN
+
+/* Define to 1 if you have the `dlsym' function. */
+#undef HAVE_DLSYM
+
+/* Whether errno() is available */
+#undef HAVE_ERRNO_DECL
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <fnmatch.h> header file. */
+#undef HAVE_FNMATCH_H
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Whether there is a __FUNCTION__ macro */
+#undef HAVE_FUNCTION_MACRO
+
+/* Define to 1 if you have the `getdents' function. */
+#undef HAVE_GETDENTS
+
+/* Define to 1 if you have the `getdirentries' function. */
+#undef HAVE_GETDIRENTRIES
+
+/* Define to 1 if you have the `getpgrp' function. */
+#undef HAVE_GETPGRP
+
+/* Define to 1 if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Whether the compiler supports immediate structures */
+#undef HAVE_IMMEDIATE_STRUCTURES
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the `memcpy' function. */
+#undef HAVE_MEMCPY
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define if target mkdir supports mode option */
+#undef HAVE_MKDIR_MODE
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#undef HAVE_MKDTEMP
+
+/* Define to 1 if you have the `mktime' function. */
+#undef HAVE_MKTIME
+
+/* Whether mmap works */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/in_ip.h> header file. */
+#undef HAVE_NETINET_IN_IP_H
+
+/* Define to 1 if you have the <netinet/in_systm.h> header file. */
+#undef HAVE_NETINET_IN_SYSTM_H
+
+/* Define to 1 if you have the <netinet/ip.h> header file. */
+#undef HAVE_NETINET_IP_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* usability of net/if.h */
+#undef HAVE_NET_IF_H
+
+/* Whether the open(2) accepts O_DIRECT */
+#undef HAVE_OPEN_O_DIRECT
+
+/* Define to 1 if you have the `pipe' function. */
+#undef HAVE_PIPE
+
+/* Define to 1 if you have the `pread' function. */
+#undef HAVE_PREAD
+
+/* Define to 1 if you have the `printf' function. */
+#undef HAVE_PRINTF
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define to 1 if you have the `pwrite' function. */
+#undef HAVE_PWRITE
+
+/* Define to 1 if you have the `rand' function. */
+#undef HAVE_RAND
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have the `rename' function. */
+#undef HAVE_RENAME
+
+/* Whether mkstemp is secure */
+#undef HAVE_SECURE_MKSTEMP
+
+/* Define to 1 if you have the `setbuffer' function. */
+#undef HAVE_SETBUFFER
+
+/* Define to 1 if you have the `setegid' function. */
+#undef HAVE_SETEGID
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Whether setenv() is available */
+#undef HAVE_SETENV_DECL
+
+/* Define to 1 if you have the `seteuid' function. */
+#undef HAVE_SETEUID
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#undef HAVE_SETJMP_H
+
+/* Define to 1 if you have the `setlinebuf' function. */
+#undef HAVE_SETLINEBUF
+
+/* Define to 1 if you have the `setresgid' function. */
+#undef HAVE_SETRESGID
+
+/* Whether setresgid() is available */
+#undef HAVE_SETRESGID_DECL
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Whether setresuid() is available */
+#undef HAVE_SETRESUID_DECL
+
+/* Define to 1 if you have the <shadow.h> header file. */
+#undef HAVE_SHADOW_H
+
+/* Whether we have the atomic_t variable type */
+#undef HAVE_SIG_ATOMIC_T_TYPE
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define to 1 if you have the `srand' function. */
+#undef HAVE_SRAND
+
+/* Define to 1 if you have the `srandom' function. */
+#undef HAVE_SRANDOM
+
+/* Define to 1 if you have the <standards.h> header file. */
+#undef HAVE_STANDARDS_H
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasestr' function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
+/* Define to 1 if you have the `strnlen' function. */
+#undef HAVE_STRNLEN
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define to 1 if you have the `strtoq' function. */
+#undef HAVE_STRTOQ
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define to 1 if you have the `strtouq' function. */
+#undef HAVE_STRTOUQ
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_RDEV
+
+/* Define to 1 if your `struct stat' has `st_rdev'. Deprecated, use
+   `HAVE_STRUCT_STAT_ST_RDEV' instead. */
+#undef HAVE_ST_RDEV
+
+/* Define to 1 if you have the `syslog' function. */
+#undef HAVE_SYSLOG
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/acl.h> header file. */
+#undef HAVE_SYS_ACL_H
+
+/* Define to 1 if you have the <sys/capability.h> header file. */
+#undef HAVE_SYS_CAPABILITY_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/fcntl.h> header file. */
+#undef HAVE_SYS_FCNTL_H
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/filsys.h> header file. */
+#undef HAVE_SYS_FILSYS_H
+
+/* Define to 1 if you have the <sys/fs/s5param.h> header file. */
+#undef HAVE_SYS_FS_S5PARAM_H
+
+/* Define to 1 if you have the <sys/id.h> header file. */
+#undef HAVE_SYS_ID_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#undef HAVE_SYS_IPC_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/mode.h> header file. */
+#undef HAVE_SYS_MODE_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/priv.h> header file. */
+#undef HAVE_SYS_PRIV_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/security.h> header file. */
+#undef HAVE_SYS_SECURITY_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+#undef HAVE_SYS_SHM_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syslog.h> header file. */
+#undef HAVE_SYS_SYSLOG_H
+
+/* Define to 1 if you have the <sys/termio.h> header file. */
+#undef HAVE_SYS_TERMIO_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define to 1 if you have the `timegm' function. */
+#undef HAVE_TIMEGM
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define to 1 if you have the `usleep' function. */
+#undef HAVE_USLEEP
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if you have the <vararg.h> header file. */
+#undef HAVE_VARARG_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Whether va_copy() is available */
+#undef HAVE_VA_COPY
+
+/* Whether the C compiler understands volatile */
+#undef HAVE_VOLATILE
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `vsyslog' function. */
+#undef HAVE_VSYSLOG
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+#undef HAVE_WS2TCPIP_H
+
+/* Whether the _Bool type is available */
+#undef HAVE__Bool
+
+/* Whether the __VA_ARGS__ macro is available */
+#undef HAVE__VA_ARGS__MACRO
+
+/* Define to 1 if you have the `__strtoll' function. */
+#undef HAVE___STRTOLL
+
+/* Define to 1 if you have the `__strtoull' function. */
+#undef HAVE___STRTOULL
+
+/* Whether __va_copy() is available */
+#undef HAVE___VA_COPY
+
+/* Whether there is a __func__ macro */
+#undef HAVE_func_MACRO
+
+/* Whether MMAP is broken */
+#undef MMAP_BLACKLIST
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Whether getpass should be replaced */
+#undef REPLACE_GETPASS
+
+/* Whether inet_ntoa should be replaced */
+#undef REPLACE_INET_NTOA
+
+/* replace readdir */
+#undef REPLACE_READDIR
+
+/* replace readdir using getdents() */
+#undef REPLACE_READDIR_GETDENTS
+
+/* replace readdir using getdirentries() */
+#undef REPLACE_READDIR_GETDIRENTRIES
+
+/* Whether strptime should be replaced */
+#undef REPLACE_STRPTIME
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Whether seekdir returns an int */
+#undef SEEKDIR_RETURNS_INT
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `off_t', as computed by sizeof. */
+#undef SIZEOF_OFF_T
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of `ssize_t', as computed by sizeof. */
+#undef SIZEOF_SSIZE_T
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Whether telldir takes a const pointer */
+#undef TELLDIR_TAKES_CONST_DIR
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+#ifndef _OSF_SOURCE
+# define _OSF_SOURCE 1
+#endif
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Whether to enable POSIX support */
+#undef _POSIX_C_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Whether to enable System V compatibility */
+#undef _SYSV
+
+#ifndef _XOPEN_SOURCE_EXTENDED
+# define _XOPEN_SOURCE_EXTENDED 1
+#endif
+
+/* Enable extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef ino_t
+
+/* Define to `short' if <sys/types.h> does not define. */
+#undef int16_t
+
+/* Define to `long' if <sys/types.h> does not define. */
+#undef int32_t
+
+/* Define to `long long' if <sys/types.h> does not define. */
+#undef int64_t
+
+/* Define to `char' if <sys/types.h> does not define. */
+#undef int8_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef intptr_t
+
+/* Define to `off_t' if <sys/types.h> does not define. */
+#undef loff_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef mode_t
+
+/* Define to `long int' if <sys/types.h> does not define. */
+#undef off_t
+
+/* Define to `loff_t' if <sys/types.h> does not define. */
+#undef offset_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef ptrdiff_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Socket length type */
+#undef socklen_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to `unsigned short' if <sys/types.h> does not define. */
+#undef uint16_t
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#undef uint32_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef uint64_t
+
+/* Define to `unsigned char' if <sys/types.h> does not define. */
+#undef uint8_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef uint_t

Added: branches/ctdb/squeeze-backports/lib/replace/config.sub
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/config.sub	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/config.sub	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1693 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-06-11'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray)
+		os=
+		basic_machine=$1
+		;;
+        -bluegene*)
+	        os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/lib/replace/config.sub
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/replace/configure.ac
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/configure.ac	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/configure.ac	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,24 @@
+AC_PREREQ(2.50)
+AC_INIT(replace.c)
+AC_CONFIG_SRCDIR([replace.c])
+AC_CONFIG_HEADER(config.h)
+
+AC_LIBREPLACE_ALL_CHECKS
+
+if test "$ac_cv_prog_gcc" = yes; then
+   CFLAGS="$CFLAGS -Wall"
+   CFLAGS="$CFLAGS -W"
+   CFLAGS="$CFLAGS -Wshadow"
+   CFLAGS="$CFLAGS -Wstrict-prototypes"
+   CFLAGS="$CFLAGS -Wpointer-arith"
+   CFLAGS="$CFLAGS -Wcast-qual"
+   CFLAGS="$CFLAGS -Wcast-align"
+   CFLAGS="$CFLAGS -Wwrite-strings"
+   CFLAGS="$CFLAGS -Werror-implicit-function-declaration"
+   CFLAGS="$CFLAGS -Wformat=2"
+   CFLAGS="$CFLAGS -Wno-format-y2k"
+fi
+
+AC_SUBST(LDFLAGS)
+
+AC_OUTPUT(Makefile)

Added: branches/ctdb/squeeze-backports/lib/replace/dlfcn.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/dlfcn.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/dlfcn.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,73 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Samba system utilities
+   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Jeremy Allison 1998-2002
+
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#ifdef HAVE_DL_H
+#include <dl.h>
+#endif
+
+#ifndef HAVE_DLOPEN
+#ifdef DLOPEN_TAKES_UNSIGNED_FLAGS
+void *rep_dlopen(const char *name, unsigned int flags)
+#else
+void *rep_dlopen(const char *name, int flags)
+#endif
+{
+#ifdef HAVE_SHL_LOAD
+	return (void *)shl_load(name, flags, 0);
+#else
+	return NULL;
+#endif
+}
+#endif
+
+#ifndef HAVE_DLSYM
+void *rep_dlsym(void *handle, const char *symbol)
+{
+#ifdef HAVE_SHL_FINDSYM
+	void *sym_addr;
+	if (!shl_findsym((shl_t *)&handle, symbol, TYPE_UNDEFINED, &sym_addr))
+		return sym_addr;
+#endif
+    return NULL;
+}
+#endif
+
+#ifndef HAVE_DLERROR
+char *rep_dlerror(void)
+{
+	return "dynamic loading of objects not supported on this platform";
+}
+#endif
+
+#ifndef HAVE_DLCLOSE
+int rep_dlclose(void *handle)
+{
+#ifdef HAVE_SHL_CLOSE
+	return shl_unload((shl_t)handle);
+#else
+	return 0;
+#endif
+}
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/dlfcn.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/dlfcn.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/dlfcn.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+dnl dummies provided by dlfcn.c if not available
+save_LIBS="$LIBS"
+LIBS=""
+
+libreplace_cv_dlfcn=no
+AC_SEARCH_LIBS(dlopen, dl)
+
+AC_CHECK_HEADERS(dlfcn.h)
+AC_CHECK_FUNCS([dlopen dlsym dlerror dlclose],[],[libreplace_cv_dlfcn=yes])
+
+libreplace_cv_shl=no
+AC_SEARCH_LIBS(shl_load, sl)
+AC_CHECK_HEADERS(dl.h)
+AC_CHECK_FUNCS([shl_load shl_unload shl_findsym],[],[libreplace_cv_shl=yes])
+
+AC_VERIFY_C_PROTOTYPE([void *dlopen(const char* filename, unsigned int flags)],
+	[
+	return 0;
+	],[
+	AC_DEFINE(DLOPEN_TAKES_UNSIGNED_FLAGS, 1, [Whether dlopen takes unsigned int flags])
+	],[],[
+	#include <dlfcn.h>
+	])
+
+if test x"${libreplace_cv_dlfcn}" = x"yes";then
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} dlfcn.o"
+fi
+
+LIBDL="$LIBS"
+AC_SUBST(LIBDL)
+LIBS="$save_LIBS"

Added: branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,497 @@
+/*
+PostgreSQL Database Management System
+(formerly known as Postgres, then as Postgres95)
+
+Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
+
+Portions Copyright (c) 1994, The Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this paragraph
+and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+*/
+
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.c
+ *	  Support getaddrinfo() on platforms that don't have it.
+ *
+ * We also supply getnameinfo() here, assuming that the platform will have
+ * it if and only if it has getaddrinfo().	If this proves false on some
+ * platform, we'll need to split this file and provide a separate configure
+ * test for getnameinfo().
+ *
+ * Copyright (c) 2003-2007, PostgreSQL Global Development Group
+ *
+ * Copyright (C) 2007 Jeremy Allison.
+ * Modified to return multiple IPv4 addresses for Samba.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+#ifndef SMB_MALLOC
+#define SMB_MALLOC(s) malloc(s)
+#endif
+
+#ifndef SMB_STRDUP
+#define SMB_STRDUP(s) strdup(s)
+#endif
+
+static int check_hostent_err(struct hostent *hp)
+{
+	if (!hp) {
+		switch (h_errno) {
+			case HOST_NOT_FOUND:
+			case NO_DATA:
+				return EAI_NONAME;
+			case TRY_AGAIN:
+				return EAI_AGAIN;
+			case NO_RECOVERY:
+			default:
+				return EAI_FAIL;
+		}
+	}
+	if (!hp->h_name || hp->h_addrtype != AF_INET) {
+		return EAI_FAIL;
+	}
+	return 0;
+}
+
+static char *canon_name_from_hostent(struct hostent *hp,
+				int *perr)
+{
+	char *ret = NULL;
+
+	*perr = check_hostent_err(hp);
+	if (*perr) {
+		return NULL;
+	}
+	ret = SMB_STRDUP(hp->h_name);
+	if (!ret) {
+		*perr = EAI_MEMORY;
+	}
+	return ret;
+}
+
+static char *get_my_canon_name(int *perr)
+{
+	char name[HOST_NAME_MAX+1];
+
+	if (gethostname(name, HOST_NAME_MAX) == -1) {
+		*perr = EAI_FAIL;
+		return NULL;
+	}
+	/* Ensure null termination. */
+	name[HOST_NAME_MAX] = '\0';
+	return canon_name_from_hostent(gethostbyname(name), perr);
+}
+
+static char *get_canon_name_from_addr(struct in_addr ip,
+				int *perr)
+{
+	return canon_name_from_hostent(
+			gethostbyaddr(&ip, sizeof(ip), AF_INET),
+			perr);
+}
+
+static struct addrinfo *alloc_entry(const struct addrinfo *hints,
+				struct in_addr ip,
+				unsigned short port)
+{
+	struct sockaddr_in *psin = NULL;
+	struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
+
+	if (!ai) {
+		return NULL;
+	}
+	memset(ai, '\0', sizeof(*ai));
+
+	psin = SMB_MALLOC(sizeof(*psin));
+	if (!psin) {
+		free(ai);
+		return NULL;
+	}
+
+	memset(psin, '\0', sizeof(*psin));
+
+	psin->sin_family = AF_INET;
+	psin->sin_port = htons(port);
+	psin->sin_addr = ip;
+
+	ai->ai_flags = 0;
+	ai->ai_family = AF_INET;
+	ai->ai_socktype = hints->ai_socktype;
+	ai->ai_protocol = hints->ai_protocol;
+	ai->ai_addrlen = sizeof(*psin);
+	ai->ai_addr = (struct sockaddr *) psin;
+	ai->ai_canonname = NULL;
+	ai->ai_next = NULL;
+
+	return ai;
+}
+
+/*
+ * get address info for a single ipv4 address.
+ *
+ *	Bugs:	- servname can only be a number, not text.
+ */
+
+static int getaddr_info_single_addr(const char *service,
+				uint32_t addr,
+				const struct addrinfo *hints,
+				struct addrinfo **res)
+{
+
+	struct addrinfo *ai = NULL;
+	struct in_addr ip;
+	unsigned short port = 0;
+
+	if (service) {
+		port = (unsigned short)atoi(service);
+	}
+	ip.s_addr = htonl(addr);
+
+	ai = alloc_entry(hints, ip, port);
+	if (!ai) {
+		return EAI_MEMORY;
+	}
+
+	/* If we're asked for the canonical name,
+	 * make sure it returns correctly. */
+	if (!(hints->ai_flags & AI_NUMERICSERV) &&
+			hints->ai_flags & AI_CANONNAME) {
+		int err;
+		if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
+			ai->ai_canonname = get_my_canon_name(&err);
+		} else {
+			ai->ai_canonname =
+			get_canon_name_from_addr(ip,&err);
+		}
+		if (ai->ai_canonname == NULL) {
+			freeaddrinfo(ai);
+			return err;
+		}
+	}
+
+	*res = ai;
+	return 0;
+}
+
+/*
+ * get address info for multiple ipv4 addresses.
+ *
+ *	Bugs:	- servname can only be a number, not text.
+ */
+
+static int getaddr_info_name(const char *node,
+				const char *service,
+				const struct addrinfo *hints,
+				struct addrinfo **res)
+{
+	struct addrinfo *listp = NULL, *prevp = NULL;
+	char **pptr = NULL;
+	int err;
+	struct hostent *hp = NULL;
+	unsigned short port = 0;
+
+	if (service) {
+		port = (unsigned short)atoi(service);
+	}
+
+	hp = gethostbyname(node);
+	err = check_hostent_err(hp);
+	if (err) {
+		return err;
+	}
+
+	for(pptr = hp->h_addr_list; *pptr; pptr++) {
+		struct in_addr ip = *(struct in_addr *)*pptr;
+		struct addrinfo *ai = alloc_entry(hints, ip, port);
+
+		if (!ai) {
+			freeaddrinfo(listp);
+			return EAI_MEMORY;
+		}
+
+		if (!listp) {
+			listp = ai;
+			prevp = ai;
+			ai->ai_canonname = SMB_STRDUP(hp->h_name);
+			if (!ai->ai_canonname) {
+				freeaddrinfo(listp);
+				return EAI_MEMORY;
+			}
+		} else {
+			prevp->ai_next = ai;
+			prevp = ai;
+		}
+	}
+	*res = listp;
+	return 0;
+}
+
+/*
+ * get address info for ipv4 sockets.
+ *
+ *	Bugs:	- servname can only be a number, not text.
+ */
+
+int rep_getaddrinfo(const char *node,
+		const char *service,
+		const struct addrinfo * hintp,
+		struct addrinfo ** res)
+{
+	struct addrinfo hints;
+
+	/* Setup the hints struct. */
+	if (hintp == NULL) {
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = AF_INET;
+		hints.ai_socktype = SOCK_STREAM;
+	} else {
+		memcpy(&hints, hintp, sizeof(hints));
+	}
+
+	if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
+		return EAI_FAMILY;
+	}
+
+	if (hints.ai_socktype == 0) {
+		hints.ai_socktype = SOCK_STREAM;
+	}
+
+	if (!node && !service) {
+		return EAI_NONAME;
+	}
+
+	if (node) {
+		if (node[0] == '\0') {
+			return getaddr_info_single_addr(service,
+					INADDR_ANY,
+					&hints,
+					res);
+		} else if (hints.ai_flags & AI_NUMERICHOST) {
+			struct in_addr ip;
+			if (!inet_aton(node, &ip)) {
+				return EAI_FAIL;
+			}
+			return getaddr_info_single_addr(service,
+					ntohl(ip.s_addr),
+					&hints,
+					res);
+		} else {
+			return getaddr_info_name(node,
+						service,
+						&hints,
+						res);
+		}
+	} else if (hints.ai_flags & AI_PASSIVE) {
+		return getaddr_info_single_addr(service,
+					INADDR_ANY,
+					&hints,
+					res);
+	}
+	return getaddr_info_single_addr(service,
+					INADDR_LOOPBACK,
+					&hints,
+					res);
+}
+
+
+void rep_freeaddrinfo(struct addrinfo *res)
+{
+	struct addrinfo *next = NULL;
+
+	for (;res; res = next) {
+		next = res->ai_next;
+		if (res->ai_canonname) {
+			free(res->ai_canonname);
+		}
+		if (res->ai_addr) {
+			free(res->ai_addr);
+		}
+		free(res);
+	}
+}
+
+
+const char *rep_gai_strerror(int errcode)
+{
+#ifdef HAVE_HSTRERROR
+	int			hcode;
+
+	switch (errcode)
+	{
+		case EAI_NONAME:
+			hcode = HOST_NOT_FOUND;
+			break;
+		case EAI_AGAIN:
+			hcode = TRY_AGAIN;
+			break;
+		case EAI_FAIL:
+		default:
+			hcode = NO_RECOVERY;
+			break;
+	}
+
+	return hstrerror(hcode);
+#else							/* !HAVE_HSTRERROR */
+
+	switch (errcode)
+	{
+		case EAI_NONAME:
+			return "Unknown host";
+		case EAI_AGAIN:
+			return "Host name lookup failure";
+#ifdef EAI_BADFLAGS
+		case EAI_BADFLAGS:
+			return "Invalid argument";
+#endif
+#ifdef EAI_FAMILY
+		case EAI_FAMILY:
+			return "Address family not supported";
+#endif
+#ifdef EAI_MEMORY
+		case EAI_MEMORY:
+			return "Not enough memory";
+#endif
+#ifdef EAI_NODATA
+		case EAI_NODATA:
+			return "No host data of that type was found";
+#endif
+#ifdef EAI_SERVICE
+		case EAI_SERVICE:
+			return "Class type not found";
+#endif
+#ifdef EAI_SOCKTYPE
+		case EAI_SOCKTYPE:
+			return "Socket type not supported";
+#endif
+		default:
+			return "Unknown server error";
+	}
+#endif   /* HAVE_HSTRERROR */
+}
+
+static int gethostnameinfo(const struct sockaddr *sa,
+			char *node,
+			size_t nodelen,
+			int flags)
+{
+	int ret = -1;
+	char *p = NULL;
+
+	if (!(flags & NI_NUMERICHOST)) {
+		struct hostent *hp = gethostbyaddr(
+				&((struct sockaddr_in *)sa)->sin_addr,
+				sizeof(struct in_addr),
+				sa->sa_family);
+		ret = check_hostent_err(hp);
+		if (ret == 0) {
+			/* Name looked up successfully. */
+			ret = snprintf(node, nodelen, "%s", hp->h_name);
+			if (ret < 0 || (size_t)ret >= nodelen) {
+				return EAI_MEMORY;
+			}
+			if (flags & NI_NOFQDN) {
+				p = strchr(node,'.');
+				if (p) {
+					*p = '\0';
+				}
+			}
+			return 0;
+		}
+
+		if (flags & NI_NAMEREQD) {
+			/* If we require a name and didn't get one,
+			 * automatically fail. */
+			return ret;
+		}
+		/* Otherwise just fall into the numeric host code... */
+	}
+	p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
+	ret = snprintf(node, nodelen, "%s", p);
+	if (ret < 0 || (size_t)ret >= nodelen) {
+		return EAI_MEMORY;
+	}
+	return 0;
+}
+
+static int getservicenameinfo(const struct sockaddr *sa,
+			char *service,
+			size_t servicelen,
+			int flags)
+{
+	int ret = -1;
+	int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+
+	if (!(flags & NI_NUMERICSERV)) {
+		struct servent *se = getservbyport(
+				port,
+				(flags & NI_DGRAM) ? "udp" : "tcp");
+		if (se && se->s_name) {
+			/* Service name looked up successfully. */
+			ret = snprintf(service, servicelen, "%s", se->s_name);
+			if (ret < 0 || (size_t)ret >= servicelen) {
+				return EAI_MEMORY;
+			}
+			return 0;
+		}
+		/* Otherwise just fall into the numeric service code... */
+	}
+	ret = snprintf(service, servicelen, "%d", port);
+	if (ret < 0 || (size_t)ret >= servicelen) {
+		return EAI_MEMORY;
+	}
+	return 0;
+}
+
+/*
+ * Convert an ipv4 address to a hostname.
+ *
+ * Bugs:	- No IPv6 support.
+ */
+int rep_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+			char *node, size_t nodelen,
+			char *service, size_t servicelen, int flags)
+{
+
+	/* Invalid arguments. */
+	if (sa == NULL || (node == NULL && service == NULL)) {
+		return EAI_FAIL;
+	}
+
+	if (sa->sa_family != AF_INET) {
+		return EAI_FAIL;
+	}
+
+	if (salen < sizeof(struct sockaddr_in)) {
+		return EAI_FAIL;
+	}
+
+	if (node) {
+		return gethostnameinfo(sa, node, nodelen, flags);
+	}
+
+	if (service) {
+		return getservicenameinfo(sa, service, servicelen, flags);
+	}
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,89 @@
+/*
+PostgreSQL Database Management System
+(formerly known as Postgres, then as Postgres95)
+
+Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
+
+Portions Copyright (c) 1994, The Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this paragraph
+and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+*/
+
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.h
+ *	  Support getaddrinfo() on platforms that don't have it.
+ *
+ * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO,
+ * whether or not the library routine getaddrinfo() can be found.  This
+ * policy is needed because on some platforms a manually installed libbind.a
+ * may provide getaddrinfo(), yet the system headers may not provide the
+ * struct definitions needed to call it.  To avoid conflict with the libbind
+ * definition in such cases, we rename our routines to pg_xxx() via macros.
+ *
+
+in lib/replace we use rep_xxx()
+
+ * This code will also work on platforms where struct addrinfo is defined
+ * in the system headers but no getaddrinfo() can be located.
+ *
+ * Copyright (c) 2003-2007, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef GETADDRINFO_H
+#define GETADDRINFO_H
+
+#ifndef HAVE_GETADDRINFO
+
+/* Rename private copies per comments above */
+#ifdef getaddrinfo
+#undef getaddrinfo
+#endif
+#define getaddrinfo rep_getaddrinfo
+#define HAVE_GETADDRINFO
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
+#define freeaddrinfo rep_freeaddrinfo
+#define HAVE_FREEADDRINFO
+
+#ifdef gai_strerror
+#undef gai_strerror
+#endif
+#define gai_strerror rep_gai_strerror
+#define HAVE_GAI_STRERROR
+
+#ifdef getnameinfo
+#undef getnameinfo
+#endif
+#define getnameinfo rep_getnameinfo
+#define HAVE_GETNAMEINFO
+
+extern int rep_getaddrinfo(const char *node, const char *service,
+			const struct addrinfo * hints, struct addrinfo ** res);
+extern void rep_freeaddrinfo(struct addrinfo * res);
+extern const char *rep_gai_strerror(int errcode);
+extern int rep_getnameinfo(const struct sockaddr * sa, socklen_t salen,
+			char *node, size_t nodelen,
+			char *service, size_t servicelen, int flags);
+#endif   /* HAVE_GETADDRINFO */
+
+#endif   /* GETADDRINFO_H */

Added: branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/getaddrinfo.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,32 @@
+dnl test for getaddrinfo/getnameinfo
+AC_CACHE_CHECK([for getaddrinfo],libreplace_cv_HAVE_GETADDRINFO,[
+AC_TRY_LINK([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <sys/socket.h>
+#include <netdb.h>],
+[
+struct sockaddr sa;
+struct addrinfo *ai = NULL;
+int ret = getaddrinfo(NULL, NULL, NULL, &ai);
+if (ret != 0) {
+	const char *es = gai_strerror(ret);
+}
+freeaddrinfo(ai);
+ret = getnameinfo(&sa, sizeof(sa),
+		NULL, 0,
+		NULL, 0, 0);
+
+],
+libreplace_cv_HAVE_GETADDRINFO=yes,libreplace_cv_HAVE_GETADDRINFO=no)])
+if test x"$libreplace_cv_HAVE_GETADDRINFO" = x"yes"; then
+	AC_DEFINE(HAVE_GETADDRINFO,1,[Whether the system has getaddrinfo])
+	AC_DEFINE(HAVE_GETNAMEINFO,1,[Whether the system has getnameinfo])
+	AC_DEFINE(HAVE_FREEADDRINFO,1,[Whether the system has freeaddrinfo])
+	AC_DEFINE(HAVE_GAI_STRERROR,1,[Whether the system has gai_strerror])
+else
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} getaddrinfo.o"
+fi

Added: branches/ctdb/squeeze-backports/lib/replace/getifaddrs.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/getifaddrs.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/getifaddrs.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,392 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Samba utility functions
+   Copyright (C) Andrew Tridgell 1998
+   Copyright (C) Jeremy Allison 2007
+   Copyright (C) Jelmer Vernooij <jelmer at samba.org> 2007
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifndef SIOCGIFCONF
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#endif
+
+#ifdef HAVE_IFACE_GETIFADDRS
+#define _FOUND_IFACE_ANY
+#else
+
+void rep_freeifaddrs(struct ifaddrs *ifp)
+{
+	free(ifp->ifa_name);
+	free(ifp->ifa_addr);
+	free(ifp->ifa_netmask);
+	free(ifp->ifa_dstaddr);
+	if (ifp->ifa_next != NULL)
+		freeifaddrs(ifp->ifa_next);
+	free(ifp);
+}
+
+static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
+{
+	struct sockaddr *ret;
+	socklen_t socklen;
+#ifdef HAVE_SOCKADDR_SA_LEN
+	socklen = sa->sa_len;
+#else
+	socklen = sizeof(struct sockaddr_storage);
+#endif
+	ret = calloc(1, socklen);
+	if (ret == NULL)
+		return NULL;
+	memcpy(ret, sa, socklen);
+	return ret;
+}
+#endif
+
+#if HAVE_IFACE_IFCONF
+
+/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
+   V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
+
+   It probably also works on any BSD style system.  */
+
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+	struct ifconf ifc;
+	char buff[8192];
+	int fd, i, n;
+	struct ifreq *ifr=NULL;
+	int total = 0;
+	struct in_addr ipaddr;
+	struct in_addr nmask;
+	char *iname;
+	struct ifaddrs *curif, *lastif;
+
+	*ifap = NULL;
+
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+		return -1;
+	}
+  
+	ifc.ifc_len = sizeof(buff);
+	ifc.ifc_buf = buff;
+
+	if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+		close(fd);
+		return -1;
+	} 
+
+	ifr = ifc.ifc_req;
+  
+	n = ifc.ifc_len / sizeof(struct ifreq);
+
+	/* Loop through interfaces, looking for given IP address */
+	for (i=n-1;i>=0 && total < max_interfaces;i--) {
+		if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
+			freeifaddrs(*ifap);
+		}
+
+		curif = calloc(1, sizeof(struct ifaddrs));
+		if (lastif == NULL) {
+			*ifap = curif;
+		} else {
+			lastif->ifa_next = (*ifap);
+		}
+
+		curif->ifa_name = strdup(ifr[i].ifr_name);
+		curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
+		curif->ifa_dstaddr = NULL;
+		curif->ifa_data = NULL;
+		curif->ifa_next = NULL;
+		curif->ifa_netmask = NULL;
+
+		if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
+			freeifaddrs(*ifap);
+			return -1;
+		}  
+
+		curif->ifa_flags = ifr[i].ifr_flags;
+
+		if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
+			freeifaddrs(*ifap);
+			return -1;
+		}  
+
+		curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
+
+		lastif = curif;
+	}
+
+	close(fd);
+
+	return 0;
+}  
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_IFCONF */
+#ifdef HAVE_IFACE_IFREQ
+
+#ifndef I_STR
+#include <sys/stropts.h>
+#endif
+
+/****************************************************************************
+this should cover most of the streams based systems
+Thanks to Andrej.Borsenkow at mow.siemens.ru for several ideas in this code
+****************************************************************************/
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+	struct ifreq ifreq;
+	struct strioctl strioctl;
+	char buff[8192];
+	int fd, i, n;
+	struct ifreq *ifr=NULL;
+	int total = 0;
+	struct in_addr ipaddr;
+	struct in_addr nmask;
+	char *iname;
+	struct ifaddrs *curif;
+
+	*ifap = NULL;
+
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+		return -1;
+	}
+  
+	strioctl.ic_cmd = SIOCGIFCONF;
+	strioctl.ic_dp  = buff;
+	strioctl.ic_len = sizeof(buff);
+	if (ioctl(fd, I_STR, &strioctl) < 0) {
+		close(fd);
+		return -1;
+	} 
+
+	/* we can ignore the possible sizeof(int) here as the resulting
+	   number of interface structures won't change */
+	n = strioctl.ic_len / sizeof(struct ifreq);
+
+	/* we will assume that the kernel returns the length as an int
+           at the start of the buffer if the offered size is a
+           multiple of the structure size plus an int */
+	if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
+		ifr = (struct ifreq *)(buff + sizeof(int));  
+	} else {
+		ifr = (struct ifreq *)buff;  
+	}
+
+	/* Loop through interfaces */
+
+	for (i = 0; i<n && total < max_interfaces; i++) {
+		ifreq = ifr[i];
+  
+		curif = calloc(1, sizeof(struct ifaddrs));
+		if (lastif == NULL) {
+			*ifap = curif;
+		} else {
+			lastif->ifa_next = (*ifap);
+		}
+
+		strioctl.ic_cmd = SIOCGIFFLAGS;
+		strioctl.ic_dp  = (char *)&ifreq;
+		strioctl.ic_len = sizeof(struct ifreq);
+		if (ioctl(fd, I_STR, &strioctl) != 0) {
+			freeifaddrs(*ifap);
+			return -1;
+		}
+
+		curif->ifa_flags = ifreq.ifr_flags;
+		
+		strioctl.ic_cmd = SIOCGIFADDR;
+		strioctl.ic_dp  = (char *)&ifreq;
+		strioctl.ic_len = sizeof(struct ifreq);
+		if (ioctl(fd, I_STR, &strioctl) != 0) {
+			freeifaddrs(*ifap);
+			return -1;
+		}
+
+		curif->ifa_name = strdup(ifreq.ifr_name);
+		curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
+		curif->ifa_dstaddr = NULL;
+		curif->ifa_data = NULL;
+		curif->ifa_next = NULL;
+		curif->ifa_netmask = NULL;
+
+		strioctl.ic_cmd = SIOCGIFNETMASK;
+		strioctl.ic_dp  = (char *)&ifreq;
+		strioctl.ic_len = sizeof(struct ifreq);
+		if (ioctl(fd, I_STR, &strioctl) != 0) {
+			freeifaddrs(*ifap);
+			return -1;
+		}
+
+		curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
+
+		lastif = curif;
+	}
+
+	close(fd);
+
+	return 0;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_IFREQ */
+#ifdef HAVE_IFACE_AIX
+
+/****************************************************************************
+this one is for AIX (tested on 4.2)
+****************************************************************************/
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+	char buff[8192];
+	int fd, i;
+	struct ifconf ifc;
+	struct ifreq *ifr=NULL;
+	struct in_addr ipaddr;
+	struct in_addr nmask;
+	char *iname;
+	int total = 0;
+	struct ifaddrs *curif, *lastif;
+
+	*ifap = NULL;
+
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+		return -1;
+	}
+
+	ifc.ifc_len = sizeof(buff);
+	ifc.ifc_buf = buff;
+
+	if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+		close(fd);
+		return -1;
+	}
+
+	ifr = ifc.ifc_req;
+
+	/* Loop through interfaces */
+	i = ifc.ifc_len;
+
+	while (i > 0) {
+		uint_t inc;
+
+		inc = ifr->ifr_addr.sa_len;
+
+		if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
+			freeaddrinfo(*ifap);
+			return -1;
+		}
+
+		curif = calloc(1, sizeof(struct ifaddrs));
+		if (lastif == NULL) {
+			*ifap = curif;
+		} else {
+			lastif->ifa_next = (*ifap);
+		}
+
+		curif->ifa_name = strdup(ifr->ifr_name);
+		curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
+		curif->ifa_dstaddr = NULL;
+		curif->ifa_data = NULL;
+		curif->ifa_netmask = NULL;
+		curif->ifa_next = NULL;
+
+		if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
+			freeaddrinfo(*ifap);
+			return -1;
+		}
+
+		curif->ifa_flags = ifr->ifr_flags;
+
+		if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
+			freeaddrinfo(*ifap);
+			return -1;
+		}
+
+		curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
+
+		lastif = curif;
+
+	next:
+		/*
+		 * Patch from Archie Cobbs (archie at whistle.com).  The
+		 * addresses in the SIOCGIFCONF interface list have a
+		 * minimum size. Usually this doesn't matter, but if
+		 * your machine has tunnel interfaces, etc. that have
+		 * a zero length "link address", this does matter.  */
+
+		if (inc < sizeof(ifr->ifr_addr))
+			inc = sizeof(ifr->ifr_addr);
+		inc += IFNAMSIZ;
+
+		ifr = (struct ifreq*) (((char*) ifr) + inc);
+		i -= inc;
+	}
+
+	close(fd);
+	return 0;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_AIX */
+#ifndef _FOUND_IFACE_ANY
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+	errno = ENOSYS;
+	return -1;
+}
+#endif
+
+#ifdef AUTOCONF_TEST
+/* this is the autoconf driver to test get_interfaces() */
+
+ int main()
+{
+	struct ifaddrs *ifs = NULL;
+	int ret;
+	
+	ret = getifaddrs(&ifs);
+	if (ret != 0) {
+		perror("getifaddrs() failed");
+		return 1;
+	}
+
+	while (ifs) {
+		printf("%-10s ", ifs->ifa_name);
+		if (ifs->ifa_addr != NULL && 
+		    ifs->ifa_addr->sa_family == AF_INET) {
+			printf("IP=%s ", inet_ntoa(((struct sockaddr_in *)ifs->ifa_addr)->sin_addr));
+			if (ifs->ifa_netmask != NULL)
+				printf("NETMASK=%s", inet_ntoa(((struct sockaddr_in *)ifs->ifa_netmask)->sin_addr));
+		}
+		printf("\n");
+		ifs = ifs->ifa_next;
+	}
+	return 0;
+}
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/getifaddrs.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/getifaddrs.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/getifaddrs.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,101 @@
+AC_CHECK_HEADERS([ifaddrs.h])
+
+dnl Used when getifaddrs is not available
+AC_CHECK_MEMBERS([struct sockaddr.sa_len], 
+	 [AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1, [Whether struct sockaddr has a sa_len member])],
+	 [],
+	 [#include <sys/socket.h>])
+
+dnl test for getifaddrs and freeifaddrs
+AC_CACHE_CHECK([for getifaddrs and freeifaddrs],samba_cv_HAVE_GETIFADDRS,[
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <netdb.h>],
+[
+struct ifaddrs *ifp = NULL;
+int ret = getifaddrs (&ifp);
+freeifaddrs(ifp);
+],
+samba_cv_HAVE_GETIFADDRS=yes,samba_cv_HAVE_GETIFADDRS=no)])
+if test x"$samba_cv_HAVE_GETIFADDRS" = x"yes"; then
+    AC_DEFINE(HAVE_GETIFADDRS,1,[Whether the system has getifaddrs])
+    AC_DEFINE(HAVE_FREEIFADDRS,1,[Whether the system has freeifaddrs])
+	AC_DEFINE(HAVE_STRUCT_IFADDRS,1,[Whether struct ifaddrs is available])
+fi
+
+##################
+# look for a method of finding the list of network interfaces
+#
+# This tests need LIBS="$NSL_LIBS $SOCKET_LIBS"
+#
+old_LIBS=$LIBS
+LIBS="$NSL_LIBS $SOCKET_LIBS"
+iface=no;
+##################
+# look for a method of finding the list of network interfaces
+iface=no;
+AC_CACHE_CHECK([for iface getifaddrs],samba_cv_HAVE_IFACE_GETIFADDRS,[
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS ${SAMBA_CONFIGURE_CPPFLAGS}"
+AC_TRY_RUN([
+#define NO_CONFIG_H 1
+#define HAVE_IFACE_GETIFADDRS 1
+#define AUTOCONF_TEST 1
+#include "$libreplacedir/replace.c"
+#include "$libreplacedir/getifaddrs.c"],
+           samba_cv_HAVE_IFACE_GETIFADDRS=yes,samba_cv_HAVE_IFACE_GETIFADDRS=no,samba_cv_HAVE_IFACE_GETIFADDRS=cross)])
+CPPFLAGS="$SAVE_CPPFLAGS"
+if test x"$samba_cv_HAVE_IFACE_GETIFADDRS" = x"yes"; then
+    iface=yes;AC_DEFINE(HAVE_IFACE_GETIFADDRS,1,[Whether iface getifaddrs is available])
+else
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} getifaddrs.o"
+fi
+
+
+if test $iface = no; then
+AC_CACHE_CHECK([for iface AIX],samba_cv_HAVE_IFACE_AIX,[
+AC_TRY_RUN([
+#define HAVE_IFACE_AIX 1
+#define AUTOCONF_TEST 1
+#undef _XOPEN_SOURCE_EXTENDED
+#include "$libreplacedir/getifaddrs.c"],
+           samba_cv_HAVE_IFACE_AIX=yes,samba_cv_HAVE_IFACE_AIX=no,samba_cv_HAVE_IFACE_AIX=cross)])
+if test x"$samba_cv_HAVE_IFACE_AIX" = x"yes"; then
+    iface=yes;AC_DEFINE(HAVE_IFACE_AIX,1,[Whether iface AIX is available])
+fi
+fi
+
+
+if test $iface = no; then
+AC_CACHE_CHECK([for iface ifconf],samba_cv_HAVE_IFACE_IFCONF,[
+AC_TRY_RUN([
+#define HAVE_IFACE_IFCONF 1
+#define AUTOCONF_TEST 1
+#include "$libreplacedir/getifaddrs.c"],
+           samba_cv_HAVE_IFACE_IFCONF=yes,samba_cv_HAVE_IFACE_IFCONF=no,samba_cv_HAVE_IFACE_IFCONF=cross)])
+if test x"$samba_cv_HAVE_IFACE_IFCONF" = x"yes"; then
+    iface=yes;AC_DEFINE(HAVE_IFACE_IFCONF,1,[Whether iface ifconf is available])
+fi
+fi
+
+if test $iface = no; then
+AC_CACHE_CHECK([for iface ifreq],samba_cv_HAVE_IFACE_IFREQ,[
+AC_TRY_RUN([
+#define HAVE_IFACE_IFREQ 1
+#define AUTOCONF_TEST 1
+#include "$libreplacedir/getifaddrs.c"],
+           samba_cv_HAVE_IFACE_IFREQ=yes,samba_cv_HAVE_IFACE_IFREQ=no,samba_cv_HAVE_IFACE_IFREQ=cross)])
+if test x"$samba_cv_HAVE_IFACE_IFREQ" = x"yes"; then
+    iface=yes;AC_DEFINE(HAVE_IFACE_IFREQ,1,[Whether iface ifreq is available])
+fi
+fi
+
+LIBS=$old_LIBS

Added: branches/ctdb/squeeze-backports/lib/replace/getpass.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/getpass.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/getpass.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,219 @@
+/* Copyright (C) 1992-1998 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 3 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, see <http://www.gnu.org/licenses/>.  */
+
+/* Modified to use with samba by Jeremy Allison, 8th July 1995. */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "system/terminal.h"
+#include "system/passwd.h"
+
+/*
+ * Define additional missing types
+ */
+#ifndef HAVE_SIG_ATOMIC_T_TYPE
+typedef int sig_atomic_t;
+#endif
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+#ifndef SIGNAL_CAST
+#define SIGNAL_CAST (RETSIGTYPE (*)(int))
+#endif
+
+#ifdef SYSV_TERMIO 
+
+/* SYSTEM V TERMIO HANDLING */
+
+static struct termio t;
+
+#define ECHO_IS_ON(t) ((t).c_lflag & ECHO)
+#define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO)
+#define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO)
+
+#ifndef TCSAFLUSH
+#define TCSAFLUSH 1
+#endif
+
+#ifndef TCSANOW
+#define TCSANOW 0
+#endif
+
+static int tcgetattr(int fd, struct termio *_t)
+{
+	return ioctl(fd, TCGETA, _t);
+}
+
+static int tcsetattr(int fd, int flags, struct termio *_t)
+{
+	if(flags & TCSAFLUSH)
+		ioctl(fd, TCFLSH, TCIOFLUSH);
+	return ioctl(fd, TCSETS, _t);
+}
+
+#elif !defined(TCSAFLUSH)
+
+/* BSD TERMIO HANDLING */
+
+static struct sgttyb t;  
+
+#define ECHO_IS_ON(t) ((t).sg_flags & ECHO)
+#define TURN_ECHO_OFF(t) ((t).sg_flags &= ~ECHO)
+#define TURN_ECHO_ON(t) ((t).sg_flags |= ECHO)
+
+#define TCSAFLUSH 1
+#define TCSANOW 0
+
+static int tcgetattr(int fd, struct sgttyb *_t)
+{
+	return ioctl(fd, TIOCGETP, (char *)_t);
+}
+
+static int tcsetattr(int fd, int flags, struct sgttyb *_t)
+{
+	return ioctl(fd, TIOCSETP, (char *)_t);
+}
+
+#else /* POSIX TERMIO HANDLING */
+#define ECHO_IS_ON(t) ((t).c_lflag & ECHO)
+#define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO)
+#define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO)
+
+static struct termios t;
+#endif /* SYSV_TERMIO */
+
+static void catch_signal(int signum,void (*handler)(int ))
+{
+#ifdef HAVE_SIGACTION
+	struct sigaction act;
+	struct sigaction oldact;
+
+	memset(&act, 0, sizeof(act));
+
+	act.sa_handler = handler;
+#ifdef SA_RESTART
+	/*
+	 * We *want* SIGALRM to interrupt a system call.
+	 */
+	if(signum != SIGALRM)
+		act.sa_flags = SA_RESTART;
+#endif
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask,signum);
+	sigaction(signum,&act,&oldact);
+#else /* !HAVE_SIGACTION */
+	/* FIXME: need to handle sigvec and systems with broken signal() */
+	signal(signum, handler);
+#endif
+}
+
+static sig_atomic_t gotintr;
+static int in_fd = -1;
+
+/***************************************************************
+ Signal function to tell us were ^C'ed.
+****************************************************************/
+
+static void gotintr_sig(void)
+{
+	gotintr = 1;
+	if (in_fd != -1)
+		close(in_fd); /* Safe way to force a return. */
+	in_fd = -1;
+}
+
+char *rep_getpass(const char *prompt)
+{
+	FILE *in, *out;
+	int echo_off;
+	static char buf[256];
+	static size_t bufsize = sizeof(buf);
+	size_t nread;
+
+	/* Catch problematic signals */
+	catch_signal(SIGINT, SIGNAL_CAST gotintr_sig);
+
+	/* Try to write to and read from the terminal if we can.
+		If we can't open the terminal, use stderr and stdin.  */
+
+	in = fopen ("/dev/tty", "w+");
+	if (in == NULL) {
+		in = stdin;
+		out = stderr;
+	} else {
+		out = in;
+	}
+
+	setvbuf(in, NULL, _IONBF, 0);
+
+	/* Turn echoing off if it is on now.  */
+
+	if (tcgetattr (fileno (in), &t) == 0) {
+		if (ECHO_IS_ON(t)) {
+			TURN_ECHO_OFF(t);
+			echo_off = tcsetattr (fileno (in), TCSAFLUSH, &t) == 0;
+			TURN_ECHO_ON(t);
+		} else {
+			echo_off = 0;
+		}
+	} else {
+		echo_off = 0;
+	}
+
+	/* Write the prompt.  */
+	fputs(prompt, out);
+	fflush(out);
+
+	/* Read the password.  */
+	buf[0] = 0;
+	if (!gotintr) {
+		in_fd = fileno(in);
+		fgets(buf, bufsize, in);
+	}
+	nread = strlen(buf);
+	if (nread) {
+		if (buf[nread - 1] == '\n')
+			buf[nread - 1] = '\0';
+	}
+
+	/* Restore echoing.  */
+	if (echo_off) {
+		if (gotintr && in_fd == -1)
+			in = fopen ("/dev/tty", "w+");
+		if (in != NULL)
+			tcsetattr (fileno (in), TCSANOW, &t);
+	}
+
+	fprintf(out, "\n");
+	fflush(out);
+
+	if (in && in != stdin) /* We opened the terminal; now close it.  */
+		fclose(in);
+
+	/* Catch problematic signals */
+	catch_signal(SIGINT, SIGNAL_CAST SIG_DFL);
+
+	if (gotintr) {
+		printf("Interrupted by signal.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	return buf;
+}

Added: branches/ctdb/squeeze-backports/lib/replace/getpass.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/getpass.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/getpass.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+AC_CACHE_CHECK([whether getpass should be replaced],samba_cv_REPLACE_GETPASS,[
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -I$libreplacedir/"
+AC_TRY_COMPILE([
+#include "confdefs.h"
+#define NO_CONFIG_H
+#include "$libreplacedir/getpass.c"
+],[],samba_cv_REPLACE_GETPASS=yes,samba_cv_REPLACE_GETPASS=no)
+CPPFLAGS="$SAVE_CPPFLAGS"
+])
+if test x"$samba_cv_REPLACE_GETPASS" = x"yes"; then
+	AC_DEFINE(REPLACE_GETPASS,1,[Whether getpass should be replaced])
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} getpass.o"
+fi

Added: branches/ctdb/squeeze-backports/lib/replace/havenone.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/havenone.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/havenone.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,51 @@
+#undef HAVE_TIMEGM
+#undef HAVE_ASPRINTF
+#undef HAVE_BOOL
+#undef HAVE_BZERO
+#undef HAVE_C99_VSNPRINTF
+#undef HAVE_CHROOT
+#undef HAVE_CHSIZE
+#undef HAVE_COMPARISON_FN_T
+#undef HAVE_DECL_ASPRINTF
+#undef HAVE_DECL_SNPRINTF
+#undef HAVE_DECL_VASPRINTF
+#undef HAVE_DECL_VSNPRINTF
+#undef HAVE_DLCLOSE
+#undef HAVE_DLERROR
+#undef HAVE_DLOPEN
+#undef HAVE_DLSYM
+#undef HAVE_ENDNETGRENT
+#undef HAVE_GETNETGRENT
+#undef HAVE_INITGROUPS
+#undef HAVE_INNETGR
+#undef HAVE_MEMCPY
+#undef HAVE_MEMMOVE
+#undef HAVE_MEMSET
+#undef HAVE_MKDTEMP
+#undef HAVE_MKTIME
+#undef HAVE_PREAD
+#undef HAVE_PRINTF
+#undef HAVE_PWRITE
+#undef HAVE_RENAME
+#undef HAVE_SECURE_MKSTEMP
+#undef HAVE_SETENV
+#undef HAVE_SETLINEBUF
+#undef HAVE_SETNETGRENT
+#undef HAVE_SETRESGID
+#undef HAVE_SETRESUID
+#undef HAVE_SIG_ATOMIC_T_TYPE
+#undef HAVE_SNPRINTF
+#undef HAVE_STRCASESTR
+#undef HAVE_STRDUP
+#undef HAVE_STRLCAT
+#undef HAVE_STRLCPY
+#undef HAVE_STRNDUP
+#undef HAVE_STRNLEN
+#undef HAVE_STRTOK_R
+#undef HAVE_SYSLOG
+#undef HAVE_TIMEGM
+#undef HAVE_VASPRINTF
+#undef HAVE_VA_COPY
+#undef HAVE_VSNPRINTF
+#undef HAVE_VSYSLOG
+#undef HAVE_WAITPID

Added: branches/ctdb/squeeze-backports/lib/replace/inet_ntop.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/inet_ntop.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/inet_ntop.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 1996-2001  Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+
+#include "replace.h"
+#include "system/network.h"
+
+#define NS_INT16SZ	 2
+#define NS_IN6ADDRSZ	16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const unsigned char *src, char *dst,
+			      socklen_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst,
+			      socklen_t size);
+#endif
+
+/* char *
+ * isc_net_ntop(af, src, dst, size)
+ *	convert a network format address to presentation format.
+ * return:
+ *	pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *	Paul Vixie, 1996.
+ */
+const char *
+rep_inet_ntop(int af, const void *src, char *dst, socklen_t size)
+{
+	switch (af) {
+	case AF_INET:
+		return (inet_ntop4(src, dst, size));
+#ifdef AF_INET6
+	case AF_INET6:
+		return (inet_ntop6(src, dst, size));
+#endif
+	default:
+		errno = EAFNOSUPPORT;
+		return (NULL);
+	}
+	/* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *	format an IPv4 address
+ * return:
+ *	`dst' (as a const)
+ * notes:
+ *	(1) uses no statics
+ *	(2) takes a unsigned char* not an in_addr as input
+ * author:
+ *	Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, socklen_t size)
+{
+	static const char *fmt = "%u.%u.%u.%u";
+	char tmp[sizeof "255.255.255.255"];
+	size_t len;
+
+	len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]);
+	if (len >= size) {
+		errno = ENOSPC;
+		return (NULL);
+	}
+	memcpy(dst, tmp, len + 1);
+
+	return (dst);
+}
+
+/* const char *
+ * isc_inet_ntop6(src, dst, size)
+ *	convert IPv6 binary address into presentation (printable) format
+ * author:
+ *	Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, socklen_t size)
+{
+	/*
+	 * Note that int32_t and int16_t need only be "at least" large enough
+	 * to contain a value of the specified size.  On some systems, like
+	 * Crays, there is no such thing as an integer variable with 16 bits.
+	 * Keep this in mind if you think this function should have been coded
+	 * to use pointer overlays.  All the world's not a VAX.
+	 */
+	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+	struct { int base, len; } best, cur;
+	unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+	int i, inc;
+
+	/*
+	 * Preprocess:
+	 *	Copy the input (bytewise) array into a wordwise array.
+	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
+	 */
+	memset(words, '\0', sizeof words);
+	for (i = 0; i < NS_IN6ADDRSZ; i++)
+		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+	best.base = -1;
+	best.len = 0;
+	cur.base = -1;
+	cur.len = 0;
+	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+		if (words[i] == 0) {
+			if (cur.base == -1)
+				cur.base = i, cur.len = 1;
+			else
+				cur.len++;
+		} else {
+			if (cur.base != -1) {
+				if (best.base == -1 || cur.len > best.len)
+					best = cur;
+				cur.base = -1;
+			}
+		}
+	}
+	if (cur.base != -1) {
+		if (best.base == -1 || cur.len > best.len)
+			best = cur;
+	}
+	if (best.base != -1 && best.len < 2)
+		best.base = -1;
+
+	/*
+	 * Format the result.
+	 */
+	tp = tmp;
+	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+		/* Are we inside the best run of 0x00's? */
+		if (best.base != -1 && i >= best.base &&
+		    i < (best.base + best.len)) {
+			if (i == best.base)
+				*tp++ = ':';
+			continue;
+		}
+		/* Are we following an initial run of 0x00s or any real hex? */
+		if (i != 0)
+			*tp++ = ':';
+		/* Is this address an encapsulated IPv4? */
+		if (i == 6 && best.base == 0 &&
+		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+			if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+				return (NULL);
+			tp += strlen(tp);
+			break;
+		}
+		inc = snprintf(tp, 5, "%x", words[i]);
+		if (inc >= 5) {
+			abort();
+		}
+		tp += inc;
+	}
+	/* Was it a trailing run of 0x00's? */
+	if (best.base != -1 && (best.base + best.len) ==
+	    (NS_IN6ADDRSZ / NS_INT16SZ))
+		*tp++ = ':';
+	*tp++ = '\0';
+
+	/*
+	 * Check for overflow, copy, and we're done.
+	 */
+	if ((size_t)(tp - tmp) > size) {
+		errno = ENOSPC;
+		return (NULL);
+	}
+	memcpy(dst, tmp, tp - tmp);
+	return (dst);
+}
+#endif /* AF_INET6 */

Added: branches/ctdb/squeeze-backports/lib/replace/inet_ntop.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/inet_ntop.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/inet_ntop.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+AC_CHECK_FUNCS(inet_ntop,[],[LIBREPLACEOBJ="${LIBREPLACEOBJ} inet_ntop.o"])

Added: branches/ctdb/squeeze-backports/lib/replace/inet_pton.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/inet_pton.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/inet_pton.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1996-2001  Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+#define NS_INT16SZ	 2
+#define NS_INADDRSZ	 4
+#define NS_IN6ADDRSZ	16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifdef AF_INET6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ *	convert from presentation format (which usually means ASCII printable)
+ *	to network format (which is usually some kind of binary format).
+ * return:
+ *	1 if the address was valid for the specified address family
+ *	0 if the address wasn't valid (`dst' is untouched in this case)
+ *	-1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *	Paul Vixie, 1996.
+ */
+int
+rep_inet_pton(int af,
+	  const char *src,
+	  void *dst)
+{
+	switch (af) {
+	case AF_INET:
+		return (inet_pton4(src, dst));
+#ifdef AF_INET6
+	case AF_INET6:
+		return (inet_pton6(src, dst));
+#endif
+	default:
+		errno = EAFNOSUPPORT;
+		return (-1);
+	}
+	/* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ *	like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *	1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *	does not touch `dst' unless it's returning 1.
+ * author:
+ *	Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+	const char *src;
+	unsigned char *dst;
+{
+	static const char digits[] = "0123456789";
+	int saw_digit, octets, ch;
+	unsigned char tmp[NS_INADDRSZ], *tp;
+
+	saw_digit = 0;
+	octets = 0;
+	*(tp = tmp) = 0;
+	while ((ch = *src++) != '\0') {
+		const char *pch;
+
+		if ((pch = strchr(digits, ch)) != NULL) {
+			unsigned int new = *tp * 10 + (pch - digits);
+
+			if (new > 255)
+				return (0);
+			*tp = new;
+			if (! saw_digit) {
+				if (++octets > 4)
+					return (0);
+				saw_digit = 1;
+			}
+		} else if (ch == '.' && saw_digit) {
+			if (octets == 4)
+				return (0);
+			*++tp = 0;
+			saw_digit = 0;
+		} else
+			return (0);
+	}
+	if (octets < 4)
+		return (0);
+	memcpy(dst, tmp, NS_INADDRSZ);
+	return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *	convert presentation level address to network order binary form.
+ * return:
+ *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *	(1) does not touch `dst' unless it's returning 1.
+ *	(2) :: in a full address is silently ignored.
+ * credit:
+ *	inspired by Mark Andrews.
+ * author:
+ *	Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static int
+inet_pton6(src, dst)
+	const char *src;
+	unsigned char *dst;
+{
+	static const char xdigits_l[] = "0123456789abcdef",
+			  xdigits_u[] = "0123456789ABCDEF";
+	unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+	const char *xdigits, *curtok;
+	int ch, saw_xdigit;
+	unsigned int val;
+
+	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+	endp = tp + NS_IN6ADDRSZ;
+	colonp = NULL;
+	/* Leading :: requires some special handling. */
+	if (*src == ':')
+		if (*++src != ':')
+			return (0);
+	curtok = src;
+	saw_xdigit = 0;
+	val = 0;
+	while ((ch = *src++) != '\0') {
+		const char *pch;
+
+		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+			pch = strchr((xdigits = xdigits_u), ch);
+		if (pch != NULL) {
+			val <<= 4;
+			val |= (pch - xdigits);
+			if (val > 0xffff)
+				return (0);
+			saw_xdigit = 1;
+			continue;
+		}
+		if (ch == ':') {
+			curtok = src;
+			if (!saw_xdigit) {
+				if (colonp)
+					return (0);
+				colonp = tp;
+				continue;
+			}
+			if (tp + NS_INT16SZ > endp)
+				return (0);
+			*tp++ = (unsigned char) (val >> 8) & 0xff;
+			*tp++ = (unsigned char) val & 0xff;
+			saw_xdigit = 0;
+			val = 0;
+			continue;
+		}
+		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+		    inet_pton4(curtok, tp) > 0) {
+			tp += NS_INADDRSZ;
+			saw_xdigit = 0;
+			break;	/* '\0' was seen by inet_pton4(). */
+		}
+		return (0);
+	}
+	if (saw_xdigit) {
+		if (tp + NS_INT16SZ > endp)
+			return (0);
+		*tp++ = (unsigned char) (val >> 8) & 0xff;
+		*tp++ = (unsigned char) val & 0xff;
+	}
+	if (colonp != NULL) {
+		/*
+		 * Since some memmove()'s erroneously fail to handle
+		 * overlapping regions, we'll do the shift by hand.
+		 */
+		const int n = tp - colonp;
+		int i;
+
+		for (i = 1; i <= n; i++) {
+			endp[- i] = colonp[n - i];
+			colonp[n - i] = 0;
+		}
+		tp = endp;
+	}
+	if (tp != endp)
+		return (0);
+	memcpy(dst, tmp, NS_IN6ADDRSZ);
+	return (1);
+}
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/inet_pton.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/inet_pton.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/inet_pton.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+AC_CHECK_FUNCS(inet_pton,[],[LIBREPLACEOBJ="${LIBREPLACEOBJ} inet_pton.o"])

Added: branches/ctdb/squeeze-backports/lib/replace/install-sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/install-sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/install-sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/lib/replace/install-sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/replace/libreplace.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/libreplace.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/libreplace.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,378 @@
+AC_DEFUN_ONCE(AC_LIBREPLACE_LOCATION_CHECKS,
+[
+echo "LIBREPLACE_LOCATION_CHECKS: START"
+
+dnl find the libreplace sources. This is meant to work both for 
+dnl libreplace standalone builds, and builds of packages using libreplace
+libreplacedir=""
+libreplacepaths="$srcdir $srcdir/lib/replace $srcdir/libreplace $srcdir/../libreplace $srcdir/../replace"
+for d in $libreplacepaths; do
+	if test -f "$d/replace.c"; then
+		libreplacedir="$d"		
+		AC_SUBST(libreplacedir)
+		break;
+	fi
+done
+if test x"$libreplacedir" = "x"; then
+	AC_MSG_ERROR([cannot find libreplace in $libreplacepaths])
+fi
+LIBREPLACEOBJ="replace.o"
+AC_SUBST(LIBREPLACEOBJ)
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+
+echo "LIBREPLACE_LOCATION_CHECKS: END"
+]) dnl end AC_LIBREPLACE_LOCATION_CHECKS
+
+
+AC_DEFUN_ONCE(AC_LIBREPLACE_BROKEN_CHECKS,
+[
+echo "LIBREPLACE_BROKEN_CHECKS: START"
+
+dnl find the libreplace sources. This is meant to work both for 
+dnl libreplace standalone builds, and builds of packages using libreplace
+libreplacedir=""
+for d in "$srcdir" "$srcdir/lib/replace" "$srcdir/libreplace" "$srcdir/../libreplace" "$srcdir/../replace"; do
+	if test -f "$d/replace.c"; then
+		libreplacedir="$d"		
+		AC_SUBST(libreplacedir)
+		break;
+	fi
+done
+LIBREPLACEOBJ="replace.o"
+AC_SUBST(LIBREPLACEOBJ)
+
+LIBREPLACEOBJ="${LIBREPLACEOBJ} snprintf.o"
+
+AC_TYPE_SIGNAL
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_TYPE_PID_T
+AC_STRUCT_ST_RDEV
+AC_CHECK_TYPE(ino_t,unsigned)
+AC_CHECK_TYPE(loff_t,off_t)
+AC_CHECK_TYPE(offset_t,loff_t)
+
+AC_FUNC_MEMCMP
+
+AC_CHECK_FUNCS(pipe strftime srandom random srand rand usleep setbuffer lstat getpgrp)
+
+AC_CHECK_HEADERS(stdbool.h stdint.h sys/select.h)
+AC_CHECK_HEADERS(setjmp.h)
+
+LIBREPLACE_PROVIDE_HEADER([stdint.h])
+LIBREPLACE_PROVIDE_HEADER([stdbool.h])
+
+AC_CHECK_TYPE(bool, 
+[AC_DEFINE(HAVE_BOOL, 1, [Whether the bool type is available])],,
+[
+AC_INCLUDES_DEFAULT
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif]
+)
+
+AC_CHECK_TYPE(_Bool, 
+[AC_DEFINE(HAVE__Bool, 1, [Whether the _Bool type is available])],,
+[
+AC_INCLUDES_DEFAULT
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif]
+)
+
+AC_CACHE_CHECK([for working mmap],samba_cv_HAVE_MMAP,[
+AC_TRY_RUN([#include "$libreplacedir/test/shared_mmap.c"],
+           samba_cv_HAVE_MMAP=yes,samba_cv_HAVE_MMAP=no,samba_cv_HAVE_MMAP=cross)])
+if test x"$samba_cv_HAVE_MMAP" = x"yes"; then
+    AC_DEFINE(HAVE_MMAP,1,[Whether mmap works])
+fi
+
+
+AC_CHECK_HEADERS(sys/syslog.h syslog.h)
+AC_CHECK_HEADERS(sys/time.h time.h)
+AC_CHECK_HEADERS(stdarg.h vararg.h)
+AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h arpa/inet.h)
+AC_CHECK_HEADERS(netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h)
+AC_CHECK_HEADERS(sys/sockio.h sys/un.h)
+AC_CHECK_HEADERS(sys/mount.h mntent.h)
+
+dnl we need to check that net/if.h really can be used, to cope with hpux
+dnl where including it always fails
+AC_CACHE_CHECK([for usable net/if.h],libreplace_cv_USABLE_NET_IF_H,[
+	AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+		AC_INCLUDES_DEFAULT
+		#if HAVE_SYS_SOCKET_H
+		# include <sys/socket.h>
+		#endif
+		#include <net/if.h>
+		int main(void) {return 0;}])],
+		[libreplace_cv_USABLE_NET_IF_H=yes],
+		[libreplace_cv_USABLE_NET_IF_H=no]
+	)
+])
+if test x"$libreplace_cv_USABLE_NET_IF_H" = x"yes";then
+	AC_DEFINE(HAVE_NET_IF_H, 1, usability of net/if.h)
+fi
+
+AC_CACHE_CHECK([for broken inet_ntoa],samba_cv_REPLACE_INET_NTOA,[
+AC_TRY_RUN([
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+main() { struct in_addr ip; ip.s_addr = 0x12345678;
+if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
+    strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(0); } 
+exit(1);}],
+           samba_cv_REPLACE_INET_NTOA=yes,samba_cv_REPLACE_INET_NTOA=no,samba_cv_REPLACE_INET_NTOA=cross)])
+if test x"$samba_cv_REPLACE_INET_NTOA" = x"yes"; then
+    AC_DEFINE(REPLACE_INET_NTOA,1,[Whether inet_ntoa should be replaced])
+fi
+
+AC_HAVE_TYPE([socklen_t],[#include <sys/socket.h>])
+AC_HAVE_TYPE([sa_family_t],[#include <sys/socket.h>])
+AC_HAVE_TYPE([struct addrinfo], [#include <netdb.h>])
+AC_HAVE_TYPE([struct sockaddr], [#include <sys/socket.h>])
+AC_HAVE_TYPE([struct sockaddr_storage], [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+])
+AC_HAVE_TYPE([struct sockaddr_in6], [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+])
+
+if test x"$ac_cv_type_struct_sockaddr_storage" = x"yes"; then
+AC_CHECK_MEMBER(struct sockaddr_storage.ss_family,
+                AC_DEFINE(HAVE_SS_FAMILY, 1, [Defined if struct sockaddr_storage has ss_family field]),,
+                [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+		])
+
+if test x"$ac_cv_member_struct_sockaddr_storage_ss_family" != x"yes"; then
+AC_CHECK_MEMBER(struct sockaddr_storage.__ss_family,
+                AC_DEFINE(HAVE___SS_FAMILY, 1, [Defined if struct sockaddr_storage has __ss_family field]),,
+                [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+		])
+fi
+fi
+
+AC_CHECK_FUNCS(seteuid setresuid setegid setresgid chroot bzero strerror)
+AC_CHECK_FUNCS(vsyslog setlinebuf mktime ftruncate chsize rename)
+AC_CHECK_FUNCS(waitpid strlcpy strlcat initgroups memmove strdup)
+AC_CHECK_FUNCS(pread pwrite strndup strcasestr strtok_r mkdtemp socketpair)
+AC_CHECK_FUNCS(isatty)
+AC_HAVE_DECL(setresuid, [#include <unistd.h>])
+AC_HAVE_DECL(setresgid, [#include <unistd.h>])
+AC_HAVE_DECL(errno, [#include <errno.h>])
+
+AC_CACHE_CHECK([for secure mkstemp],samba_cv_HAVE_SECURE_MKSTEMP,[
+AC_TRY_RUN([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+main() { 
+  struct stat st;
+  char tpl[20]="/tmp/test.XXXXXX"; 
+  int fd = mkstemp(tpl); 
+  if (fd == -1) exit(1);
+  unlink(tpl);
+  if (fstat(fd, &st) != 0) exit(1);
+  if ((st.st_mode & 0777) != 0600) exit(1);
+  exit(0);
+}],
+samba_cv_HAVE_SECURE_MKSTEMP=yes,
+samba_cv_HAVE_SECURE_MKSTEMP=no,
+samba_cv_HAVE_SECURE_MKSTEMP=cross)])
+if test x"$samba_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
+    AC_DEFINE(HAVE_SECURE_MKSTEMP,1,[Whether mkstemp is secure])
+fi
+
+dnl Provided by snprintf.c:
+AC_CHECK_HEADERS(stdio.h strings.h)
+AC_CHECK_DECLS([snprintf, vsnprintf, asprintf, vasprintf])
+AC_CHECK_FUNCS(snprintf vsnprintf asprintf vasprintf)
+
+AC_CACHE_CHECK([for C99 vsnprintf],samba_cv_HAVE_C99_VSNPRINTF,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+void foo(const char *format, ...) { 
+       va_list ap;
+       int len;
+       char buf[20];
+       long long l = 1234567890;
+       l *= 100;
+
+       va_start(ap, format);
+       len = vsnprintf(buf, 0, format, ap);
+       va_end(ap);
+       if (len != 5) exit(1);
+
+       va_start(ap, format);
+       len = vsnprintf(0, 0, format, ap);
+       va_end(ap);
+       if (len != 5) exit(2);
+
+       if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(3);
+
+       if (snprintf(buf, 20, "%lld", l) != 12 || strcmp(buf, "123456789000") != 0) exit(4);
+       if (snprintf(buf, 20, "%zu", 123456789) != 9 || strcmp(buf, "123456789") != 0) exit(5);
+       if (snprintf(buf, 20, "%2\$d %1\$d", 3, 4) != 3 || strcmp(buf, "4 3") != 0) exit(6);
+       if (snprintf(buf, 20, "%s", 0) < 3) exit(7);
+
+       exit(0);
+}
+main() { foo("hello"); }
+],
+samba_cv_HAVE_C99_VSNPRINTF=yes,samba_cv_HAVE_C99_VSNPRINTF=no,samba_cv_HAVE_C99_VSNPRINTF=cross)])
+if test x"$samba_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
+    AC_DEFINE(HAVE_C99_VSNPRINTF,1,[Whether there is a C99 compliant vsnprintf])
+fi
+
+
+dnl VA_COPY
+AC_CACHE_CHECK([for va_copy],samba_cv_HAVE_VA_COPY,[
+AC_TRY_LINK([#include <stdarg.h>
+va_list ap1,ap2;], [va_copy(ap1,ap2);],
+samba_cv_HAVE_VA_COPY=yes,samba_cv_HAVE_VA_COPY=no)])
+if test x"$samba_cv_HAVE_VA_COPY" = x"yes"; then
+    AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available])
+fi
+
+if test x"$samba_cv_HAVE_VA_COPY" != x"yes"; then
+AC_CACHE_CHECK([for __va_copy],samba_cv_HAVE___VA_COPY,[
+AC_TRY_LINK([#include <stdarg.h>
+va_list ap1,ap2;], [__va_copy(ap1,ap2);],
+samba_cv_HAVE___VA_COPY=yes,samba_cv_HAVE___VA_COPY=no)])
+if test x"$samba_cv_HAVE___VA_COPY" = x"yes"; then
+    AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available])
+fi
+fi
+
+dnl __FUNCTION__ macro
+AC_CACHE_CHECK([for __FUNCTION__ macro],samba_cv_HAVE_FUNCTION_MACRO,[
+AC_TRY_COMPILE([#include <stdio.h>], [printf("%s\n", __FUNCTION__);],
+samba_cv_HAVE_FUNCTION_MACRO=yes,samba_cv_HAVE_FUNCTION_MACRO=no)])
+if test x"$samba_cv_HAVE_FUNCTION_MACRO" = x"yes"; then
+    AC_DEFINE(HAVE_FUNCTION_MACRO,1,[Whether there is a __FUNCTION__ macro])
+else
+    dnl __func__ macro
+    AC_CACHE_CHECK([for __func__ macro],samba_cv_HAVE_func_MACRO,[
+    AC_TRY_COMPILE([#include <stdio.h>], [printf("%s\n", __func__);],
+    samba_cv_HAVE_func_MACRO=yes,samba_cv_HAVE_func_MACRO=no)])
+    if test x"$samba_cv_HAVE_func_MACRO" = x"yes"; then
+       AC_DEFINE(HAVE_func_MACRO,1,[Whether there is a __func__ macro])
+    fi
+fi
+
+AC_CHECK_HEADERS([sys/param.h limits.h])
+
+AC_CHECK_TYPE(comparison_fn_t, 
+[AC_DEFINE(HAVE_COMPARISON_FN_T, 1,[Whether or not we have comparison_fn_t])])
+
+AC_HAVE_DECL(setenv, [#include <stdlib.h>])
+AC_CHECK_FUNCS(setenv unsetenv)
+
+AC_CHECK_FUNCS(strnlen)
+AC_CHECK_FUNCS(strtoull __strtoull strtouq strtoll __strtoll strtoq)
+
+# this test disabled as we don't actually need __VA_ARGS__ yet
+AC_TRY_CPP([
+#define eprintf(...) fprintf(stderr, __VA_ARGS__)
+eprintf("bla", "bar");
+], AC_DEFINE(HAVE__VA_ARGS__MACRO, 1, [Whether the __VA_ARGS__ macro is available]))
+
+
+AC_CACHE_CHECK([for sig_atomic_t type],samba_cv_sig_atomic_t, [
+    AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <signal.h>],[sig_atomic_t i = 0],
+	samba_cv_sig_atomic_t=yes,samba_cv_sig_atomic_t=no)])
+if test x"$samba_cv_sig_atomic_t" = x"yes"; then
+   AC_DEFINE(HAVE_SIG_ATOMIC_T_TYPE,1,[Whether we have the atomic_t variable type])
+fi
+
+
+AC_CACHE_CHECK([for O_DIRECT flag to open(2)],samba_cv_HAVE_OPEN_O_DIRECT,[
+AC_TRY_COMPILE([
+#include <unistd.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif],
+[int fd = open("/dev/null", O_DIRECT);],
+samba_cv_HAVE_OPEN_O_DIRECT=yes,samba_cv_HAVE_OPEN_O_DIRECT=no)])
+if test x"$samba_cv_HAVE_OPEN_O_DIRECT" = x"yes"; then
+    AC_DEFINE(HAVE_OPEN_O_DIRECT,1,[Whether the open(2) accepts O_DIRECT])
+fi
+
+
+dnl Check if the C compiler understands volatile (it should, being ANSI).
+AC_CACHE_CHECK([that the C compiler understands volatile],samba_cv_volatile, [
+	AC_TRY_COMPILE([#include <sys/types.h>],[volatile int i = 0],
+		samba_cv_volatile=yes,samba_cv_volatile=no)])
+if test x"$samba_cv_volatile" = x"yes"; then
+	AC_DEFINE(HAVE_VOLATILE, 1, [Whether the C compiler understands volatile])
+fi
+
+m4_include(system/config.m4)
+
+m4_include(dlfcn.m4)
+m4_include(getpass.m4)
+m4_include(strptime.m4)
+m4_include(win32.m4)
+m4_include(timegm.m4)
+m4_include(inet_ntop.m4)
+m4_include(inet_pton.m4)
+m4_include(getaddrinfo.m4)
+m4_include(repdir.m4)
+m4_include(getifaddrs.m4)
+
+AC_CHECK_FUNCS([syslog printf memset memcpy],,[AC_MSG_ERROR([Required function not found])])
+
+echo "LIBREPLACE_BROKEN_CHECKS: END"
+]) dnl end AC_LIBREPLACE_BROKEN_CHECKS
+
+AC_DEFUN_ONCE(AC__LIBREPLACE_ALL_CHECKS_START,
+[
+#LIBREPLACE_ALL_CHECKS: START"
+])
+AC_DEFUN_ONCE(AC__LIBREPLACE_ALL_CHECKS_END,
+[
+#LIBREPLACE_ALL_CHECKS: END"
+])
+m4_define(AC_LIBREPLACE_ALL_CHECKS,
+[
+AC__LIBREPLACE_ALL_CHECKS_START
+AC_LIBREPLACE_LOCATION_CHECKS
+AC_LIBREPLACE_CC_CHECKS
+AC_LIBREPLACE_BROKEN_CHECKS
+AC__LIBREPLACE_ALL_CHECKS_END
+CFLAGS="$CFLAGS -I$libreplacedir"
+])
+
+m4_include(libreplace_cc.m4)
+m4_include(libreplace_ld.m4)
+m4_include(libreplace_macros.m4)
+m4_include(autoconf-2.60.m4)

Added: branches/ctdb/squeeze-backports/lib/replace/libreplace_cc.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/libreplace_cc.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/libreplace_cc.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,171 @@
+
+AC_DEFUN_ONCE(AC__LIBREPLACE_ONLY_CC_CHECKS_START,
+[
+echo "LIBREPLACE_CC_CHECKS: START"
+])
+
+AC_DEFUN_ONCE(AC__LIBREPLACE_ONLY_CC_CHECKS_END,
+[
+echo "LIBREPLACE_CC_CHECKS: END"
+])
+
+dnl
+dnl
+dnl AC_LIBREPLACE_CC_CHECKS
+dnl
+dnl Note: we need to use m4_define instead of AC_DEFUN because
+dnl       of the ordering of tests
+dnl       
+dnl 
+m4_define(AC_LIBREPLACE_CC_CHECKS,
+[
+AC__LIBREPLACE_ONLY_CC_CHECKS_START
+
+dnl stop the C89 attempt by autoconf - if autoconf detects -Ae it will enable it
+dnl which conflicts with C99 on HPUX
+ac_cv_prog_cc_Ae=no
+
+savedCFLAGS=$CFLAGS
+AC_PROG_CC
+CFLAGS=$savedCFLAGS
+
+dnl don't try for C99 if we are using gcc, as otherwise we 
+dnl lose immediate structure constants
+if test x"$GCC" != x"yes" ; then
+AC_PROG_CC_C99
+fi
+
+if test x"$GCC" = x"yes" ; then
+	AC_MSG_CHECKING([for version of gcc])
+	GCC_VERSION=`$CC -dumpversion`
+	AC_MSG_RESULT(${GCC_VERSION})
+fi
+AC_USE_SYSTEM_EXTENSIONS
+AC_C_BIGENDIAN
+AC_C_INLINE
+LIBREPLACE_C99_STRUCT_INIT([],[AC_MSG_WARN([c99 structure initializer are not supported])])
+
+AC_PROG_INSTALL
+
+AC_ISC_POSIX
+AC_N_DEFINE(_XOPEN_SOURCE_EXTENDED)
+
+AC_SYS_LARGEFILE
+
+dnl Add #include for broken IRIX header files
+case "$host_os" in
+	*irix6*) AC_ADD_INCLUDE(<standards.h>)
+		;;
+	*hpux*)
+		# mmap on HPUX is completely broken...
+		AC_DEFINE(MMAP_BLACKLIST, 1, [Whether MMAP is broken])
+		if test "`uname -r`" = "B.11.00" -o "`uname -r`" = "B.11.11"; then
+			AC_MSG_WARN([Enabling HPUX 11.00/11.11 header bug workaround])
+			CFLAGS="$CFLAGS -Dpread=pread64 -Dpwrite=pwrite64"
+		fi
+		if test "`uname -r`" = "B.11.23"; then
+			AC_MSG_WARN([Enabling HPUX 11.23 machine/sys/getppdp.h bug workaround])
+			CFLAGS="$CFLAGS -D_MACHINE_SYS_GETPPDP_INCLUDED"
+		fi
+		;;
+	*aix*)
+		AC_DEFINE(BROKEN_STRNDUP, 1, [Whether strndup is broken])
+		AC_DEFINE(BROKEN_STRNLEN, 1, [Whether strnlen is broken])
+		if test "${GCC}" != "yes"; then
+			## for funky AIX compiler using strncpy()
+			CFLAGS="$CFLAGS -D_LINUX_SOURCE_COMPAT -qmaxmem=32000"
+		fi
+		;;
+	*osf*)
+		# this brings in socklen_t
+		AC_N_DEFINE(_XOPEN_SOURCE,600)
+		AC_N_DEFINE(_OSF_SOURCE)
+		;;
+	#
+	# VOS may need to have POSIX support and System V compatibility enabled.
+	#
+	*vos*)
+		case "$CFLAGS" in
+			*-D_POSIX_C_SOURCE*);;
+			*)
+				CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=200112L"
+				AC_DEFINE(_POSIX_C_SOURCE, 200112L, [Whether to enable POSIX support])
+				;;
+		esac
+		case "$CFLAGS" in
+			*-D_SYSV*|*-D_SVID_SOURCE*);;
+			*)
+				CFLAGS="$CFLAGS -D_SYSV"
+				AC_DEFINE(_SYSV, 1, [Whether to enable System V compatibility])
+				;;
+		esac
+		;;
+esac
+
+
+
+AC_CHECK_HEADERS([standards.h])
+
+# Solaris needs HAVE_LONG_LONG defined
+AC_CHECK_TYPES(long long)
+
+AC_CHECK_TYPE(uint_t, unsigned int)
+AC_CHECK_TYPE(int8_t, char)
+AC_CHECK_TYPE(uint8_t, unsigned char)
+AC_CHECK_TYPE(int16_t, short)
+AC_CHECK_TYPE(uint16_t, unsigned short)
+AC_CHECK_TYPE(int32_t, long)
+AC_CHECK_TYPE(uint32_t, unsigned long)
+AC_CHECK_TYPE(int64_t, long long)
+AC_CHECK_TYPE(uint64_t, unsigned long long)
+
+AC_CHECK_TYPE(size_t, unsigned int)
+AC_CHECK_TYPE(ssize_t, int)
+
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(char)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(long long)
+
+AC_CHECK_SIZEOF(off_t)
+AC_CHECK_SIZEOF(size_t)
+AC_CHECK_SIZEOF(ssize_t)
+
+AC_CHECK_TYPE(intptr_t, unsigned long long)
+AC_CHECK_TYPE(ptrdiff_t, unsigned long long)
+
+if test x"$ac_cv_type_long_long" != x"yes";then
+	AC_MSG_ERROR([LIBREPLACE needs type 'long long'])
+fi
+if test $ac_cv_sizeof_long_long -lt 8;then
+	AC_MSG_ERROR([LIBREPLACE needs sizeof(long long) >= 8])
+fi
+
+############################################
+# check if the compiler can do immediate structures
+AC_SUBST(libreplace_cv_immediate_structures)
+AC_CACHE_CHECK([for immediate structures],libreplace_cv_immediate_structures,[
+	AC_TRY_COMPILE([
+		#include <stdio.h>
+	],[
+		typedef struct {unsigned x;} FOOBAR;
+		#define X_FOOBAR(x) ((FOOBAR) { x })
+		#define FOO_ONE X_FOOBAR(1)
+		FOOBAR f = FOO_ONE;   
+		static const struct {
+			FOOBAR y; 
+		} f2[] = {
+			{FOO_ONE}
+		};   
+	],
+	libreplace_cv_immediate_structures=yes,
+	libreplace_cv_immediate_structures=no,
+	libreplace_cv_immediate_structures=cross)
+])
+if test x"$libreplace_cv_immediate_structures" = x"yes"; then
+	AC_DEFINE(HAVE_IMMEDIATE_STRUCTURES,1,[Whether the compiler supports immediate structures])
+fi
+
+AC__LIBREPLACE_ONLY_CC_CHECKS_END
+]) dnl end AC_LIBREPLACE_CC_CHECKS

Added: branches/ctdb/squeeze-backports/lib/replace/libreplace_ld.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/libreplace_ld.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/libreplace_ld.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,313 @@
+#
+# This offers a nice overview how to build shared libraries on all platforms
+#        http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
+#
+
+AC_DEFUN([AC_LIBREPLACE_STLD],
+[
+	AC_PATH_PROG(PROG_AR, ar)
+
+	STLD=${PROG_AR}
+
+	AC_SUBST(STLD)
+])
+
+AC_DEFUN([AC_LIBREPLACE_STLD_FLAGS],
+[
+	STLD_FLAGS="-rcs"
+	AC_SUBST(STLD_FLAGS)
+])
+
+AC_DEFUN([AC_LD_EXPORT_DYNAMIC],
+[
+saved_LDFLAGS="$LDFLAGS"
+if AC_TRY_COMMAND([${CC-cc} $CFLAGS -Wl,--version 2>&1 | grep "GNU ld" >/dev/null]); then
+	LD_EXPORT_DYNAMIC="-Wl,-export-dynamic"
+else
+	case "$host_os" in
+		hpux* )
+		  LD_EXPORT_DYNAMIC="-Wl,-E"
+		  ;;
+		*)
+		  LD_EXPORT_DYNAMIC=""
+		  ;;
+	  esac
+fi
+AC_SUBST(LD_EXPORT_DYNAMIC)
+LDFLAGS="$saved_LDFLAGS"
+])
+
+AC_DEFUN([AC_LD_PICFLAG],
+[
+case "$host_os" in
+	*linux*) 
+		PICFLAG="-fPIC" 
+		;;
+	*solaris*)
+		if test "${GCC}" = "yes"; then
+			PICFLAG="-fPIC"
+		else
+			PICFLAG="-KPIC"
+		fi
+		;;
+	*sunos*)
+		PICFLAG="-KPIC"   # Is this correct for SunOS
+		;;
+	*netbsd* | *freebsd* | *dragonfly* )  
+		PICFLAG="-fPIC -DPIC"
+		;;
+	*openbsd*)
+		PICFLAG="-fPIC"
+		;;
+	*irix*)
+		if test "${GCC}" = "yes"; then
+			PICFLAG="-fPIC"
+		else 
+			PICFLAG="-KPIC"
+		fi
+		;;
+	*aix*)
+		# as AIX code is always position independent...
+		PICFLAG="-O2"
+		;;
+	*hpux*)
+		if test $ac_cv_prog_cc_Ae = yes; then
+			PICFLAG="+z +ESnolit"
+		elif test "${GCC}" = "yes"; then
+			PICFLAG="-fPIC"
+		fi
+		if test "$host_cpu" = "ia64"; then
+			PICFLAG="+z"
+		fi
+		;;
+	*osf*)
+		PICFLAG="-fPIC"
+		;;
+	*unixware*)
+		PICFLAG="-KPIC"
+		;;
+	*darwin*)
+		PICFLAG="-fno-common"
+		;;
+esac
+AC_SUBST(PICFLAG)
+])
+
+AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_LINKER],
+[
+	LD_SHLIB_LINKER="${CC}"
+
+	case "$host_os" in
+		*irix*)
+			LD_SHLIB_LINKER="${PROG_LD}"
+			;;
+	esac
+
+	AC_SUBST(LD_SHLIB_LINKER)
+])
+
+AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_FLAGS],
+[
+	LD_SHLIB_FLAGS="-shared"
+
+	case "$host_os" in
+		*linux*)
+			LD_SHLIB_FLAGS="-shared -Wl,-Bsymbolic"
+			;;
+		*solaris*)
+			LD_SHLIB_FLAGS="-G"
+			if test "${GCC}" = "no"; then
+				## ${CFLAGS} added for building 64-bit shared 
+				## libs using Sun's Compiler
+				LD_SHLIB_FLAGS="-G \${CFLAGS}"
+			fi
+			;;
+		*sunos*)
+			LD_SHLIB_FLAGS="-G"
+			;;
+		*irix*)
+			LD_SHLIB_FLAGS="-shared"
+			;;
+		*aix*)
+			LD_SHLIB_FLAGS="-Wl,-G,-bexpall,-bbigtoc"
+			;;
+		*hpux*)
+			if test "${GCC}" = "yes"; then
+				LD_SHLIB_FLAGS="-shared"
+			else
+				LD_SHLIB_FLAGS="-b"
+			fi
+			;;
+		*osf*)
+			LD_SHLIB_FLAGS="-shared"
+			;;
+		*darwin*)
+			LD_SHLIB_FLAGS="-dynamiclib -Wl,-search_paths_first"
+			;;
+	esac
+
+	AC_SUBST(LD_SHLIB_FLAGS)
+])
+
+AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_DISALLOW_UNDEF_FLAG],
+[
+	LD_SHLIB_DISALLOW_UNDEF_FLAG=""
+
+	#
+	# TODO: enforce error not only warnings
+	#
+	# NOTE: -Wl,--no-allow-shlib-undefined isn't what we want...
+	#       as it bails out on broken system libraries
+	#
+	case "$host_os" in
+		*osf*)
+			LD_SHLIB_DISALLOW_UNDEF_FLAG="-warning_unresolved"
+			;;
+		*darwin*)
+			LD_SHLIB_DISALLOW_UNDEF_FLAG="-undefined error"
+			;;
+	esac
+
+	AC_SUBST(LD_SHLIB_DISALLOW_UNDEF_FLAG)
+])
+
+AC_DEFUN([AC_LIBREPLACE_SHLD],
+[
+	AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_LINKER])
+	SHLD="$LD_SHLIB_LINKER"
+	AC_SUBST(SHLD)
+])
+
+AC_DEFUN([AC_LIBREPLACE_SHLD_FLAGS],
+[
+	AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_FLAGS])
+	AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_DISALLOW_UNDEF_FLAG])
+	SHLD_FLAGS="$LD_SHLIB_FLAGS $LD_SHLIB_DISALLOW_UNDEF_FLAG"
+	AC_SUBST(SHLD_FLAGS)
+])
+
+AC_DEFUN([AC_LD_SHLIBEXT],
+[
+	SHLIBEXT="so"
+	case "$host_os" in
+		*hpux*)
+			if test "$host_cpu" = "ia64"; then
+				SHLIBEXT="so"
+			else
+				SHLIBEXT="sl"
+			fi
+		;;
+		*darwin*)
+			SHLIBEXT="dylib"
+		;;
+	esac
+	AC_SUBST(SHLIBEXT)
+])
+
+AC_DEFUN([AC_LD_SONAMEFLAG],
+[
+	AC_SUBST(SONAMEFLAG)
+	SONAMEFLAG=""
+	case "$host_os" in 
+		*linux*)
+			SONAMEFLAG="-Wl,-soname="
+			;;
+		*solaris*)
+			SONAMEFLAG="-h "
+			if test "${GCC}" = "yes"; then
+				SONAMEFLAG="-Wl,-soname="
+			fi
+			;;
+		*sunos*)
+			SONAMEFLAG="-Wl,-h,"
+			;;
+		*netbsd* | *freebsd* | *dragonfly* )
+			SONAMEFLAG="-Wl,-soname,"
+			;;
+		*openbsd*)
+			SONAMEFLAG="-Wl,-soname,"
+			;;
+		*irix*)
+			SONAMEFLAG="-Wl,-soname,"
+			;;
+		*hpux*)
+			SONAMEFLAG="-Wl,+h,"
+			;;
+		*osf*)
+			SONAMEFLAG="-Wl,-soname,"
+			;;
+		*unixware*)
+			SONAMEFLAG="-Wl,-soname,"
+			;;
+		*darwin*)
+			SONAMEFLAG="#"
+			;;
+		*aix*)
+			# Not supported
+			SONAMEFLAG="#"
+			;;
+		esac
+])
+
+AC_DEFUN([AC_LIBREPLACE_MDLD],
+[
+	AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_LINKER])
+	MDLD="$LD_SHLIB_LINKER"
+	AC_SUBST(MDLD)
+])
+
+AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG],
+[
+	LD_ALLOW_SHLIB_UNDEF_FLAG=""
+
+	case "$host_os" in
+		*linux*)
+			LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,--allow-shlib-undefined"
+			;;
+		*osf*)
+			LD_SHLIB_ALLOW_UNDEF_FLAG="-expect_unresolved '*'"
+			;;
+		*darwin*)
+			LD_SHLIB_ALLOW_UNDEF_FLAG="-undefined dynamic_lookup"
+			;;
+	esac
+
+	AC_SUBST(LD_SHLIB_ALLOW_UNDEF_FLAG)
+])
+
+AC_DEFUN([AC_LIBREPLACE_MDLD_FLAGS],
+[
+	AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_FLAGS])
+	AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG])
+	MDLD_FLAGS="$LD_SHLIB_FLAGS $LD_SHLIB_ALLOW_UNDEF_FLAG"
+	AC_SUBST(MDLD_FLAGS)
+])
+
+AC_DEFUN([AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR],
+[
+	case "$host_os" in
+		*linux*)
+			LIB_PATH_VAR=LD_LIBRARY_PATH
+		;;
+		*solaris*)
+			LIB_PATH_VAR=LD_LIBRARY_PATH
+		;;
+		*hpux*)
+			LIB_PATH_VAR=SHLIB_PATH
+		;;
+		*osf*)
+			LIB_PATH_VAR=LD_LIBRARY_PATH
+		;;
+		*aix*)
+			LIB_PATH_VAR=LIB_PATH
+			;;
+		*irix*)
+			LIB_PATH_VAR=LD_LIBRARY_PATH
+			;;
+		*darwin*)
+			LIB_PATH_VAR=DYLD_LIBRARY_PATH
+			;;
+	esac
+
+	AC_SUBST(LIB_PATH_VAR)
+])

Added: branches/ctdb/squeeze-backports/lib/replace/libreplace_macros.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/libreplace_macros.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/libreplace_macros.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,332 @@
+#
+# This is a collection of useful autoconf macros
+#
+
+############################################
+# Check if the compiler handles c99 struct initialization, and if not try -AC99 and -c99 flags
+# Usage: LIBREPLACE_C99_STRUCT_INIT(success-action,failure-action)
+# changes CFLAGS to add -AC99 or -c99 if needed
+AC_DEFUN([LIBREPLACE_C99_STRUCT_INIT],
+[
+saved_CFLAGS="$CFLAGS";
+c99_init=no
+if test x"$c99_init" = x"no"; then
+    AC_MSG_CHECKING(for C99 designated initializers)
+    CFLAGS="$saved_CFLAGS";
+    AC_TRY_COMPILE([#include <stdio.h>],
+     [ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };	 
+     ],
+     [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+if test x"$c99_init" = x"no"; then
+    AC_MSG_CHECKING(for C99 designated initializers with -AC99)
+    CFLAGS="$saved_CFLAGS -AC99";
+    AC_TRY_COMPILE([#include <stdio.h>],
+     [ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };	 
+     ],
+     [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+if test x"$c99_init" = x"no"; then
+    AC_MSG_CHECKING(for C99 designated initializers with -qlanglvl=extc99)
+    CFLAGS="$saved_CFLAGS -qlanglvl=extc99";
+    AC_TRY_COMPILE([#include <stdio.h>],
+     [ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };	 
+     ],
+     [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+if test x"$c99_init" = x"no"; then
+    AC_MSG_CHECKING(for C99 designated initializers with -qlanglvl=stdc99)
+    CFLAGS="$saved_CFLAGS -qlanglvl=stdc99";
+    AC_TRY_COMPILE([#include <stdio.h>],
+     [ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };	 
+     ],
+     [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+if test x"$c99_init" = x"no"; then
+    AC_MSG_CHECKING(for C99 designated initializers with -c99)
+    CFLAGS="$saved_CFLAGS -c99"
+    AC_TRY_COMPILE([#include <stdio.h>],
+     [ struct foo {int x;char y;};
+       struct foo bar = { .y = 'X', .x = 1 };	 
+     ],
+     [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)])
+fi
+
+if test "`uname`" = "HP-UX"; then
+  if test "$ac_cv_c_compiler_gnu" = no; then
+	# special override for broken HP-UX compiler - I can't find a way to test
+	# this properly (its a compiler bug)
+	CFLAGS="$CFLAGS -AC99";
+	c99_init=yes;
+  fi
+fi
+
+if test x"$c99_init" = x"yes"; then
+    saved_CFLAGS=""
+    $1
+else
+    CFLAGS="$saved_CFLAGS"
+    saved_CFLAGS=""
+    $2
+fi
+])
+
+dnl AC_PROG_CC_FLAG(flag)
+AC_DEFUN(AC_PROG_CC_FLAG,
+[AC_CACHE_CHECK(whether ${CC-cc} accepts -$1, ac_cv_prog_cc_$1,
+[echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -$1 -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_$1=yes
+else
+  ac_cv_prog_cc_$1=no
+fi
+rm -f conftest*
+])])
+
+dnl see if a declaration exists for a function or variable
+dnl defines HAVE_function_DECL if it exists
+dnl AC_HAVE_DECL(var, includes)
+AC_DEFUN(AC_HAVE_DECL,
+[
+ AC_CACHE_CHECK([for $1 declaration],ac_cv_have_$1_decl,[
+    AC_TRY_COMPILE([$2],[int i = (int)$1],
+        ac_cv_have_$1_decl=yes,ac_cv_have_$1_decl=no)])
+ if test x"$ac_cv_have_$1_decl" = x"yes"; then
+    AC_DEFINE([HAVE_]translit([$1], [a-z], [A-Z])[_DECL],1,[Whether $1() is available])
+ fi
+])
+
+
+# AC_CHECK_LIB_EXT(LIBRARY, [EXT_LIBS], [FUNCTION],
+#              [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND],
+#              [ADD-ACTION-IF-FOUND],[OTHER-LIBRARIES])
+# ------------------------------------------------------
+#
+# Use a cache variable name containing both the library and function name,
+# because the test really is for library $1 defining function $3, not
+# just for library $1.  Separate tests with the same $1 and different $3s
+# may have different results.
+#
+# Note that using directly AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$3])
+# is asking for trouble, since AC_CHECK_LIB($lib, fun) would give
+# ac_cv_lib_$lib_fun, which is definitely not what was meant.  Hence
+# the AS_LITERAL_IF indirection.
+#
+# FIXME: This macro is extremely suspicious.  It DEFINEs unconditionally,
+# whatever the FUNCTION, in addition to not being a *S macro.  Note
+# that the cache does depend upon the function we are looking for.
+#
+# It is on purpose we used `ac_check_lib_ext_save_LIBS' and not just
+# `ac_save_LIBS': there are many macros which don't want to see `LIBS'
+# changed but still want to use AC_CHECK_LIB_EXT, so they save `LIBS'.
+# And ``ac_save_LIBS' is too tempting a name, so let's leave them some
+# freedom.
+AC_DEFUN([AC_CHECK_LIB_EXT],
+[
+AH_CHECK_LIB_EXT([$1])
+ac_check_lib_ext_save_LIBS=$LIBS
+LIBS="-l$1 $$2 $7 $LIBS"
+AS_LITERAL_IF([$1],
+      [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1])],
+      [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1''])])dnl
+
+m4_ifval([$3],
+ [
+    AH_CHECK_FUNC_EXT([$3])
+    AS_LITERAL_IF([$1],
+              [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1_$3])],
+              [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1''_$3])])dnl
+    AC_CACHE_CHECK([for $3 in -l$1], ac_Lib_func,
+	[AC_TRY_LINK_FUNC($3,
+                 [AS_VAR_SET(ac_Lib_func, yes);
+		  AS_VAR_SET(ac_Lib_ext, yes)],
+                 [AS_VAR_SET(ac_Lib_func, no);
+		  AS_VAR_SET(ac_Lib_ext, no)])
+	])
+    AS_IF([test AS_VAR_GET(ac_Lib_func) = yes],
+        [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$3))])dnl
+    AS_VAR_POPDEF([ac_Lib_func])dnl
+ ],[
+    AC_CACHE_CHECK([for -l$1], ac_Lib_ext,
+	[AC_TRY_LINK_FUNC([main],
+                 [AS_VAR_SET(ac_Lib_ext, yes)],
+                 [AS_VAR_SET(ac_Lib_ext, no)])
+	])
+ ])
+LIBS=$ac_check_lib_ext_save_LIBS
+
+AS_IF([test AS_VAR_GET(ac_Lib_ext) = yes],
+    [m4_default([$4], 
+        [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1))
+		case "$$2" in
+		    *-l$1*)
+			;;
+		    *)
+			$2="-l$1 $$2"
+			;;
+		esac])
+		[$6]
+	    ],
+	    [$5])dnl
+AS_VAR_POPDEF([ac_Lib_ext])dnl
+])# AC_CHECK_LIB_EXT
+
+# AH_CHECK_LIB_EXT(LIBNAME)
+# ---------------------
+m4_define([AH_CHECK_LIB_EXT],
+[AH_TEMPLATE(AS_TR_CPP(HAVE_LIB$1),
+             [Define to 1 if you have the `]$1[' library (-l]$1[).])])
+
+dnl AC_SEARCH_LIBS_EXT(FUNCTION, SEARCH-LIBS, EXT_LIBS,
+dnl                    [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND],
+dnl                    [OTHER-LIBRARIES])
+dnl --------------------------------------------------------
+dnl Search for a library defining FUNC, if it's not already available.
+AC_DEFUN([AC_SEARCH_LIBS_EXT],
+[AC_CACHE_CHECK([for library containing $1], [ac_cv_search_ext_$1],
+[
+ac_func_search_ext_save_LIBS=$LIBS
+ac_cv_search_ext_$1=no
+AC_LINK_IFELSE([AC_LANG_CALL([], [$1])],
+	       [ac_cv_search_ext_$1="none required"])
+if test "$ac_cv_search_ext_$1" = no; then
+  for ac_lib in $2; do
+    LIBS="-l$ac_lib $$3 $6 $ac_func_search_save_ext_LIBS"
+    AC_LINK_IFELSE([AC_LANG_CALL([], [$1])],
+		   [ac_cv_search_ext_$1="-l$ac_lib"
+break])
+  done
+fi
+LIBS=$ac_func_search_ext_save_LIBS])
+AS_IF([test "$ac_cv_search_ext_$1" != no],
+  [test "$ac_cv_search_ext_$1" = "none required" || $3="$ac_cv_search_ext_$1 $$3"
+  $4],
+      [$5])dnl
+])
+
+dnl check for a function in a $LIBS and $OTHER_LIBS libraries variable.
+dnl AC_CHECK_FUNC_EXT(func,OTHER_LIBS,IF-TRUE,IF-FALSE)
+AC_DEFUN([AC_CHECK_FUNC_EXT],
+[
+    AH_CHECK_FUNC_EXT($1)	
+    ac_check_func_ext_save_LIBS=$LIBS
+    LIBS="$2 $LIBS"
+    AS_VAR_PUSHDEF([ac_var], [ac_cv_func_ext_$1])dnl
+    AC_CACHE_CHECK([for $1], ac_var,
+	[AC_LINK_IFELSE([AC_LANG_FUNC_LINK_TRY([$1])],
+                [AS_VAR_SET(ac_var, yes)],
+                [AS_VAR_SET(ac_var, no)])])
+    LIBS=$ac_check_func_ext_save_LIBS
+    AS_IF([test AS_VAR_GET(ac_var) = yes], 
+	    [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1])) $3], 
+	    [$4])dnl
+AS_VAR_POPDEF([ac_var])dnl
+])# AC_CHECK_FUNC
+
+# AH_CHECK_FUNC_EXT(FUNCNAME)
+# ---------------------
+m4_define([AH_CHECK_FUNC_EXT],
+[AH_TEMPLATE(AS_TR_CPP(HAVE_$1),
+             [Define to 1 if you have the `]$1[' function.])])
+
+dnl Define an AC_DEFINE with ifndef guard.
+dnl AC_N_DEFINE(VARIABLE [, VALUE])
+AC_DEFUN([AC_N_DEFINE],
+[
+AH_VERBATIM([$1], [
+#ifndef $1
+# undef $1
+#endif
+])
+
+ cat >>confdefs.h <<\EOF
+#ifndef $1
+[#define] $1 m4_if($#, 1, 1, [$2])
+#endif
+EOF
+])
+
+dnl Add an #include
+dnl AC_ADD_INCLUDE(VARIABLE)
+define(AC_ADD_INCLUDE,
+[cat >> confdefs.h <<\EOF
+[#include] $1
+EOF
+])
+
+dnl remove an #include
+dnl AC_REMOVE_INCLUDE(VARIABLE)
+define(AC_REMOVE_INCLUDE,
+[
+grep -v '[#include] $1' confdefs.h >confdefs.h.tmp
+cat confdefs.h.tmp > confdefs.h
+rm confdefs.h.tmp
+])
+
+dnl remove an #define
+dnl AC_REMOVE_DEFINE(VARIABLE)
+define(AC_REMOVE_DEFINE,
+[
+grep -v '[#define] $1 ' confdefs.h |grep -v '[#define] $1[$]'>confdefs.h.tmp
+cat confdefs.h.tmp > confdefs.h
+rm confdefs.h.tmp
+])
+
+dnl AS_HELP_STRING is not available in autoconf 2.57, and AC_HELP_STRING is deprecated
+dnl in autoconf 2.59, so define AS_HELP_STRING to be AC_HELP_STRING unless it is already
+dnl defined.
+m4_ifdef([AS_HELP_STRING], , [m4_define([AS_HELP_STRING], m4_defn([AC_HELP_STRING]))])
+
+dnl check if the prototype in the header matches the given one
+dnl AC_VERIFY_C_PROTOTYPE(prototype,functionbody,[IF-TRUE].[IF-FALSE],[extraheaders])
+AC_DEFUN(AC_VERIFY_C_PROTOTYPE,
+[AC_CACHE_CHECK([for prototype $1], AS_TR_SH([ac_cv_c_prototype_$1]),
+	AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+		AC_INCLUDES_DEFAULT
+		$5
+		$1
+		{
+			$2
+		}
+	])],[
+		AS_TR_SH([ac_cv_c_prototype_$1])=yes
+	],[
+		AS_TR_SH([ac_cv_c_prototype_$1])=no
+	])
+)
+AS_IF([test $AS_TR_SH([ac_cv_c_prototype_$1]) = yes],[$3],[$4])
+])
+
+AC_DEFUN(LIBREPLACE_PROVIDE_HEADER, 
+[AC_CHECK_HEADER([$1], 
+		[ AC_CONFIG_COMMANDS(rm-$1, [rm -f $libreplacedir/$1], [libreplacedir=$libreplacedir]) ],
+		[ AC_CONFIG_COMMANDS(mk-$1, [echo "#include \"replace.h\"" > $libreplacedir/$1], [libreplacedir=$libreplacedir]) ]
+	)
+])
+
+dnl AC_HAVE_TYPE(TYPE,INCLUDES)
+AC_DEFUN([AC_HAVE_TYPE], [
+AC_REQUIRE([AC_HEADER_STDC])
+cv=`echo "$1" | sed 'y%./+- %__p__%'`
+AC_MSG_CHECKING(for $1)
+AC_CACHE_VAL([ac_cv_type_$cv],
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+AC_INCLUDES_DEFAULT
+$2]],
+[[$1 foo;]])],
+[eval "ac_cv_type_$cv=yes"],
+[eval "ac_cv_type_$cv=no"]))dnl
+ac_foo=`eval echo \\$ac_cv_type_$cv`
+AC_MSG_RESULT($ac_foo)
+if test "$ac_foo" = yes; then
+  ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
+if false; then
+	AC_CHECK_TYPES($1)
+fi
+  AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1'])
+fi
+])

Added: branches/ctdb/squeeze-backports/lib/replace/repdir.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/repdir.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/repdir.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,78 @@
+AC_CACHE_CHECK([for broken readdir],libreplace_cv_READDIR_NEEDED,[
+	AC_TRY_RUN([
+#define test_readdir_os2_delete main
+#include "$libreplacedir/tests/os2_delete.c"],
+	[libreplace_cv_READDIR_NEEDED=no],
+	[libreplace_cv_READDIR_NEEDED=yes],
+	[libreplace_cv_READDIR_NEEDED="assuming not"])
+])
+
+#
+# try to replace with getdirentries() if needed
+#
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+AC_CHECK_FUNCS(getdirentries)
+AC_VERIFY_C_PROTOTYPE([long telldir(const DIR *dir)],
+	[
+	return 0;
+	],[
+	AC_DEFINE(TELLDIR_TAKES_CONST_DIR, 1, [Whether telldir takes a const pointer])
+	],[],[
+	#include <dirent.h>
+	])
+
+AC_VERIFY_C_PROTOTYPE([int seekdir(DIR *dir, long ofs)],
+	[
+	return 0;
+	],[
+	AC_DEFINE(SEEKDIR_RETURNS_INT, 1, [Whether seekdir returns an int])
+	],[],[
+	#include <dirent.h>
+	])
+AC_CACHE_CHECK([for replacing readdir using getdirentries()],libreplace_cv_READDIR_GETDIRENTRIES,[
+	AC_TRY_RUN([
+#define _LIBREPLACE_REPLACE_H
+#include "$libreplacedir/repdir_getdirentries.c"
+#define test_readdir_os2_delete main
+#include "$libreplacedir/tests/os2_delete.c"],
+	[libreplace_cv_READDIR_GETDIRENTRIES=yes],
+	[libreplace_cv_READDIR_GETDIRENTRIES=no])
+])
+fi
+if test x"$libreplace_cv_READDIR_GETDIRENTRIES" = x"yes"; then
+	AC_DEFINE(REPLACE_READDIR,1,[replace readdir])
+	AC_DEFINE(REPLACE_READDIR_GETDIRENTRIES,1,[replace readdir using getdirentries()])
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} repdir_getdirentries.o"
+	libreplace_cv_READDIR_NEEDED=no
+fi
+
+#
+# try to replace with getdents() if needed
+#
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+AC_CHECK_FUNCS(getdents)
+AC_CACHE_CHECK([for replacing readdir using getdents()],libreplace_cv_READDIR_GETDENTS,[
+	AC_TRY_RUN([
+#define _LIBREPLACE_REPLACE_H
+#error _donot_use_getdents_replacement_anymore
+#include "$libreplacedir/repdir_getdents.c"
+#define test_readdir_os2_delete main
+#include "$libreplacedir/tests/os2_delete.c"],
+	[libreplace_cv_READDIR_GETDENTS=yes],
+	[libreplace_cv_READDIR_GETDENTS=no])
+])
+fi
+if test x"$libreplace_cv_READDIR_GETDENTS" = x"yes"; then
+	AC_DEFINE(REPLACE_READDIR,1,[replace readdir])
+	AC_DEFINE(REPLACE_READDIR_GETDENTS,1,[replace readdir using getdents()])
+	LIBREPLACEOBJ="${LIBREPLACEOBJ} repdir_getdents.o"
+	libreplace_cv_READDIR_NEEDED=no
+fi
+
+AC_MSG_CHECKING([a usable readdir()])
+if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then
+	AC_MSG_RESULT(no)
+	AC_MSG_WARN([the provided readdir() is broken])
+else
+	AC_MSG_RESULT(yes)
+fi

Added: branches/ctdb/squeeze-backports/lib/replace/repdir_getdents.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/repdir_getdents.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/repdir_getdents.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,166 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Andrew Tridgell 2005
+
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+  a replacement for opendir/readdir/telldir/seekdir/closedir for BSD systems
+
+  This is needed because the existing directory handling in FreeBSD
+  and OpenBSD (and possibly NetBSD) doesn't correctly handle unlink()
+  on files in a directory where telldir() has been used. On a block
+  boundary it will occasionally miss a file when seekdir() is used to
+  return to a position previously recorded with telldir().
+
+  This also fixes a severe performance and memory usage problem with
+  telldir() on BSD systems. Each call to telldir() in BSD adds an
+  entry to a linked list, and those entries are cleaned up on
+  closedir(). This means with a large directory closedir() can take an
+  arbitrary amount of time, causing network timeouts as millions of
+  telldir() entries are freed
+
+  Note! This replacement code is not portable. It relies on getdents()
+  always leaving the file descriptor at a seek offset that is a
+  multiple of DIR_BUF_SIZE. If the code detects that this doesn't
+  happen then it will abort(). It also does not handle directories
+  with offsets larger than can be stored in a long,
+
+  This code is available under other free software licenses as
+  well. Contact the author.
+*/
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define DIR_BUF_BITS 9
+#define DIR_BUF_SIZE (1<<DIR_BUF_BITS)
+
+struct dir_buf {
+	int fd;
+	int nbytes, ofs;
+	off_t seekpos;
+	char buf[DIR_BUF_SIZE];
+};
+
+DIR *opendir(const char *dname)
+{
+	struct dir_buf *d;
+	struct stat sb;
+	d = malloc(sizeof(*d));
+	if (d == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	d->fd = open(dname, O_RDONLY);
+	if (d->fd == -1) {
+		free(d);
+		return NULL;
+	}
+	if (fstat(d->fd, &sb) < 0) {
+		close(d->fd);
+		free(d);
+		return NULL;
+	}
+	if (!S_ISDIR(sb.st_mode)) {
+		close(d->fd);
+		free(d);   
+		errno = ENOTDIR;
+		return NULL;
+	}
+	d->ofs = 0;
+	d->seekpos = 0;
+	d->nbytes = 0;
+	return (DIR *)d;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	struct dirent *de;
+
+	if (d->ofs >= d->nbytes) {
+		d->seekpos = lseek(d->fd, 0, SEEK_CUR);
+		d->nbytes = getdents(d->fd, d->buf, DIR_BUF_SIZE);
+		d->ofs = 0;
+	}
+	if (d->ofs >= d->nbytes) {
+		return NULL;
+	}
+	de = (struct dirent *)&d->buf[d->ofs];
+	d->ofs += de->d_reclen;
+	return de;
+}
+
+long telldir(DIR *dir)
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	if (d->ofs >= d->nbytes) {
+		d->seekpos = lseek(d->fd, 0, SEEK_CUR);
+		d->ofs = 0;
+		d->nbytes = 0;
+	}
+	/* this relies on seekpos always being a multiple of
+	   DIR_BUF_SIZE. Is that always true on BSD systems? */
+	if (d->seekpos & (DIR_BUF_SIZE-1)) {
+		abort();
+	}
+	return d->seekpos + d->ofs;
+}
+
+void seekdir(DIR *dir, long ofs)
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	d->seekpos = lseek(d->fd, ofs & ~(DIR_BUF_SIZE-1), SEEK_SET);
+	d->nbytes = getdents(d->fd, d->buf, DIR_BUF_SIZE);
+	d->ofs = 0;
+	while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) {
+		if (readdir(dir) == NULL) break;
+	}
+}
+
+void rewinddir(DIR *dir)
+{
+	seekdir(dir, 0);
+}
+
+int closedir(DIR *dir)
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	int r = close(d->fd);
+	if (r != 0) {
+		return r;
+	}
+	free(d);
+	return 0;
+}
+
+#ifndef dirfd
+/* darn, this is a macro on some systems. */
+int dirfd(DIR *dir)
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	return d->fd;
+}
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/repdir_getdirentries.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/repdir_getdirentries.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/repdir_getdirentries.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,183 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Andrew Tridgell 2005
+
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+  a replacement for opendir/readdir/telldir/seekdir/closedir for BSD
+  systems using getdirentries
+
+  This is needed because the existing directory handling in FreeBSD
+  and OpenBSD (and possibly NetBSD) doesn't correctly handle unlink()
+  on files in a directory where telldir() has been used. On a block
+  boundary it will occasionally miss a file when seekdir() is used to
+  return to a position previously recorded with telldir().
+
+  This also fixes a severe performance and memory usage problem with
+  telldir() on BSD systems. Each call to telldir() in BSD adds an
+  entry to a linked list, and those entries are cleaned up on
+  closedir(). This means with a large directory closedir() can take an
+  arbitrary amount of time, causing network timeouts as millions of
+  telldir() entries are freed
+
+  Note! This replacement code is not portable. It relies on
+  getdirentries() always leaving the file descriptor at a seek offset
+  that is a multiple of DIR_BUF_SIZE. If the code detects that this
+  doesn't happen then it will abort(). It also does not handle
+  directories with offsets larger than can be stored in a long,
+
+  This code is available under other free software licenses as
+  well. Contact the author.
+*/
+
+#include "replace.h"
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define DIR_BUF_BITS 9
+#define DIR_BUF_SIZE (1<<DIR_BUF_BITS)
+
+struct dir_buf {
+	int fd;
+	int nbytes, ofs;
+	off_t seekpos;
+	char buf[DIR_BUF_SIZE];
+};
+
+DIR *opendir(const char *dname)
+{
+	struct dir_buf *d;
+	struct stat sb;
+	d = malloc(sizeof(*d));
+	if (d == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	d->fd = open(dname, O_RDONLY);
+	if (d->fd == -1) {
+		free(d);
+		return NULL;
+	}
+	if (fstat(d->fd, &sb) < 0) {
+		close(d->fd);
+		free(d);
+		return NULL;
+	}
+	if (!S_ISDIR(sb.st_mode)) {
+		close(d->fd);
+		free(d);   
+		errno = ENOTDIR;
+		return NULL;
+	}
+	d->ofs = 0;
+	d->seekpos = 0;
+	d->nbytes = 0;
+	return (DIR *)d;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	struct dirent *de;
+
+	if (d->ofs >= d->nbytes) {
+		long pos;
+		d->nbytes = getdirentries(d->fd, d->buf, DIR_BUF_SIZE, &pos);
+		d->seekpos = pos;
+		d->ofs = 0;
+	}
+	if (d->ofs >= d->nbytes) {
+		return NULL;
+	}
+	de = (struct dirent *)&d->buf[d->ofs];
+	d->ofs += de->d_reclen;
+	return de;
+}
+
+#ifdef TELLDIR_TAKES_CONST_DIR
+long telldir(const DIR *dir)
+#else
+long telldir(DIR *dir)
+#endif
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	if (d->ofs >= d->nbytes) {
+		d->seekpos = lseek(d->fd, 0, SEEK_CUR);
+		d->ofs = 0;
+		d->nbytes = 0;
+	}
+	/* this relies on seekpos always being a multiple of
+	   DIR_BUF_SIZE. Is that always true on BSD systems? */
+	if (d->seekpos & (DIR_BUF_SIZE-1)) {
+		abort();
+	}
+	return d->seekpos + d->ofs;
+}
+
+#ifdef SEEKDIR_RETURNS_INT
+int seekdir(DIR *dir, long ofs)
+#else
+void seekdir(DIR *dir, long ofs)
+#endif
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	long pos;
+	d->seekpos = lseek(d->fd, ofs & ~(DIR_BUF_SIZE-1), SEEK_SET);
+	d->nbytes = getdirentries(d->fd, d->buf, DIR_BUF_SIZE, &pos);
+	d->ofs = 0;
+	while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) {
+		if (readdir(dir) == NULL) break;
+	}
+#ifdef SEEKDIR_RETURNS_INT
+	return -1;
+#endif
+}
+
+void rewinddir(DIR *dir)
+{
+	seekdir(dir, 0);
+}
+
+int closedir(DIR *dir)
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	int r = close(d->fd);
+	if (r != 0) {
+		return r;
+	}
+	free(d);
+	return 0;
+}
+
+#ifndef dirfd
+/* darn, this is a macro on some systems. */
+int dirfd(DIR *dir)
+{
+	struct dir_buf *d = (struct dir_buf *)dir;
+	return d->fd;
+}
+#endif
+
+

Added: branches/ctdb/squeeze-backports/lib/replace/replace.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/replace.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/replace.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,623 @@
+/* 
+   Unix SMB/CIFS implementation.
+   replacement routines for broken systems
+   Copyright (C) Andrew Tridgell 1992-1998
+
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/passwd.h"
+#include "system/syslog.h"
+#include "system/network.h"
+#include "system/locale.h"
+#include "system/wait.h"
+
+void replace_dummy(void);
+void replace_dummy(void) {}
+
+#ifndef HAVE_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+int rep_ftruncate(int f, off_t l)
+{
+#ifdef HAVE_CHSIZE
+      return chsize(f,l);
+#elif defined(F_FREESP)
+      struct  flock   fl;
+
+      fl.l_whence = 0;
+      fl.l_len = 0;
+      fl.l_start = l;
+      fl.l_type = F_WRLCK;
+      return fcntl(f, F_FREESP, &fl);
+#else
+#error "you must have a ftruncate function"
+#endif
+}
+#endif /* HAVE_FTRUNCATE */
+
+
+#ifndef HAVE_STRLCPY
+/* like strncpy but does not 0 fill the buffer and always null 
+   terminates. bufsize is the size of the destination buffer */
+size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
+{
+	size_t len = strlen(s);
+	size_t ret = len;
+	if (bufsize <= 0) return 0;
+	if (len >= bufsize) len = bufsize-1;
+	memcpy(d, s, len);
+	d[len] = 0;
+	return ret;
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+/* like strncat but does not 0 fill the buffer and always null 
+   terminates. bufsize is the length of the buffer, which should
+   be one more than the maximum resulting string length */
+size_t rep_strlcat(char *d, const char *s, size_t bufsize)
+{
+	size_t len1 = strlen(d);
+	size_t len2 = strlen(s);
+	size_t ret = len1 + len2;
+
+	if (len1+len2 >= bufsize) {
+		len2 = bufsize - (len1+1);
+	}
+	if (len2 > 0) {
+		memcpy(d+len1, s, len2);
+		d[len1+len2] = 0;
+	}
+	return ret;
+}
+#endif
+
+#ifndef HAVE_MKTIME
+/*******************************************************************
+a mktime() replacement for those who don't have it - contributed by 
+C.A. Lademann <cal at zls.com>
+Corrections by richard.kettlewell at kewill.com
+********************************************************************/
+
+#define  MINUTE  60
+#define  HOUR    60*MINUTE
+#define  DAY             24*HOUR
+#define  YEAR    365*DAY
+time_t rep_mktime(struct tm *t)
+{
+  struct tm       *u;
+  time_t  epoch = 0;
+  int n;
+  int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+  y, m, i;
+
+  if(t->tm_year < 70)
+    return((time_t)-1);
+
+  n = t->tm_year + 1900 - 1;
+  epoch = (t->tm_year - 70) * YEAR + 
+    ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
+
+  y = t->tm_year + 1900;
+  m = 0;
+
+  for(i = 0; i < t->tm_mon; i++) {
+    epoch += mon [m] * DAY;
+    if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+      epoch += DAY;
+    
+    if(++m > 11) {
+      m = 0;
+      y++;
+    }
+  }
+
+  epoch += (t->tm_mday - 1) * DAY;
+  epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+  
+  if((u = localtime(&epoch)) != NULL) {
+    t->tm_sec = u->tm_sec;
+    t->tm_min = u->tm_min;
+    t->tm_hour = u->tm_hour;
+    t->tm_mday = u->tm_mday;
+    t->tm_mon = u->tm_mon;
+    t->tm_year = u->tm_year;
+    t->tm_wday = u->tm_wday;
+    t->tm_yday = u->tm_yday;
+    t->tm_isdst = u->tm_isdst;
+  }
+
+  return(epoch);
+}
+#endif /* !HAVE_MKTIME */
+
+
+#ifndef HAVE_INITGROUPS
+/****************************************************************************
+ some systems don't have an initgroups call 
+****************************************************************************/
+int rep_initgroups(char *name, gid_t id)
+{
+#ifndef HAVE_SETGROUPS
+	/* yikes! no SETGROUPS or INITGROUPS? how can this work? */
+	errno = ENOSYS;
+	return -1;
+#else /* HAVE_SETGROUPS */
+
+#include <grp.h>
+
+	gid_t *grouplst = NULL;
+	int max_gr = 32;
+	int ret;
+	int    i,j;
+	struct group *g;
+	char   *gr;
+	
+	if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	grouplst[0] = id;
+	i = 1;
+	while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
+		if (g->gr_gid == id)
+			continue;
+		j = 0;
+		gr = g->gr_mem[0];
+		while (gr && (*gr != (char)NULL)) {
+			if (strcmp(name,gr) == 0) {
+				grouplst[i] = g->gr_gid;
+				i++;
+				gr = (char *)NULL;
+				break;
+			}
+			gr = g->gr_mem[++j];
+		}
+	}
+	endgrent();
+	ret = setgroups(i, grouplst);
+	free(grouplst);
+	return ret;
+#endif /* HAVE_SETGROUPS */
+}
+#endif /* HAVE_INITGROUPS */
+
+
+#if (defined(SecureWare) && defined(SCO))
+/* This is needed due to needing the nap() function but we don't want
+   to include the Xenix libraries since that will break other things...
+   BTW: system call # 0x0c28 is the same as calling nap() */
+long nap(long milliseconds) {
+	 return syscall(0x0c28, milliseconds);
+ }
+#endif
+
+
+#ifndef HAVE_MEMMOVE
+/*******************************************************************
+safely copies memory, ensuring no overlap problems.
+this is only used if the machine does not have it's own memmove().
+this is not the fastest algorithm in town, but it will do for our
+needs.
+********************************************************************/
+void *rep_memmove(void *dest,const void *src,int size)
+{
+	unsigned long d,s;
+	int i;
+	if (dest==src || !size) return(dest);
+
+	d = (unsigned long)dest;
+	s = (unsigned long)src;
+
+	if ((d >= (s+size)) || (s >= (d+size))) {
+		/* no overlap */
+		memcpy(dest,src,size);
+		return(dest);
+	}
+
+	if (d < s) {
+		/* we can forward copy */
+		if (s-d >= sizeof(int) && 
+		    !(s%sizeof(int)) && 
+		    !(d%sizeof(int)) && 
+		    !(size%sizeof(int))) {
+			/* do it all as words */
+			int *idest = (int *)dest;
+			int *isrc = (int *)src;
+			size /= sizeof(int);
+			for (i=0;i<size;i++) idest[i] = isrc[i];
+		} else {
+			/* simplest */
+			char *cdest = (char *)dest;
+			char *csrc = (char *)src;
+			for (i=0;i<size;i++) cdest[i] = csrc[i];
+		}
+	} else {
+		/* must backward copy */
+		if (d-s >= sizeof(int) && 
+		    !(s%sizeof(int)) && 
+		    !(d%sizeof(int)) && 
+		    !(size%sizeof(int))) {
+			/* do it all as words */
+			int *idest = (int *)dest;
+			int *isrc = (int *)src;
+			size /= sizeof(int);
+			for (i=size-1;i>=0;i--) idest[i] = isrc[i];
+		} else {
+			/* simplest */
+			char *cdest = (char *)dest;
+			char *csrc = (char *)src;
+			for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
+		}      
+	}
+	return(dest);
+}
+#endif /* HAVE_MEMMOVE */
+
+#ifndef HAVE_STRDUP
+/****************************************************************************
+duplicate a string
+****************************************************************************/
+char *rep_strdup(const char *s)
+{
+	size_t len;
+	char *ret;
+
+	if (!s) return(NULL);
+
+	len = strlen(s)+1;
+	ret = (char *)malloc(len);
+	if (!ret) return(NULL);
+	memcpy(ret,s,len);
+	return(ret);
+}
+#endif /* HAVE_STRDUP */
+
+#ifndef WITH_PTHREADS
+/* REWRITE: not thread safe */
+#ifdef REPLACE_INET_NTOA
+char *rep_inet_ntoa(struct in_addr ip)
+{
+	uint8_t *p = (uint8_t *)&ip.s_addr;
+	static char buf[18];
+	slprintf(buf, 17, "%d.%d.%d.%d", 
+		 (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+	return buf;
+}
+#endif /* REPLACE_INET_NTOA */
+#endif
+
+#ifndef HAVE_SETLINEBUF
+void rep_setlinebuf(FILE *stream)
+{
+	setvbuf(stream, (char *)NULL, _IOLBF, 0);
+}
+#endif /* HAVE_SETLINEBUF */
+
+#ifndef HAVE_VSYSLOG
+#ifdef HAVE_SYSLOG
+void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
+{
+	char *msg = NULL;
+	vasprintf(&msg, format, arglist);
+	if (!msg)
+		return;
+	syslog(facility_priority, "%s", msg);
+	free(msg);
+}
+#endif /* HAVE_SYSLOG */
+#endif /* HAVE_VSYSLOG */
+
+#ifndef HAVE_STRNLEN
+/**
+ Some platforms don't have strnlen
+**/
+ size_t rep_strnlen(const char *s, size_t max)
+{
+        size_t len;
+  
+        for (len = 0; len < max; len++) {
+                if (s[len] == '\0') {
+                        break;
+                }
+        }
+        return len;  
+}
+#endif
+  
+#ifndef HAVE_STRNDUP
+/**
+ Some platforms don't have strndup.
+**/
+char *rep_strndup(const char *s, size_t n)
+{
+	char *ret;
+	
+	n = strnlen(s, n);
+	ret = malloc(n+1);
+	if (!ret)
+		return NULL;
+	memcpy(ret, s, n);
+	ret[n] = 0;
+
+	return ret;
+}
+#endif
+
+#ifndef HAVE_WAITPID
+int rep_waitpid(pid_t pid,int *status,int options)
+{
+  return wait4(pid, status, options, NULL);
+}
+#endif
+
+#ifndef HAVE_SETEUID
+int rep_seteuid(uid_t euid)
+{
+#ifdef HAVE_SETRESUID
+	return setresuid(-1, euid, -1);
+#else
+#  error "You need a seteuid function"
+#endif
+}
+#endif
+
+#ifndef HAVE_SETEGID
+int rep_setegid(gid_t egid)
+{
+#ifdef HAVE_SETRESGID
+	return setresgid(-1, egid, -1);
+#else
+#  error "You need a setegid function"
+#endif
+}
+#endif
+
+/*******************************************************************
+os/2 also doesn't have chroot
+********************************************************************/
+#ifndef HAVE_CHROOT
+int rep_chroot(const char *dname)
+{
+	errno = ENOSYS;
+	return -1;
+}
+#endif
+
+/*****************************************************************
+ Possibly replace mkstemp if it is broken.
+*****************************************************************/  
+
+#ifndef HAVE_SECURE_MKSTEMP
+int rep_mkstemp(char *template)
+{
+	/* have a reasonable go at emulating it. Hope that
+	   the system mktemp() isn't completly hopeless */
+	char *p = mktemp(template);
+	if (!p)
+		return -1;
+	return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
+}
+#endif
+
+#ifndef HAVE_MKDTEMP
+char *rep_mkdtemp(char *template)
+{
+	char *dname;
+	
+	if ((dname = mktemp(template))) {
+		if (mkdir(dname, 0700) >= 0) {
+			return dname;
+		}
+	}
+
+	return NULL;
+}
+#endif
+
+/*****************************************************************
+ Watch out: this is not thread safe.
+*****************************************************************/
+
+#ifndef HAVE_PREAD
+ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
+{
+	if (lseek(__fd, __offset, SEEK_SET) != __offset) {
+		return -1;
+	}
+	return read(__fd, __buf, __nbytes);
+}
+#endif
+
+/*****************************************************************
+ Watch out: this is not thread safe.
+*****************************************************************/
+
+#ifndef HAVE_PWRITE
+ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
+{
+	if (lseek(__fd, __offset, SEEK_SET) != __offset) {
+		return -1;
+	}
+	return write(__fd, __buf, __nbytes);
+}
+#endif
+
+#ifndef HAVE_STRCASESTR
+char *rep_strcasestr(const char *haystack, const char *needle)
+{
+	const char *s;
+	size_t nlen = strlen(needle);
+	for (s=haystack;*s;s++) {
+		if (toupper(*needle) == toupper(*s) &&
+		    strncasecmp(s, needle, nlen) == 0) {
+			return (char *)((intptr_t)s);
+		}
+	}
+	return NULL;
+}
+#endif
+
+#ifndef HAVE_STRTOK_R
+/* based on GLIBC version, copyright Free Software Foundation */
+char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
+{
+	char *token;
+
+	if (s == NULL) s = *save_ptr;
+
+	s += strspn(s, delim);
+	if (*s == '\0') {
+		*save_ptr = s;
+		return NULL;
+	}
+
+	token = s;
+	s = strpbrk(token, delim);
+	if (s == NULL) {
+		*save_ptr = token + strlen(token);
+	} else {
+		*s = '\0';
+		*save_ptr = s + 1;
+	}
+
+	return token;
+}
+#endif
+
+#ifndef HAVE_STRTOLL
+long long int rep_strtoll(const char *str, char **endptr, int base)
+{
+#ifdef HAVE_STRTOQ
+	return strtoq(str, endptr, base);
+#elif defined(HAVE___STRTOLL) 
+	return __strtoll(str, endptr, base);
+#elif SIZEOF_LONG == SIZEOF_LONG_LONG
+	return (long long int) strtol(str, endptr, base);
+#else
+# error "You need a strtoll function"
+#endif
+}
+#endif
+
+
+#ifndef HAVE_STRTOULL
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
+{
+#ifdef HAVE_STRTOUQ
+	return strtouq(str, endptr, base);
+#elif defined(HAVE___STRTOULL) 
+	return __strtoull(str, endptr, base);
+#elif SIZEOF_LONG == SIZEOF_LONG_LONG
+	return (unsigned long long int) strtoul(str, endptr, base);
+#else
+# error "You need a strtoull function"
+#endif
+}
+#endif
+
+#ifndef HAVE_SETENV
+int rep_setenv(const char *name, const char *value, int overwrite) 
+{
+	char *p;
+	size_t l1, l2;
+	int ret;
+
+	if (!overwrite && getenv(name)) {
+		return 0;
+	}
+
+	l1 = strlen(name);
+	l2 = strlen(value);
+
+	p = malloc(l1+l2+2);
+	if (p == NULL) {
+		return -1;
+	}
+	memcpy(p, name, l1);
+	p[l1] = '=';
+	memcpy(p+l1+1, value, l2);
+	p[l1+l2+1] = 0;
+
+	ret = putenv(p);
+	if (ret != 0) {
+		free(p);
+	}
+
+	return ret;
+}
+#endif
+
+#ifndef HAVE_UNSETENV
+int rep_unsetenv(const char *name)
+{
+	extern char **environ;
+	size_t len = strlen(name);
+	size_t i, count;
+
+	if (environ == NULL || getenv(name) == NULL) {
+		return 0;
+	}
+
+	for (i=0;environ[i];i++) /* noop */ ;
+
+	count=i;
+	
+	for (i=0;i<count;) {
+		if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
+			/* note: we do _not_ free the old variable here. It is unsafe to 
+			   do so, as the pointer may not have come from malloc */
+			memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
+			count--;
+		} else {
+			i++;
+		}
+	}
+
+	return 0;
+}
+#endif
+
+#ifndef HAVE_SOCKETPAIR
+int rep_socketpair(int d, int type, int protocol, int sv[2])
+{
+	if (d != AF_UNIX) {
+		errno = EAFNOSUPPORT;
+		return -1;
+	}
+
+	if (protocol != 0) {
+		errno = EPROTONOSUPPORT;
+		return -1;
+	}
+
+	if (type != SOCK_STREAM) {
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	return pipe(sv);
+}
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/replace.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/replace.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/replace.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,552 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   macros to go along with the lib/replace/ portability layer code
+
+   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Jelmer Vernooij 2006
+   Copyright (C) Jeremy Allison 2007.
+
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LIBREPLACE_REPLACE_H
+#define _LIBREPLACE_REPLACE_H
+
+#ifndef NO_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STANDARDS_H
+#include <standards.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include "win32_replace.h"
+#endif
+
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+/* force off HAVE_INTTYPES_H so that roken doesn't try to include both,
+   which causes a warning storm on irix */
+#undef HAVE_INTTYPES_H
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+
+#ifndef HAVE_STRERROR
+extern char *sys_errlist[];
+#define strerror(i) sys_errlist[i]
+#endif
+
+#ifndef HAVE_ERRNO_DECL
+extern int errno;
+#endif
+
+#ifndef HAVE_STRDUP
+#define strdup rep_strdup
+char *rep_strdup(const char *s);
+#endif
+
+#ifndef HAVE_MEMMOVE
+#define memmove rep_memmove
+void *rep_memmove(void *dest,const void *src,int size);
+#endif
+
+#ifndef HAVE_MKTIME
+#define mktime rep_mktime
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_TIMEGM
+#define timegm rep_timegm
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_STRLCPY
+#define strlcpy rep_strlcpy
+size_t rep_strlcpy(char *d, const char *s, size_t bufsize);
+#endif
+
+#ifndef HAVE_STRLCAT
+#define strlcat rep_strlcat
+size_t rep_strlcat(char *d, const char *s, size_t bufsize);
+#endif
+
+#if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP))
+#undef HAVE_STRNDUP
+#define strndup rep_strndup
+char *rep_strndup(const char *s, size_t n);
+#endif
+
+#if (defined(BROKEN_STRNLEN) || !defined(HAVE_STRNLEN))
+#undef HAVE_STRNLEN
+#define strnlen rep_strnlen
+size_t rep_strnlen(const char *s, size_t n);
+#endif
+
+#ifndef HAVE_SETENV
+#define setenv rep_setenv
+int rep_setenv(const char *name, const char *value, int overwrite);
+#else
+#ifndef HAVE_SETENV_DECL
+int setenv(const char *name, const char *value, int overwrite);
+#endif
+#endif
+
+#ifndef HAVE_UNSETENV
+#define unsetenv rep_unsetenv
+int rep_unsetenv(const char *name);
+#endif
+
+#ifndef HAVE_SETEUID
+#define seteuid rep_seteuid
+int rep_seteuid(uid_t);
+#endif
+
+#ifndef HAVE_SETEGID
+#define setegid rep_setegid
+int rep_setegid(gid_t);
+#endif
+
+#ifndef HAVE_SETLINEBUF
+#define setlinebuf rep_setlinebuf
+void rep_setlinebuf(FILE *);
+#endif
+
+#ifndef HAVE_STRCASESTR
+#define strcasestr rep_strcasestr
+char *rep_strcasestr(const char *haystack, const char *needle);
+#endif
+
+#ifndef HAVE_STRTOK_R
+#define strtok_r rep_strtok_r
+char *rep_strtok_r(char *s, const char *delim, char **save_ptr);
+#endif
+
+#ifndef HAVE_STRTOLL
+#define strtoll rep_strtoll
+long long int rep_strtoll(const char *str, char **endptr, int base);
+#endif
+
+#ifndef HAVE_STRTOULL
+#define strtoull rep_strtoull
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base);
+#endif
+
+#ifndef HAVE_FTRUNCATE
+#define ftruncate rep_ftruncate
+int rep_ftruncate(int,off_t);
+#endif
+
+#ifndef HAVE_INITGROUPS
+#define initgroups rep_initgroups
+int rep_initgroups(char *name, gid_t id);
+#endif
+
+#if !defined(HAVE_BZERO) && defined(HAVE_MEMSET)
+#define bzero(a,b) memset((a),'\0',(b))
+#endif
+
+#ifndef HAVE_DLERROR
+#define dlerror rep_dlerror
+char *rep_dlerror(void);
+#endif
+
+#ifndef HAVE_DLOPEN
+#define dlopen rep_dlopen
+#ifdef DLOPEN_TAKES_UNSIGNED_FLAGS
+void *rep_dlopen(const char *name, unsigned int flags);
+#else
+void *rep_dlopen(const char *name, int flags);
+#endif
+#endif
+
+#ifndef HAVE_DLSYM
+#define dlsym rep_dlsym
+void *rep_dlsym(void *handle, const char *symbol);
+#endif
+
+#ifndef HAVE_DLCLOSE
+#define dlclose rep_dlclose
+int rep_dlclose(void *handle);
+#endif
+
+#ifndef HAVE_SOCKETPAIR
+#define socketpair rep_socketpair
+int rep_socketpair(int d, int type, int protocol, int sv[2]);
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 )
+/** Use gcc attribute to check printf fns.  a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+#ifndef _DEPRECATED_
+#if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 )
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+
+#ifndef HAVE_VASPRINTF
+#define vasprintf rep_vasprintf
+int rep_vasprintf(char **ptr, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
+#endif
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define snprintf rep_snprintf
+int rep_snprintf(char *,size_t ,const char *, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define vsnprintf rep_vsnprintf
+int rep_vsnprintf(char *,size_t ,const char *, va_list ap) PRINTF_ATTRIBUTE(3,0);
+#endif
+
+#ifndef HAVE_ASPRINTF
+#define asprintf rep_asprintf
+int rep_asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3);
+#endif
+
+#ifndef HAVE_VSYSLOG
+#ifdef HAVE_SYSLOG
+#define vsyslog rep_vsyslog
+void rep_vsyslog (int facility_priority, const char *format, va_list arglist) PRINTF_ATTRIBUTE(2,0);
+#endif
+#endif
+
+/* we used to use these fns, but now we have good replacements
+   for snprintf and vsnprintf */
+#define slprintf snprintf
+
+
+#ifndef HAVE_VA_COPY
+#undef va_copy
+#ifdef HAVE___VA_COPY
+#define va_copy(dest, src) __va_copy(dest, src)
+#else
+#define va_copy(dest, src) (dest) = (src)
+#endif
+#endif
+
+#ifndef HAVE_VOLATILE
+#define volatile
+#endif
+
+#ifndef HAVE_COMPARISON_FN_T
+typedef int (*comparison_fn_t)(const void *, const void *);
+#endif
+
+#ifdef REPLACE_STRPTIME
+#define strptime rep_strptime
+struct tm;
+char *rep_strptime(const char *buf, const char *format, struct tm *tm);
+#endif
+
+/* Load header file for dynamic linking stuff */
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+
+#ifndef HAVE_SECURE_MKSTEMP
+#define mkstemp(path) rep_mkstemp(path)
+int rep_mkstemp(char *temp);
+#endif
+
+#ifndef HAVE_MKDTEMP
+#define mkdtemp rep_mkdtemp
+char *rep_mkdtemp(char *template);
+#endif
+
+#ifndef HAVE_PREAD
+#define pread rep_pread
+ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset);
+#endif
+
+#ifndef HAVE_PWRITE
+#define pwrite rep_pwrite
+ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset);
+#endif
+
+#ifdef REPLACE_INET_NTOA
+#define inet_ntoa rep_inet_ntoa
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_INET_PTON
+#define inet_pton rep_inet_pton
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_INET_NTOP
+#define inet_ntop rep_inet_ntop
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_GETIFADDRS
+#define getifaddrs rep_getifaddrs
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_FREEIFADDRS
+#define freeifaddrs rep_freeifaddrs
+/* prototype is in "system/network.h" */
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+/* The extra casts work around common compiler bugs.  */
+#define _TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
+   It is necessary at least when t == time_t.  */
+#define _TYPE_MINIMUM(t) ((t) (_TYPE_SIGNED (t) \
+  			      ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
+#define _TYPE_MAXIMUM(t) ((t) (~ (t) 0 - _TYPE_MINIMUM (t)))
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+/*
+ * Some older systems seem not to have MAXHOSTNAMELEN
+ * defined.
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN HOST_NAME_MAX
+#endif
+
+#ifndef UINT16_MAX
+#define UINT16_MAX 65535
+#endif
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef UINT64_MAX
+#define UINT64_MAX ((uint64_t)-1)
+#endif
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef INT32_MAX
+#define INT32_MAX _TYPE_MAXIMUM(int32_t)
+#endif
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+#if !defined(HAVE_BOOL)
+#ifdef HAVE__Bool
+#define bool _Bool
+#else
+typedef int bool;
+#endif
+#endif
+
+/*
+ * to prevent <rpcsvc/yp_prot.h> from doing a redefine of 'bool'
+ *
+ * IRIX, HPUX, MacOS 10 and Solaris need BOOL_DEFINED
+ * Tru64 needs _BOOL_EXISTS
+ * AIX needs _BOOL,_TRUE,_FALSE
+ */
+#ifndef BOOL_DEFINED
+#define BOOL_DEFINED
+#endif
+#ifndef _BOOL_EXISTS
+#define _BOOL_EXISTS
+#endif
+#ifndef _BOOL
+#define _BOOL
+#endif
+
+#ifndef __bool_true_false_are_defined
+#define __bool_true_false_are_defined
+#endif
+
+#ifndef true
+#define true (1)
+#endif
+#ifndef false
+#define false (0)
+#endif
+
+#ifndef _TRUE
+#define _TRUE true
+#endif
+#ifndef _FALSE
+#define _FALSE false
+#endif
+
+#ifndef HAVE_FUNCTION_MACRO
+#ifdef HAVE_func_MACRO
+#define __FUNCTION__ __func__
+#else
+#define __FUNCTION__ ("")
+#endif
+#endif
+
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#if !defined(HAVE_VOLATILE)
+#define volatile
+#endif
+
+/**
+  this is a warning hack. The idea is to use this everywhere that we
+  get the "discarding const" warning from gcc. That doesn't actually
+  fix the problem of course, but it means that when we do get to
+  cleaning them up we can do it by searching the code for
+  discard_const.
+
+  It also means that other error types aren't as swamped by the noise
+  of hundreds of const warnings, so we are more likely to notice when
+  we get new errors.
+
+  Please only add more uses of this macro when you find it
+  _really_ hard to fix const warnings. Our aim is to eventually use
+  this function in only a very few places.
+
+  Also, please call this via the discard_const_p() macro interface, as that
+  makes the return type safe.
+*/
+#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
+
+/** Type-safe version of discard_const */
+#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
+
+#ifndef __STRING
+#define __STRING(x)    #x
+#endif
+
+#ifndef __STRINGSTRING
+#define __STRINGSTRING(x) __STRING(x)
+#endif
+
+#ifndef __LINESTR__
+#define __LINESTR__ __STRINGSTRING(__LINE__)
+#endif
+
+#ifndef __location__
+#define __location__ __FILE__ ":" __LINESTR__
+#endif
+
+/** 
+ * zero a structure 
+ */
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+
+/** 
+ * zero a structure given a pointer to the structure 
+ */
+#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
+
+/** 
+ * zero a structure given a pointer to the structure - no zero check 
+ */
+#define ZERO_STRUCTPN(x) memset((char *)(x), 0, sizeof(*(x)))
+
+/* zero an array - note that sizeof(array) must work - ie. it must not be a
+   pointer */
+#define ZERO_ARRAY(x) memset((char *)(x), 0, sizeof(x))
+
+/**
+ * work out how many elements there are in a static array 
+ */
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/** 
+ * pointer difference macro 
+ */
+#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
+
+#if MMAP_BLACKLIST
+#undef HAVE_MMAP
+#endif
+
+#ifdef __COMPAR_FN_T
+#define QSORT_CAST (__compar_fn_t)
+#endif
+
+#ifndef QSORT_CAST
+#define QSORT_CAST (int (*)(const void *, const void *))
+#endif
+
+/* These should be properly defined for libraries to control visibility. */
+#define _PRIVATE_
+#define _PUBLIC_
+#endif /* _LIBREPLACE_REPLACE_H */

Added: branches/ctdb/squeeze-backports/lib/replace/samba.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/samba.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/samba.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+AC_LIBREPLACE_BROKEN_CHECKS
+
+SMB_EXT_LIB(LIBREPLACE_EXT, [${LIBDL}])
+SMB_ENABLE(LIBREPLACE_EXT)
+
+# remove leading ./
+LIBREPLACE_DIR=`echo ${libreplacedir} |sed -e 's/^\.\///g'`
+
+# remove leading srcdir .. we are looking for the relative
+# path within the samba source tree or wherever libreplace is.
+# We need to make sure the object is not forced to end up in
+# the source directory because we might be using a separate
+# build directory.
+LIBREPLACE_DIR=`echo ${LIBREPLACE_DIR} | sed -e "s|^$srcdir/||g"`
+
+LIBREPLACE_OBJS=""
+for obj in ${LIBREPLACEOBJ}; do
+	LIBREPLACE_OBJS="${LIBREPLACE_OBJS} ${LIBREPLACE_DIR}/${obj}"
+done
+
+SMB_SUBSYSTEM(LIBREPLACE,
+	[${LIBREPLACE_OBJS}],
+	[LIBREPLACE_EXT],
+	[-Ilib/replace])
+
+LIBREPLACE_HOSTCC_OBJS=`echo ${LIBREPLACE_OBJS} |sed -e 's/\.o/\.ho/g'`
+
+SMB_SUBSYSTEM(LIBREPLACE_HOSTCC,
+	[${LIBREPLACE_HOSTCC_OBJS}],
+	[],
+	[-Ilib/replace])

Added: branches/ctdb/squeeze-backports/lib/replace/snprintf.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/snprintf.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/snprintf.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1530 @@
+/*
+ * NOTE: If you change this file, please merge it into rsync, samba, etc.
+ */
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell at astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ * 
+ *  Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats. 
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ *  Andrew Tridgell (tridge at samba.org) Oct 1998
+ *    fixed handling of %.0f
+ *    added test for HAVE_LONG_DOUBLE
+ *
+ * tridge at samba.org, idra at samba.org, April 2001
+ *    got rid of fcvt code (twas buggy and made testing harder)
+ *    added C99 semantics
+ *
+ * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
+ * actually print args for %g and %e
+ * 
+ * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
+ * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
+ * see any include file that is guaranteed to be here, so I'm defining it
+ * locally.  Fixes AIX and Solaris builds.
+ * 
+ * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
+ * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
+ * functions
+ * 
+ * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
+ * Fix usage of va_list passed as an arg.  Use __va_copy before using it
+ * when it exists.
+ * 
+ * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
+ * Fix incorrect zpadlen handling in fmtfp.
+ * Thanks to Ollie Oldham <ollie.oldham at metro-optix.com> for spotting it.
+ * few mods to make it easier to compile the tests.
+ * addedd the "Ollie" test to the floating point ones.
+ *
+ * Martin Pool (mbp at samba.org) April 2003
+ *    Remove NO_CONFIG_H so that the test case can be built within a source
+ *    tree with less trouble.
+ *    Remove unnecessary SAFE_FREE() definition.
+ *
+ * Martin Pool (mbp at samba.org) May 2003
+ *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
+ *
+ *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
+ *    if the C library has some snprintf functions already.
+ *
+ * Darren Tucker (dtucker at zip.com.au) 2005
+ *    Fix bug allowing read overruns of the source string with "%.*s"
+ *    Usually harmless unless the read runs outside the process' allocation
+ *    (eg if your malloc does guard pages) in which case it will segfault.
+ *    From OpenSSH.  Also added test for same.
+ *
+ * Simo Sorce (idra at samba.org) Jan 2006
+ * 
+ *    Add support for position independent parameters 
+ *    fix fmtstr now it conforms to sprintf wrt min.max
+ *
+ **************************************************************/
+
+#include "replace.h"
+#include "system/locale.h"
+
+#ifdef TEST_SNPRINTF /* need math library headers for testing */
+
+/* In test mode, we pretend that this system doesn't have any snprintf
+ * functions, regardless of what config.h says. */
+#  undef HAVE_SNPRINTF
+#  undef HAVE_VSNPRINTF
+#  undef HAVE_C99_VSNPRINTF
+#  undef HAVE_ASPRINTF
+#  undef HAVE_VASPRINTF
+#  include <math.h>
+#endif /* TEST_SNPRINTF */
+
+#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
+/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
+#include <stdio.h>
+ /* make the compiler happy with an empty file */
+ void dummy_snprintf(void);
+ void dummy_snprintf(void) {} 
+#endif /* HAVE_SNPRINTF, etc */
+
+/* yes this really must be a ||. Don't muck with this (tridge) */
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+
+#ifdef HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+#ifndef VA_COPY
+#ifdef HAVE_VA_COPY
+#define VA_COPY(dest, src) va_copy(dest, src)
+#else
+#ifdef HAVE___VA_COPY
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#else
+#define VA_COPY(dest, src) (dest) = (src)
+#endif
+#endif
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS 	(1 << 0)
+#define DP_F_PLUS  	(1 << 1)
+#define DP_F_SPACE 	(1 << 2)
+#define DP_F_NUM   	(1 << 3)
+#define DP_F_ZERO  	(1 << 4)
+#define DP_F_UP    	(1 << 5)
+#define DP_F_UNSIGNED 	(1 << 6)
+
+/* Conversion Flags */
+#define DP_C_CHAR    1
+#define DP_C_SHORT   2
+#define DP_C_LONG    3
+#define DP_C_LDOUBLE 4
+#define DP_C_LLONG   5
+#define DP_C_SIZET   6
+
+/* Chunk types */
+#define CNK_FMT_STR 0
+#define CNK_INT     1
+#define CNK_OCTAL   2
+#define CNK_UINT    3
+#define CNK_HEX     4
+#define CNK_FLOAT   5
+#define CNK_CHAR    6
+#define CNK_STRING  7
+#define CNK_PTR     8
+#define CNK_NUM     9
+#define CNK_PRCNT   10
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+struct pr_chunk {
+	int type; /* chunk type */
+	int num; /* parameter number */
+	int min; 
+	int max;
+	int flags;
+	int cflags;
+	int start;
+	int len;
+	LLONG value;
+	LDOUBLE fvalue;
+	char *strvalue;
+	void *pnum;
+	struct pr_chunk *min_star;
+	struct pr_chunk *max_star;
+	struct pr_chunk *next;
+};
+
+struct pr_chunk_x {
+	struct pr_chunk **chunks;
+	int num;
+};
+
+static int dopr(char *buffer, size_t maxlen, const char *format, 
+		   va_list args_in);
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+		    char *value, int flags, int min, int max);
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+		    LLONG value, int base, int min, int max, int flags);
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+		   LDOUBLE fvalue, int min, int max, int flags);
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+static struct pr_chunk *new_chunk(void);
+static int add_cnk_list_entry(struct pr_chunk_x **list,
+				int max_num, struct pr_chunk *chunk);
+
+static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
+{
+	char ch;
+	int state;
+	int pflag;
+	int pnum;
+	int pfirst;
+	size_t currlen;
+	va_list args;
+	const char *base;
+	struct pr_chunk *chunks = NULL;
+	struct pr_chunk *cnk = NULL;
+	struct pr_chunk_x *clist = NULL;
+	int max_pos;
+	int ret = -1;
+
+	VA_COPY(args, args_in);
+
+	state = DP_S_DEFAULT;
+	pfirst = 1;
+	pflag = 0;
+	pnum = 0;
+
+	max_pos = 0;
+	base = format;
+	ch = *format++;
+	
+	/* retrieve the string structure as chunks */
+	while (state != DP_S_DONE) {
+		if (ch == '\0') 
+			state = DP_S_DONE;
+
+		switch(state) {
+		case DP_S_DEFAULT:
+			
+			if (cnk) {
+				cnk->next = new_chunk();
+				cnk = cnk->next;
+			} else {
+				cnk = new_chunk();
+			}
+			if (!cnk) goto done;
+			if (!chunks) chunks = cnk;
+			
+			if (ch == '%') {
+				state = DP_S_FLAGS;
+				ch = *format++;
+			} else {
+				cnk->type = CNK_FMT_STR;
+				cnk->start = format - base -1;
+				while ((ch != '\0') && (ch != '%')) ch = *format++;
+				cnk->len = format - base - cnk->start -1;
+			}
+			break;
+		case DP_S_FLAGS:
+			switch (ch) {
+			case '-':
+				cnk->flags |= DP_F_MINUS;
+				ch = *format++;
+				break;
+			case '+':
+				cnk->flags |= DP_F_PLUS;
+				ch = *format++;
+				break;
+			case ' ':
+				cnk->flags |= DP_F_SPACE;
+				ch = *format++;
+				break;
+			case '#':
+				cnk->flags |= DP_F_NUM;
+				ch = *format++;
+				break;
+			case '0':
+				cnk->flags |= DP_F_ZERO;
+				ch = *format++;
+				break;
+			case 'I':
+				/* internationalization not supported yet */
+				ch = *format++;
+				break;
+			default:
+				state = DP_S_MIN;
+				break;
+			}
+			break;
+		case DP_S_MIN:
+			if (isdigit((unsigned char)ch)) {
+				cnk->min = 10 * cnk->min + char_to_int (ch);
+				ch = *format++;
+			} else if (ch == '$') {
+				if (!pfirst && !pflag) {
+					/* parameters must be all positioned or none */
+					goto done;
+				}
+				if (pfirst) {
+					pfirst = 0;
+					pflag = 1;
+				}
+				if (cnk->min == 0) /* what ?? */
+					goto done;
+				cnk->num = cnk->min;
+				cnk->min = 0;
+				ch = *format++;
+			} else if (ch == '*') {
+				if (pfirst) pfirst = 0;
+				cnk->min_star = new_chunk();
+				if (!cnk->min_star) /* out of memory :-( */
+					goto done;
+				cnk->min_star->type = CNK_INT;
+				if (pflag) {
+					int num;
+					ch = *format++;
+					if (!isdigit((unsigned char)ch)) {
+						/* parameters must be all positioned or none */
+						goto done;
+					}
+					for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
+						num = 10 * num + char_to_int(ch);
+					}
+					cnk->min_star->num = num;
+					if (ch != '$') /* what ?? */
+						goto done;
+				} else {
+					cnk->min_star->num = ++pnum;
+				}
+				max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
+				if (max_pos == 0) /* out of memory :-( */
+					goto done;
+				ch = *format++;
+				state = DP_S_DOT;
+			} else {
+				if (pfirst) pfirst = 0;
+				state = DP_S_DOT;
+			}
+			break;
+		case DP_S_DOT:
+			if (ch == '.') {
+				state = DP_S_MAX;
+				ch = *format++;
+			} else { 
+				state = DP_S_MOD;
+			}
+			break;
+		case DP_S_MAX:
+			if (isdigit((unsigned char)ch)) {
+				if (cnk->max < 0)
+					cnk->max = 0;
+				cnk->max = 10 * cnk->max + char_to_int (ch);
+				ch = *format++;
+			} else if (ch == '$') {
+				if (!pfirst && !pflag) {
+					/* parameters must be all positioned or none */
+					goto done;
+				}
+				if (cnk->max <= 0) /* what ?? */
+					goto done;
+				cnk->num = cnk->max;
+				cnk->max = -1;
+				ch = *format++;
+			} else if (ch == '*') {
+				cnk->max_star = new_chunk();
+				if (!cnk->max_star) /* out of memory :-( */
+					goto done;
+				cnk->max_star->type = CNK_INT;
+				if (pflag) {
+					int num;
+					ch = *format++;
+					if (!isdigit((unsigned char)ch)) {
+						/* parameters must be all positioned or none */
+						goto done;
+					}
+					for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
+						num = 10 * num + char_to_int(ch);
+					}
+					cnk->max_star->num = num;
+					if (ch != '$') /* what ?? */
+						goto done;
+				} else {
+					cnk->max_star->num = ++pnum;
+				}
+				max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
+				if (max_pos == 0) /* out of memory :-( */
+					goto done;
+
+				ch = *format++;
+				state = DP_S_MOD;
+			} else {
+				state = DP_S_MOD;
+			}
+			break;
+		case DP_S_MOD:
+			switch (ch) {
+			case 'h':
+				cnk->cflags = DP_C_SHORT;
+				ch = *format++;
+				if (ch == 'h') {
+					cnk->cflags = DP_C_CHAR;
+					ch = *format++;
+				}
+				break;
+			case 'l':
+				cnk->cflags = DP_C_LONG;
+				ch = *format++;
+				if (ch == 'l') {	/* It's a long long */
+					cnk->cflags = DP_C_LLONG;
+					ch = *format++;
+				}
+				break;
+			case 'L':
+				cnk->cflags = DP_C_LDOUBLE;
+				ch = *format++;
+				break;
+			case 'z':
+				cnk->cflags = DP_C_SIZET;
+				ch = *format++;
+				break;
+			default:
+				break;
+			}
+			state = DP_S_CONV;
+			break;
+		case DP_S_CONV:
+			if (cnk->num == 0) cnk->num = ++pnum;
+			max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
+			if (max_pos == 0) /* out of memory :-( */
+				goto done;
+			
+			switch (ch) {
+			case 'd':
+			case 'i':
+				cnk->type = CNK_INT;
+				break;
+			case 'o':
+				cnk->type = CNK_OCTAL;
+				cnk->flags |= DP_F_UNSIGNED;
+				break;
+			case 'u':
+				cnk->type = CNK_UINT;
+				cnk->flags |= DP_F_UNSIGNED;
+				break;
+			case 'X':
+				cnk->flags |= DP_F_UP;
+			case 'x':
+				cnk->type = CNK_HEX;
+				cnk->flags |= DP_F_UNSIGNED;
+				break;
+			case 'A':
+				/* hex float not supported yet */
+			case 'E':
+			case 'G':
+			case 'F':
+				cnk->flags |= DP_F_UP;
+			case 'a':
+				/* hex float not supported yet */
+			case 'e':
+			case 'f':
+			case 'g':
+				cnk->type = CNK_FLOAT;
+				break;
+			case 'c':
+				cnk->type = CNK_CHAR;
+				break;
+			case 's':
+				cnk->type = CNK_STRING;
+				break;
+			case 'p':
+				cnk->type = CNK_PTR;
+				break;
+			case 'n':
+				cnk->type = CNK_NUM;
+				break;
+			case '%':
+				cnk->type = CNK_PRCNT;
+				break;
+			default:
+				/* Unknown, bail out*/
+				goto done;
+			}
+			ch = *format++;
+			state = DP_S_DEFAULT;
+			break;
+		case DP_S_DONE:
+			break;
+		default:
+			/* hmm? */
+			break; /* some picky compilers need this */
+		}
+	}
+
+	/* retieve the format arguments */
+	for (pnum = 0; pnum < max_pos; pnum++) {
+		int i;
+
+		if (clist[pnum].num == 0) {
+			/* ignoring a parameter should not be permitted
+			 * all parameters must be matched at least once
+			 * BUT seem some system ignore this rule ...
+			 * at least my glibc based system does --SSS
+			 */
+#ifdef DEBUG_SNPRINTF
+			printf("parameter at position %d not used\n", pnum+1);
+#endif
+			/* eat the parameter */
+			va_arg (args, int);
+			continue;
+		}
+		for (i = 1; i < clist[pnum].num; i++) {
+			if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
+				/* nooo noo no!
+				 * all the references to a parameter
+				 * must be of the same type
+				 */
+				goto done;
+			}
+		}
+		cnk = clist[pnum].chunks[0];
+		switch (cnk->type) {
+		case CNK_INT:
+			if (cnk->cflags == DP_C_SHORT) 
+				cnk->value = va_arg (args, int);
+			else if (cnk->cflags == DP_C_LONG)
+				cnk->value = va_arg (args, long int);
+			else if (cnk->cflags == DP_C_LLONG)
+				cnk->value = va_arg (args, LLONG);
+			else if (cnk->cflags == DP_C_SIZET)
+				cnk->value = va_arg (args, ssize_t);
+			else
+				cnk->value = va_arg (args, int);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->value = cnk->value;
+			}
+			break;
+
+		case CNK_OCTAL:
+		case CNK_UINT:
+		case CNK_HEX:
+			if (cnk->cflags == DP_C_SHORT)
+				cnk->value = va_arg (args, unsigned int);
+			else if (cnk->cflags == DP_C_LONG)
+				cnk->value = (unsigned long int)va_arg (args, unsigned long int);
+			else if (cnk->cflags == DP_C_LLONG)
+				cnk->value = (LLONG)va_arg (args, unsigned LLONG);
+			else if (cnk->cflags == DP_C_SIZET)
+				cnk->value = (size_t)va_arg (args, size_t);
+			else
+				cnk->value = (unsigned int)va_arg (args, unsigned int);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->value = cnk->value;
+			}
+			break;
+
+		case CNK_FLOAT:
+			if (cnk->cflags == DP_C_LDOUBLE)
+				cnk->fvalue = va_arg (args, LDOUBLE);
+			else
+				cnk->fvalue = va_arg (args, double);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->fvalue = cnk->fvalue;
+			}
+			break;
+
+		case CNK_CHAR:
+			cnk->value = va_arg (args, int);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->value = cnk->value;
+			}
+			break;
+
+		case CNK_STRING:
+			cnk->strvalue = va_arg (args, char *);
+			if (!cnk->strvalue) cnk->strvalue = "(NULL)";
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->strvalue = cnk->strvalue;
+			}
+			break;
+
+		case CNK_PTR:
+			cnk->strvalue = va_arg (args, void *);
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->strvalue = cnk->strvalue;
+			}
+			break;
+
+		case CNK_NUM:
+			if (cnk->cflags == DP_C_CHAR)
+				cnk->pnum = va_arg (args, char *);
+			else if (cnk->cflags == DP_C_SHORT)
+				cnk->pnum = va_arg (args, short int *);
+			else if (cnk->cflags == DP_C_LONG)
+				cnk->pnum = va_arg (args, long int *);
+			else if (cnk->cflags == DP_C_LLONG)
+				cnk->pnum = va_arg (args, LLONG *);
+			else if (cnk->cflags == DP_C_SIZET)
+				cnk->pnum = va_arg (args, ssize_t *);
+			else
+				cnk->pnum = va_arg (args, int *);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->pnum = cnk->pnum;
+			}
+			break;
+
+		case CNK_PRCNT:
+			break;
+
+		default:
+			/* what ?? */
+			goto done;
+		}
+	}
+	/* print out the actual string from chunks */
+	currlen = 0;
+	cnk = chunks;
+	while (cnk) {
+		int len, min, max;
+
+		if (cnk->min_star) min = cnk->min_star->value;
+		else min = cnk->min;
+		if (cnk->max_star) max = cnk->max_star->value;
+		else max = cnk->max;
+
+		switch (cnk->type) {
+
+		case CNK_FMT_STR:
+			if (maxlen != 0 && maxlen > currlen) {
+				if (maxlen > (currlen + cnk->len)) len = cnk->len;
+				else len = maxlen - currlen;
+
+				memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
+			}
+			currlen += cnk->len;
+				
+			break;
+
+		case CNK_INT:
+		case CNK_UINT:
+			fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
+			break;
+
+		case CNK_OCTAL:
+			fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
+			break;
+
+		case CNK_HEX:
+			fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
+			break;
+
+		case CNK_FLOAT:
+			fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
+			break;
+
+		case CNK_CHAR:
+			dopr_outch (buffer, &currlen, maxlen, cnk->value);
+			break;
+
+		case CNK_STRING:
+			if (max == -1) {
+				max = strlen(cnk->strvalue);
+			}
+			fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
+			break;
+
+		case CNK_PTR:
+			fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
+			break;
+
+		case CNK_NUM:
+			if (cnk->cflags == DP_C_CHAR)
+				*((char *)(cnk->pnum)) = (char)currlen;
+			else if (cnk->cflags == DP_C_SHORT)
+				*((short int *)(cnk->pnum)) = (short int)currlen;
+			else if (cnk->cflags == DP_C_LONG)
+				*((long int *)(cnk->pnum)) = (long int)currlen;
+			else if (cnk->cflags == DP_C_LLONG)
+				*((LLONG *)(cnk->pnum)) = (LLONG)currlen;
+			else if (cnk->cflags == DP_C_SIZET)
+				*((ssize_t *)(cnk->pnum)) = (ssize_t)currlen;
+			else
+				*((int *)(cnk->pnum)) = (int)currlen;
+			break;
+
+		case CNK_PRCNT:
+			dopr_outch (buffer, &currlen, maxlen, '%');
+			break;
+
+		default:
+			/* what ?? */
+			goto done;
+		}
+		cnk = cnk->next;
+	}
+	if (maxlen != 0) {
+		if (currlen < maxlen - 1) 
+			buffer[currlen] = '\0';
+		else if (maxlen > 0) 
+			buffer[maxlen - 1] = '\0';
+	}
+	ret = currlen;
+
+done:
+	va_end(args);
+
+	while (chunks) {
+		cnk = chunks->next;
+		free(chunks);
+		chunks = cnk;
+	}
+	if (clist) {
+		for (pnum = 0; pnum < max_pos; pnum++) {
+			if (clist[pnum].chunks) free(clist[pnum].chunks);
+		}
+		free(clist);
+	}
+	return ret;
+}
+
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+		    char *value, int flags, int min, int max)
+{
+	int padlen, strln;     /* amount to pad */
+	int cnt = 0;
+
+#ifdef DEBUG_SNPRINTF
+	printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+	if (value == 0) {
+		value = "<NULL>";
+	}
+
+	for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
+	padlen = min - strln;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justify */
+	
+	while (padlen > 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	while (*value && (cnt < max)) {
+		dopr_outch (buffer, currlen, maxlen, *value++);
+		++cnt;
+	}
+	while (padlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+		    LLONG value, int base, int min, int max, int flags)
+{
+	int signvalue = 0;
+	unsigned LLONG uvalue;
+	char convert[20];
+	int place = 0;
+	int spadlen = 0; /* amount to space pad */
+	int zpadlen = 0; /* amount to zero pad */
+	int caps = 0;
+	
+	if (max < 0)
+		max = 0;
+	
+	uvalue = value;
+	
+	if(!(flags & DP_F_UNSIGNED)) {
+		if( value < 0 ) {
+			signvalue = '-';
+			uvalue = -value;
+		} else {
+			if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+				signvalue = '+';
+			else if (flags & DP_F_SPACE)
+				signvalue = ' ';
+		}
+	}
+  
+	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+	do {
+		convert[place++] =
+			(caps? "0123456789ABCDEF":"0123456789abcdef")
+			[uvalue % (unsigned)base  ];
+		uvalue = (uvalue / (unsigned)base );
+	} while(uvalue && (place < 20));
+	if (place == 20) place--;
+	convert[place] = 0;
+
+	zpadlen = max - place;
+	spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+	if (zpadlen < 0) zpadlen = 0;
+	if (spadlen < 0) spadlen = 0;
+	if (flags & DP_F_ZERO) {
+		zpadlen = MAX(zpadlen, spadlen);
+		spadlen = 0;
+	}
+	if (flags & DP_F_MINUS) 
+		spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+	       zpadlen, spadlen, min, max, place);
+#endif
+
+	/* Spaces */
+	while (spadlen > 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		--spadlen;
+	}
+
+	/* Sign */
+	if (signvalue) 
+		dopr_outch (buffer, currlen, maxlen, signvalue);
+
+	/* Zeros */
+	if (zpadlen > 0) {
+		while (zpadlen > 0) {
+			dopr_outch (buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+	}
+
+	/* Digits */
+	while (place > 0) 
+		dopr_outch (buffer, currlen, maxlen, convert[--place]);
+  
+	/* Left Justified spaces */
+	while (spadlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++spadlen;
+	}
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+	LDOUBLE result = value;
+
+	if (value < 0)
+		result = -value;
+	
+	return result;
+}
+
+static LDOUBLE POW10(int exp)
+{
+	LDOUBLE result = 1;
+	
+	while (exp) {
+		result *= 10;
+		exp--;
+	}
+  
+	return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+	LLONG intpart;
+
+	intpart = (LLONG)value;
+	value = value - intpart;
+	if (value >= 0.5) intpart++;
+	
+	return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+   be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+	int i;
+	LLONG l=0;
+	double x = x0;
+	double f = 1.0;
+
+	for (i=0;i<100;i++) {
+		l = (long)x;
+		if (l <= (x+1) && l >= (x-1)) break;
+		x *= 0.1;
+		f *= 10.0;
+	}
+
+	if (i == 100) {
+		/* yikes! the number is beyond what we can handle. What do we do? */
+		(*iptr) = 0;
+		return 0;
+	}
+
+	if (i != 0) {
+		double i2;
+		double ret;
+
+		ret = my_modf(x0-l*f, &i2);
+		(*iptr) = l*f + i2;
+		return ret;
+	} 
+
+	(*iptr) = l;
+	return x - (*iptr);
+}
+
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+		   LDOUBLE fvalue, int min, int max, int flags)
+{
+	int signvalue = 0;
+	double ufvalue;
+	char iconvert[311];
+	char fconvert[311];
+	int iplace = 0;
+	int fplace = 0;
+	int padlen = 0; /* amount to pad */
+	int zpadlen = 0; 
+	int caps = 0;
+	int idx;
+	double intpart;
+	double fracpart;
+	double temp;
+  
+	/* 
+	 * AIX manpage says the default is 0, but Solaris says the default
+	 * is 6, and sprintf on AIX defaults to 6
+	 */
+	if (max < 0)
+		max = 6;
+
+	ufvalue = abs_val (fvalue);
+
+	if (fvalue < 0) {
+		signvalue = '-';
+	} else {
+		if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+			signvalue = '+';
+		} else {
+			if (flags & DP_F_SPACE)
+				signvalue = ' ';
+		}
+	}
+
+#if 0
+	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+	 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+	/* 
+	 * Sorry, we only support 9 digits past the decimal because of our 
+	 * conversion method
+	 */
+	if (max > 9)
+		max = 9;
+
+	/* We "cheat" by converting the fractional part to integer by
+	 * multiplying by a factor of 10
+	 */
+
+	temp = ufvalue;
+	my_modf(temp, &intpart);
+
+	fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+	
+	if (fracpart >= POW10(max)) {
+		intpart++;
+		fracpart -= POW10(max);
+	}
+
+
+	/* Convert integer part */
+	do {
+		temp = intpart*0.1;
+		my_modf(temp, &intpart);
+		idx = (int) ((temp -intpart +0.05)* 10.0);
+		/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+		/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
+		iconvert[iplace++] =
+			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+	} while (intpart && (iplace < 311));
+	if (iplace == 311) iplace--;
+	iconvert[iplace] = 0;
+
+	/* Convert fractional part */
+	if (fracpart)
+	{
+		do {
+			temp = fracpart*0.1;
+			my_modf(temp, &fracpart);
+			idx = (int) ((temp -fracpart +0.05)* 10.0);
+			/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
+			/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+			fconvert[fplace++] =
+			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+		} while(fracpart && (fplace < 311));
+		if (fplace == 311) fplace--;
+	}
+	fconvert[fplace] = 0;
+  
+	/* -1 for decimal point, another -1 if we are printing a sign */
+	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
+	zpadlen = max - fplace;
+	if (zpadlen < 0) zpadlen = 0;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justifty */
+	
+	if ((flags & DP_F_ZERO) && (padlen > 0)) {
+		if (signvalue) {
+			dopr_outch (buffer, currlen, maxlen, signvalue);
+			--padlen;
+			signvalue = 0;
+		}
+		while (padlen > 0) {
+			dopr_outch (buffer, currlen, maxlen, '0');
+			--padlen;
+		}
+	}
+	while (padlen > 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	if (signvalue) 
+		dopr_outch (buffer, currlen, maxlen, signvalue);
+	
+	while (iplace > 0) 
+		dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+#ifdef DEBUG_SNPRINTF
+	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+	/*
+	 * Decimal point.  This should probably use locale to find the correct
+	 * char to print out.
+	 */
+	if (max > 0) {
+		dopr_outch (buffer, currlen, maxlen, '.');
+		
+		while (zpadlen > 0) {
+			dopr_outch (buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+
+		while (fplace > 0) 
+			dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+	}
+
+	while (padlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+	if (*currlen < maxlen) {
+		buffer[(*currlen)] = c;
+	}
+	(*currlen)++;
+}
+
+static struct pr_chunk *new_chunk(void) {
+	struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
+
+	if (!new_c)
+		return NULL;
+
+	new_c->type = 0;
+	new_c->num = 0;
+	new_c->min = 0;
+	new_c->min_star = NULL;
+	new_c->max = -1;
+	new_c->max_star = NULL;
+	new_c->flags = 0;
+	new_c->cflags = 0;
+	new_c->start = 0;
+	new_c->len = 0;
+	new_c->value = 0;
+	new_c->fvalue = 0;
+	new_c->strvalue = NULL;
+	new_c->pnum = NULL;
+	new_c->next = NULL;
+
+	return new_c;
+}
+
+static int add_cnk_list_entry(struct pr_chunk_x **list,
+				int max_num, struct pr_chunk *chunk) {
+	struct pr_chunk_x *l;
+	struct pr_chunk **c;
+	int max;
+	int cnum;
+	int i, pos;
+
+	if (chunk->num > max_num) {
+		max = chunk->num;
+	
+		if (*list == NULL) {
+			l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
+			pos = 0;
+		} else {
+			l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
+			pos = max_num;
+		}
+		if (l == NULL) {
+			for (i = 0; i < max; i++) {
+				if ((*list)[i].chunks) free((*list)[i].chunks);
+			}
+			return 0;
+		}
+		for (i = pos; i < max; i++) {
+			l[i].chunks = NULL;
+			l[i].num = 0;
+		}
+	} else {
+		l = *list;
+		max = max_num;
+	}
+
+	i = chunk->num - 1;
+	cnum = l[i].num + 1;
+	if (l[i].chunks == NULL) {
+		c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); 
+	} else {
+		c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
+	}
+	if (c == NULL) {
+		for (i = 0; i < max; i++) {
+			if (l[i].chunks) free(l[i].chunks);
+		}
+		return 0;
+	}
+	c[l[i].num] = chunk;
+	l[i].chunks = c;
+	l[i].num = cnum;
+
+	*list = l;
+	return max;
+}
+
+ int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+	return dopr(str, count, fmt, args);
+}
+#endif
+
+/* yes this really must be a ||. Don't muck with this (tridge)
+ *
+ * The logic for these two is that we need our own definition if the
+ * OS *either* has no definition of *sprintf, or if it does have one
+ * that doesn't work properly according to the autoconf test.
+ */
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+ int snprintf(char *str,size_t count,const char *fmt,...)
+{
+	size_t ret;
+	va_list ap;
+    
+	va_start(ap, fmt);
+	ret = vsnprintf(str, count, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+#endif
+
+#ifndef HAVE_C99_VSNPRINTF
+ int printf(const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+	char *s;
+
+	s = NULL;
+	va_start(ap, fmt);
+	ret = vasprintf(&s, fmt, ap);
+	va_end(ap);
+
+	if (s) {
+		fwrite(s, 1, strlen(s), stdout);
+	}
+	free(s);
+
+	return ret;
+}
+#endif
+
+#ifndef HAVE_C99_VSNPRINTF
+ int fprintf(FILE *stream, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+	char *s;
+
+	s = NULL;
+	va_start(ap, fmt);
+	ret = vasprintf(&s, fmt, ap);
+	va_end(ap);
+
+	if (s) {
+		fwrite(s, 1, strlen(s), stream);
+	}
+	free(s);
+
+	return ret;
+}
+#endif
+
+#endif 
+
+#ifndef HAVE_VASPRINTF
+ int vasprintf(char **ptr, const char *format, va_list ap)
+{
+	int ret;
+	va_list ap2;
+
+	VA_COPY(ap2, ap);
+	ret = vsnprintf(NULL, 0, format, ap2);
+	va_end(ap2);
+	if (ret <= 0) return ret;
+
+	(*ptr) = (char *)malloc(ret+1);
+	if (!*ptr) return -1;
+
+	VA_COPY(ap2, ap);
+	ret = vsnprintf(*ptr, ret+1, format, ap2);
+	va_end(ap2);
+
+	return ret;
+}
+#endif
+
+
+#ifndef HAVE_ASPRINTF
+ int asprintf(char **ptr, const char *format, ...)
+{
+	va_list ap;
+	int ret;
+	
+	*ptr = NULL;
+	va_start(ap, format);
+	ret = vasprintf(ptr, format, ap);
+	va_end(ap);
+
+	return ret;
+}
+#endif
+
+#ifdef TEST_SNPRINTF
+
+ int sprintf(char *str,const char *fmt,...);
+ int printf(const char *fmt,...);
+
+ int main (void)
+{
+	char buf1[1024];
+	char buf2[1024];
+	char *buf3;
+	char *fp_fmt[] = {
+		"%1.1f",
+		"%-1.5f",
+		"%1.5f",
+		"%123.9f",
+		"%10.5f",
+		"% 10.5f",
+		"%+22.9f",
+		"%+4.9f",
+		"%01.3f",
+		"%4f",
+		"%3.1f",
+		"%3.2f",
+		"%.0f",
+		"%f",
+		"%-8.8f",
+		"%-9.9f",
+		NULL
+	};
+	double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 
+			     0.9996, 1.996, 4.136, 5.030201, 0.00205,
+			     /* END LIST */ 0};
+	char *int_fmt[] = {
+		"%-1.5d",
+		"%1.5d",
+		"%123.9d",
+		"%5.5d",
+		"%10.5d",
+		"% 10.5d",
+		"%+22.33d",
+		"%01.3d",
+		"%4d",
+		"%d",
+		NULL
+	};
+	long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0};
+	char *str_fmt[] = {
+		"%10.5s",
+		"%-10.5s",
+		"%5.10s",
+		"%-5.10s",
+		"%10.1s",
+		"%0.10s",
+		"%10.0s",
+		"%1.10s",
+		"%s",
+		"%.1s",
+		"%.10s",
+		"%10s",
+		NULL
+	};
+	char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
+#ifdef HAVE_LONG_LONG
+	char *ll_fmt[] = {
+		"%llu",
+		NULL
+	};
+	LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0};
+#endif
+	int x, y;
+	int fail = 0;
+	int num = 0;
+	int l1, l2;
+	char *ss_fmt[] = {
+		"%zd",
+		"%zu",
+		NULL
+	};
+	size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0};
+
+	printf ("Testing snprintf format codes against system sprintf...\n");
+
+	for (x = 0; fp_fmt[x] ; x++) {
+		for (y = 0; fp_nums[y] != 0 ; y++) {
+			buf1[0] = buf2[0] = '\0';
+			l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
+			l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]);
+			buf1[1023] = buf2[1023] = '\0';
+			if (strcmp (buf1, buf2) || (l1 != l2)) {
+				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
+				       fp_fmt[x], l1, buf1, l2, buf2);
+				fail++;
+			}
+			num++;
+		}
+	}
+
+	for (x = 0; int_fmt[x] ; x++) {
+		for (y = 0; int_nums[y] != 0 ; y++) {
+			buf1[0] = buf2[0] = '\0';
+			l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
+			l2 = sprintf (buf2, int_fmt[x], int_nums[y]);
+			buf1[1023] = buf2[1023] = '\0';
+			if (strcmp (buf1, buf2) || (l1 != l2)) {
+				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
+				       int_fmt[x], l1, buf1, l2, buf2);
+				fail++;
+			}
+			num++;
+		}
+	}
+
+	for (x = 0; str_fmt[x] ; x++) {
+		for (y = 0; str_vals[y] != 0 ; y++) {
+			buf1[0] = buf2[0] = '\0';
+			l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
+			l2 = sprintf (buf2, str_fmt[x], str_vals[y]);
+			buf1[1023] = buf2[1023] = '\0';
+			if (strcmp (buf1, buf2) || (l1 != l2)) {
+				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
+				       str_fmt[x], l1, buf1, l2, buf2);
+				fail++;
+			}
+			num++;
+		}
+	}
+
+#ifdef HAVE_LONG_LONG
+	for (x = 0; ll_fmt[x] ; x++) {
+		for (y = 0; ll_nums[y] != 0 ; y++) {
+			buf1[0] = buf2[0] = '\0';
+			l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
+			l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]);
+			buf1[1023] = buf2[1023] = '\0';
+			if (strcmp (buf1, buf2) || (l1 != l2)) {
+				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
+				       ll_fmt[x], l1, buf1, l2, buf2);
+				fail++;
+			}
+			num++;
+		}
+	}
+#endif
+
+#define BUFSZ 2048
+
+	buf1[0] = buf2[0] = '\0';
+	if ((buf3 = malloc(BUFSZ)) == NULL) {
+		fail++;
+	} else {
+		num++;
+		memset(buf3, 'a', BUFSZ);
+		snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
+		buf1[1023] = '\0';
+		if (strcmp(buf1, "a") != 0) {
+			printf("length limit buf1 '%s' expected 'a'\n", buf1);
+			fail++;
+		}
+        }
+
+	buf1[0] = buf2[0] = '\0';
+	l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
+	l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
+	buf1[1023] = buf2[1023] = '\0';
+	if (strcmp(buf1, buf2) || (l1 != l2)) {
+		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+				"%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
+		fail++;
+	}
+
+	buf1[0] = buf2[0] = '\0';
+	l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
+	l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
+	buf1[1023] = buf2[1023] = '\0';
+	if (strcmp(buf1, buf2)) {
+		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+				"%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
+		fail++;
+	}
+
+	for (x = 0; ss_fmt[x] ; x++) {
+		for (y = 0; ss_nums[y] != 0 ; y++) {
+			buf1[0] = buf2[0] = '\0';
+			l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]);
+			l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]);
+			buf1[1023] = buf2[1023] = '\0';
+			if (strcmp (buf1, buf2) || (l1 != l2)) {
+				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
+				       ss_fmt[x], l1, buf1, l2, buf2);
+				fail++;
+			}
+			num++;
+		}
+	}
+#if 0
+	buf1[0] = buf2[0] = '\0';
+	l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
+	l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
+	buf1[1023] = buf2[1023] = '\0';
+	if (strcmp(buf1, buf2)) {
+		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+				"%lld", l1, buf1, l2, buf2);
+		fail++;
+	}
+
+	buf1[0] = buf2[0] = '\0';
+	l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
+	l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
+	buf1[1023] = buf2[1023] = '\0';
+	if (strcmp(buf1, buf2)) {
+		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+				"%Lf", l1, buf1, l2, buf2);
+		fail++;
+	}
+#endif
+	printf ("%d tests failed out of %d.\n", fail, num);
+
+	printf("seeing how many digits we support\n");
+	{
+		double v0 = 0.12345678901234567890123456789012345678901;
+		for (x=0; x<100; x++) {
+			double p = pow(10, x); 
+			double r = v0*p;
+			snprintf(buf1, sizeof(buf1), "%1.1f", r);
+			sprintf(buf2,                "%1.1f", r);
+			if (strcmp(buf1, buf2)) {
+				printf("we seem to support %d digits\n", x-1);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+#endif /* TEST_SNPRINTF */

Added: branches/ctdb/squeeze-backports/lib/replace/strptime.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/strptime.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/strptime.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,990 @@
+/* Convert a string representation of time to a time value.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper at cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not, 
+   see <http://www.gnu.org/licenses/>.  */
+
+/* XXX This version of the implementation is not really complete.
+   Some of the fields cannot add information alone.  But if seeing
+   some of them in the same format (such as year, week and weekday)
+   this is enough information for determining the date.  */
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+
+#ifndef __P
+# if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+#  define __P(args) args
+# else
+#  define __P(args) ()
+# endif  /* GCC.  */
+#endif  /* Not __P.  */
+
+#if ! HAVE_LOCALTIME_R && ! defined localtime_r
+# ifdef _LIBC
+#  define localtime_r __localtime_r
+# else
+/* Approximate localtime_r as best we can in its absence.  */
+#  define localtime_r my_localtime_r
+static struct tm *localtime_r __P ((const time_t *, struct tm *));
+static struct tm *
+localtime_r (t, tp)
+     const time_t *t;
+     struct tm *tp;
+{
+  struct tm *l = localtime (t);
+  if (! l)
+    return 0;
+  *tp = *l;
+  return tp;
+}
+# endif /* ! _LIBC */
+#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
+
+
+#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
+#if defined __GNUC__ && __GNUC__ >= 2
+# define match_string(cs1, s2) \
+  ({ size_t len = strlen (cs1);						      \
+     int result = strncasecmp ((cs1), (s2), len) == 0;			      \
+     if (result) (s2) += len;						      \
+     result; })
+#else
+/* Oh come on.  Get a reasonable compiler.  */
+# define match_string(cs1, s2) \
+  (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
+#endif
+/* We intentionally do not use isdigit() for testing because this will
+   lead to problems with the wide character version.  */
+#define get_number(from, to, n) \
+  do {									      \
+    int __n = n;							      \
+    val = 0;								      \
+    while (*rp == ' ')							      \
+      ++rp;								      \
+    if (*rp < '0' || *rp > '9')						      \
+      return NULL;							      \
+    do {								      \
+      val *= 10;							      \
+      val += *rp++ - '0';						      \
+    } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9');	      \
+    if (val < from || val > to)						      \
+      return NULL;							      \
+  } while (0)
+#ifdef _NL_CURRENT
+# define get_alt_number(from, to, n) \
+  ({									      \
+    __label__ do_normal;						      \
+    if (*decided != raw)						      \
+      {									      \
+	const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS);		      \
+	int __n = n;							      \
+	int any = 0;							      \
+	while (*rp == ' ')						      \
+	  ++rp;								      \
+	val = 0;							      \
+	do {								      \
+	  val *= 10;							      \
+	  while (*alts != '\0')						      \
+	    {								      \
+	      size_t len = strlen (alts);				      \
+	      if (strncasecmp (alts, rp, len) == 0)			      \
+	        break;							      \
+	      alts += len + 1;						      \
+	      ++val;							      \
+	    }								      \
+	  if (*alts == '\0')						      \
+	    {								      \
+	      if (*decided == not && ! any)				      \
+		goto do_normal;						      \
+	      /* If we haven't read anything it's an error.  */		      \
+	      if (! any)						      \
+		return NULL;						      \
+	      /* Correct the premature multiplication.  */		      \
+	      val /= 10;						      \
+	      break;							      \
+	    }								      \
+	  else								      \
+	    *decided = loc;						      \
+	} while (--__n > 0 && val * 10 <= to);				      \
+	if (val < from || val > to)					      \
+	  return NULL;							      \
+      }									      \
+    else								      \
+      {									      \
+       do_normal:							      \
+        get_number (from, to, n);					      \
+      }									      \
+    0;									      \
+  })
+#else
+# define get_alt_number(from, to, n) \
+  /* We don't have the alternate representation.  */			      \
+  get_number(from, to, n)
+#endif
+#define recursive(new_fmt) \
+  (*(new_fmt) != '\0'							      \
+   && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL)
+
+
+#ifdef _LIBC
+/* This is defined in locale/C-time.c in the GNU libc.  */
+extern const struct locale_data _nl_C_LC_TIME;
+extern const unsigned short int __mon_yday[2][13];
+
+# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
+# define ab_weekday_name \
+  (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
+# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
+# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
+# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
+# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
+# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
+# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
+# define HERE_T_FMT_AMPM \
+  (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
+# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
+
+# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
+#else
+static char const weekday_name[][10] =
+  {
+    "Sunday", "Monday", "Tuesday", "Wednesday",
+    "Thursday", "Friday", "Saturday"
+  };
+static char const ab_weekday_name[][4] =
+  {
+    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+  };
+static char const month_name[][10] =
+  {
+    "January", "February", "March", "April", "May", "June",
+    "July", "August", "September", "October", "November", "December"
+  };
+static char const ab_month_name[][4] =
+  {
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+  };
+# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
+# define HERE_D_FMT "%m/%d/%y"
+# define HERE_AM_STR "AM"
+# define HERE_PM_STR "PM"
+# define HERE_T_FMT_AMPM "%I:%M:%S %p"
+# define HERE_T_FMT "%H:%M:%S"
+
+static const unsigned short int __mon_yday[2][13] =
+  {
+    /* Normal years.  */
+    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+    /* Leap years.  */
+    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+  };
+#endif
+
+/* Status of lookup: do we use the locale data or the raw data?  */
+enum locale_status { not, loc, raw };
+
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+   except every 100th isn't, and every 400th is).  */
+# define __isleap(year)	\
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+/* Compute the day of the week.  */
+static void
+day_of_the_week (struct tm *tm)
+{
+  /* We know that January 1st 1970 was a Thursday (= 4).  Compute the
+     the difference between this data in the one on TM and so determine
+     the weekday.  */
+  int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
+  int wday = (-473
+	      + (365 * (tm->tm_year - 70))
+	      + (corr_year / 4)
+	      - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
+	      + (((corr_year / 4) / 25) / 4)
+	      + __mon_yday[0][tm->tm_mon]
+	      + tm->tm_mday - 1);
+  tm->tm_wday = ((wday % 7) + 7) % 7;
+}
+
+/* Compute the day of the year.  */
+static void
+day_of_the_year (struct tm *tm)
+{
+  tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
+		 + (tm->tm_mday - 1));
+}
+
+static char *
+#ifdef _LIBC
+internal_function
+#endif
+strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm,
+			enum locale_status *decided, int era_cnt));
+
+static char *
+#ifdef _LIBC
+internal_function
+#endif
+strptime_internal (rp, fmt, tm, decided, era_cnt)
+     const char *rp;
+     const char *fmt;
+     struct tm *tm;
+     enum locale_status *decided;
+     int era_cnt;
+{
+  const char *rp_backup;
+  int cnt;
+  size_t val;
+  int have_I, is_pm;
+  int century, want_century;
+  int want_era;
+  int have_wday, want_xday;
+  int have_yday;
+  int have_mon, have_mday;
+#ifdef _NL_CURRENT
+  size_t num_eras;
+#endif
+  struct era_entry *era;
+
+  have_I = is_pm = 0;
+  century = -1;
+  want_century = 0;
+  want_era = 0;
+  era = NULL;
+
+  have_wday = want_xday = have_yday = have_mon = have_mday = 0;
+
+  while (*fmt != '\0')
+    {
+      /* A white space in the format string matches 0 more or white
+	 space in the input string.  */
+      if (isspace (*fmt))
+	{
+	  while (isspace (*rp))
+	    ++rp;
+	  ++fmt;
+	  continue;
+	}
+
+      /* Any character but `%' must be matched by the same character
+	 in the iput string.  */
+      if (*fmt != '%')
+	{
+	  match_char (*fmt++, *rp++);
+	  continue;
+	}
+
+      ++fmt;
+#ifndef _NL_CURRENT
+      /* We need this for handling the `E' modifier.  */
+    start_over:
+#endif
+
+      /* Make back up of current processing pointer.  */
+      rp_backup = rp;
+
+      switch (*fmt++)
+	{
+	case '%':
+	  /* Match the `%' character itself.  */
+	  match_char ('%', *rp++);
+	  break;
+	case 'a':
+	case 'A':
+	  /* Match day of week.  */
+	  for (cnt = 0; cnt < 7; ++cnt)
+	    {
+#ifdef _NL_CURRENT
+	      if (*decided !=raw)
+		{
+		  if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
+		    {
+		      if (*decided == not
+			  && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
+				     weekday_name[cnt]))
+			*decided = loc;
+		      break;
+		    }
+		  if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
+		    {
+		      if (*decided == not
+			  && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
+				     ab_weekday_name[cnt]))
+			*decided = loc;
+		      break;
+		    }
+		}
+#endif
+	      if (*decided != loc
+		  && (match_string (weekday_name[cnt], rp)
+		      || match_string (ab_weekday_name[cnt], rp)))
+		{
+		  *decided = raw;
+		  break;
+		}
+	    }
+	  if (cnt == 7)
+	    /* Does not match a weekday name.  */
+	    return NULL;
+	  tm->tm_wday = cnt;
+	  have_wday = 1;
+	  break;
+	case 'b':
+	case 'B':
+	case 'h':
+	  /* Match month name.  */
+	  for (cnt = 0; cnt < 12; ++cnt)
+	    {
+#ifdef _NL_CURRENT
+	      if (*decided !=raw)
+		{
+		  if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
+		    {
+		      if (*decided == not
+			  && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
+				     month_name[cnt]))
+			*decided = loc;
+		      break;
+		    }
+		  if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
+		    {
+		      if (*decided == not
+			  && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
+				     ab_month_name[cnt]))
+			*decided = loc;
+		      break;
+		    }
+		}
+#endif
+	      if (match_string (month_name[cnt], rp)
+		  || match_string (ab_month_name[cnt], rp))
+		{
+		  *decided = raw;
+		  break;
+		}
+	    }
+	  if (cnt == 12)
+	    /* Does not match a month name.  */
+	    return NULL;
+	  tm->tm_mon = cnt;
+	  want_xday = 1;
+	  break;
+	case 'c':
+	  /* Match locale's date and time format.  */
+#ifdef _NL_CURRENT
+	  if (*decided != raw)
+	    {
+	      if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
+		{
+		  if (*decided == loc)
+		    return NULL;
+		  else
+		    rp = rp_backup;
+		}
+	      else
+		{
+		  if (*decided == not &&
+		      strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
+		    *decided = loc;
+		  want_xday = 1;
+		  break;
+		}
+	      *decided = raw;
+	    }
+#endif
+	  if (!recursive (HERE_D_T_FMT))
+	    return NULL;
+	  want_xday = 1;
+	  break;
+	case 'C':
+	  /* Match century number.  */
+#ifdef _NL_CURRENT
+	match_century:
+#endif
+	  get_number (0, 99, 2);
+	  century = val;
+	  want_xday = 1;
+	  break;
+	case 'd':
+	case 'e':
+	  /* Match day of month.  */
+	  get_number (1, 31, 2);
+	  tm->tm_mday = val;
+	  have_mday = 1;
+	  want_xday = 1;
+	  break;
+	case 'F':
+	  if (!recursive ("%Y-%m-%d"))
+	    return NULL;
+	  want_xday = 1;
+	  break;
+	case 'x':
+#ifdef _NL_CURRENT
+	  if (*decided != raw)
+	    {
+	      if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
+		{
+		  if (*decided == loc)
+		    return NULL;
+		  else
+		    rp = rp_backup;
+		}
+	      else
+		{
+		  if (*decided == not
+		      && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
+		    *decided = loc;
+		  want_xday = 1;
+		  break;
+		}
+	      *decided = raw;
+	    }
+#endif
+	  /* Fall through.  */
+	case 'D':
+	  /* Match standard day format.  */
+	  if (!recursive (HERE_D_FMT))
+	    return NULL;
+	  want_xday = 1;
+	  break;
+	case 'k':
+	case 'H':
+	  /* Match hour in 24-hour clock.  */
+	  get_number (0, 23, 2);
+	  tm->tm_hour = val;
+	  have_I = 0;
+	  break;
+	case 'I':
+	  /* Match hour in 12-hour clock.  */
+	  get_number (1, 12, 2);
+	  tm->tm_hour = val % 12;
+	  have_I = 1;
+	  break;
+	case 'j':
+	  /* Match day number of year.  */
+	  get_number (1, 366, 3);
+	  tm->tm_yday = val - 1;
+	  have_yday = 1;
+	  break;
+	case 'm':
+	  /* Match number of month.  */
+	  get_number (1, 12, 2);
+	  tm->tm_mon = val - 1;
+	  have_mon = 1;
+	  want_xday = 1;
+	  break;
+	case 'M':
+	  /* Match minute.  */
+	  get_number (0, 59, 2);
+	  tm->tm_min = val;
+	  break;
+	case 'n':
+	case 't':
+	  /* Match any white space.  */
+	  while (isspace (*rp))
+	    ++rp;
+	  break;
+	case 'p':
+	  /* Match locale's equivalent of AM/PM.  */
+#ifdef _NL_CURRENT
+	  if (*decided != raw)
+	    {
+	      if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
+		{
+		  if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
+		    *decided = loc;
+		  break;
+		}
+	      if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
+		{
+		  if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
+		    *decided = loc;
+		  is_pm = 1;
+		  break;
+		}
+	      *decided = raw;
+	    }
+#endif
+	  if (!match_string (HERE_AM_STR, rp)) {
+	    if (match_string (HERE_PM_STR, rp)) {
+	      is_pm = 1;
+	    } else {
+	      return NULL;
+	    }
+	  }
+	  break;
+	case 'r':
+#ifdef _NL_CURRENT
+	  if (*decided != raw)
+	    {
+	      if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
+		{
+		  if (*decided == loc)
+		    return NULL;
+		  else
+		    rp = rp_backup;
+		}
+	      else
+		{
+		  if (*decided == not &&
+		      strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
+			      HERE_T_FMT_AMPM))
+		    *decided = loc;
+		  break;
+		}
+	      *decided = raw;
+	    }
+#endif
+	  if (!recursive (HERE_T_FMT_AMPM))
+	    return NULL;
+	  break;
+	case 'R':
+	  if (!recursive ("%H:%M"))
+	    return NULL;
+	  break;
+	case 's':
+	  {
+	    /* The number of seconds may be very high so we cannot use
+	       the `get_number' macro.  Instead read the number
+	       character for character and construct the result while
+	       doing this.  */
+	    time_t secs = 0;
+	    if (*rp < '0' || *rp > '9')
+	      /* We need at least one digit.  */
+	      return NULL;
+
+	    do
+	      {
+		secs *= 10;
+		secs += *rp++ - '0';
+	      }
+	    while (*rp >= '0' && *rp <= '9');
+
+	    if (localtime_r (&secs, tm) == NULL)
+	      /* Error in function.  */
+	      return NULL;
+	  }
+	  break;
+	case 'S':
+	  get_number (0, 61, 2);
+	  tm->tm_sec = val;
+	  break;
+	case 'X':
+#ifdef _NL_CURRENT
+	  if (*decided != raw)
+	    {
+	      if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
+		{
+		  if (*decided == loc)
+		    return NULL;
+		  else
+		    rp = rp_backup;
+		}
+	      else
+		{
+		  if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
+		    *decided = loc;
+		  break;
+		}
+	      *decided = raw;
+	    }
+#endif
+	  /* Fall through.  */
+	case 'T':
+	  if (!recursive (HERE_T_FMT))
+	    return NULL;
+	  break;
+	case 'u':
+	  get_number (1, 7, 1);
+	  tm->tm_wday = val % 7;
+	  have_wday = 1;
+	  break;
+	case 'g':
+	  get_number (0, 99, 2);
+	  /* XXX This cannot determine any field in TM.  */
+	  break;
+	case 'G':
+	  if (*rp < '0' || *rp > '9')
+	    return NULL;
+	  /* XXX Ignore the number since we would need some more
+	     information to compute a real date.  */
+	  do
+	    ++rp;
+	  while (*rp >= '0' && *rp <= '9');
+	  break;
+	case 'U':
+	case 'V':
+	case 'W':
+	  get_number (0, 53, 2);
+	  /* XXX This cannot determine any field in TM without some
+	     information.  */
+	  break;
+	case 'w':
+	  /* Match number of weekday.  */
+	  get_number (0, 6, 1);
+	  tm->tm_wday = val;
+	  have_wday = 1;
+	  break;
+	case 'y':
+#ifdef _NL_CURRENT
+	match_year_in_century:
+#endif
+	  /* Match year within century.  */
+	  get_number (0, 99, 2);
+	  /* The "Year 2000: The Millennium Rollover" paper suggests that
+	     values in the range 69-99 refer to the twentieth century.  */
+	  tm->tm_year = val >= 69 ? val : val + 100;
+	  /* Indicate that we want to use the century, if specified.  */
+	  want_century = 1;
+	  want_xday = 1;
+	  break;
+	case 'Y':
+	  /* Match year including century number.  */
+	  get_number (0, 9999, 4);
+	  tm->tm_year = val - 1900;
+	  want_century = 0;
+	  want_xday = 1;
+	  break;
+	case 'Z':
+	  /* XXX How to handle this?  */
+	  break;
+	case 'E':
+#ifdef _NL_CURRENT
+	  switch (*fmt++)
+	    {
+	    case 'c':
+	      /* Match locale's alternate date and time format.  */
+	      if (*decided != raw)
+		{
+		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
+
+		  if (*fmt == '\0')
+		    fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
+
+		  if (!recursive (fmt))
+		    {
+		      if (*decided == loc)
+			return NULL;
+		      else
+			rp = rp_backup;
+		    }
+		  else
+		    {
+		      if (strcmp (fmt, HERE_D_T_FMT))
+			*decided = loc;
+		      want_xday = 1;
+		      break;
+		    }
+		  *decided = raw;
+		}
+	      /* The C locale has no era information, so use the
+		 normal representation.  */
+	      if (!recursive (HERE_D_T_FMT))
+		return NULL;
+	      want_xday = 1;
+	      break;
+	    case 'C':
+	      if (*decided != raw)
+		{
+		  if (era_cnt >= 0)
+		    {
+		      era = _nl_select_era_entry (era_cnt);
+		      if (match_string (era->era_name, rp))
+			{
+			  *decided = loc;
+			  break;
+			}
+		      else
+			return NULL;
+		    }
+		  else
+		    {
+		      num_eras = _NL_CURRENT_WORD (LC_TIME,
+						   _NL_TIME_ERA_NUM_ENTRIES);
+		      for (era_cnt = 0; era_cnt < (int) num_eras;
+			   ++era_cnt, rp = rp_backup)
+			{
+			  era = _nl_select_era_entry (era_cnt);
+			  if (match_string (era->era_name, rp))
+			    {
+			      *decided = loc;
+			      break;
+			    }
+			}
+		      if (era_cnt == (int) num_eras)
+			{
+			  era_cnt = -1;
+			  if (*decided == loc)
+			    return NULL;
+			}
+		      else
+			break;
+		    }
+
+		  *decided = raw;
+		}
+	      /* The C locale has no era information, so use the
+		 normal representation.  */
+	      goto match_century;
+ 	    case 'y':
+	      if (*decided == raw)
+		goto match_year_in_century;
+
+	      get_number(0, 9999, 4);
+	      tm->tm_year = val;
+	      want_era = 1;
+	      want_xday = 1;
+	      break;
+	    case 'Y':
+	      if (*decided != raw)
+		{
+		  num_eras = _NL_CURRENT_WORD (LC_TIME,
+					       _NL_TIME_ERA_NUM_ENTRIES);
+		  for (era_cnt = 0; era_cnt < (int) num_eras;
+		       ++era_cnt, rp = rp_backup)
+		    {
+		      era = _nl_select_era_entry (era_cnt);
+		      if (recursive (era->era_format))
+			break;
+		    }
+		  if (era_cnt == (int) num_eras)
+		    {
+		      era_cnt = -1;
+		      if (*decided == loc)
+			return NULL;
+		      else
+			rp = rp_backup;
+		    }
+		  else
+		    {
+		      *decided = loc;
+		      era_cnt = -1;
+		      break;
+		    }
+
+		  *decided = raw;
+		}
+	      get_number (0, 9999, 4);
+	      tm->tm_year = val - 1900;
+	      want_century = 0;
+	      want_xday = 1;
+	      break;
+	    case 'x':
+	      if (*decided != raw)
+		{
+		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
+
+		  if (*fmt == '\0')
+		    fmt = _NL_CURRENT (LC_TIME, D_FMT);
+
+		  if (!recursive (fmt))
+		    {
+		      if (*decided == loc)
+			return NULL;
+		      else
+			rp = rp_backup;
+		    }
+		  else
+		    {
+		      if (strcmp (fmt, HERE_D_FMT))
+			*decided = loc;
+		      break;
+		    }
+		  *decided = raw;
+		}
+	      if (!recursive (HERE_D_FMT))
+		return NULL;
+	      break;
+	    case 'X':
+	      if (*decided != raw)
+		{
+		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
+
+		  if (*fmt == '\0')
+		    fmt = _NL_CURRENT (LC_TIME, T_FMT);
+
+		  if (!recursive (fmt))
+		    {
+		      if (*decided == loc)
+			return NULL;
+		      else
+			rp = rp_backup;
+		    }
+		  else
+		    {
+		      if (strcmp (fmt, HERE_T_FMT))
+			*decided = loc;
+		      break;
+		    }
+		  *decided = raw;
+		}
+	      if (!recursive (HERE_T_FMT))
+		return NULL;
+	      break;
+	    default:
+	      return NULL;
+	    }
+	  break;
+#else
+	  /* We have no information about the era format.  Just use
+	     the normal format.  */
+	  if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
+	      && *fmt != 'x' && *fmt != 'X')
+	    /* This is an illegal format.  */
+	    return NULL;
+
+	  goto start_over;
+#endif
+	case 'O':
+	  switch (*fmt++)
+	    {
+	    case 'd':
+	    case 'e':
+	      /* Match day of month using alternate numeric symbols.  */
+	      get_alt_number (1, 31, 2);
+	      tm->tm_mday = val;
+	      have_mday = 1;
+	      want_xday = 1;
+	      break;
+	    case 'H':
+	      /* Match hour in 24-hour clock using alternate numeric
+		 symbols.  */
+	      get_alt_number (0, 23, 2);
+	      tm->tm_hour = val;
+	      have_I = 0;
+	      break;
+	    case 'I':
+	      /* Match hour in 12-hour clock using alternate numeric
+		 symbols.  */
+	      get_alt_number (1, 12, 2);
+	      tm->tm_hour = val - 1;
+	      have_I = 1;
+	      break;
+	    case 'm':
+	      /* Match month using alternate numeric symbols.  */
+	      get_alt_number (1, 12, 2);
+	      tm->tm_mon = val - 1;
+	      have_mon = 1;
+	      want_xday = 1;
+	      break;
+	    case 'M':
+	      /* Match minutes using alternate numeric symbols.  */
+	      get_alt_number (0, 59, 2);
+	      tm->tm_min = val;
+	      break;
+	    case 'S':
+	      /* Match seconds using alternate numeric symbols.  */
+	      get_alt_number (0, 61, 2);
+	      tm->tm_sec = val;
+	      break;
+	    case 'U':
+	    case 'V':
+	    case 'W':
+	      get_alt_number (0, 53, 2);
+	      /* XXX This cannot determine any field in TM without
+		 further information.  */
+	      break;
+	    case 'w':
+	      /* Match number of weekday using alternate numeric symbols.  */
+	      get_alt_number (0, 6, 1);
+	      tm->tm_wday = val;
+	      have_wday = 1;
+	      break;
+	    case 'y':
+	      /* Match year within century using alternate numeric symbols.  */
+	      get_alt_number (0, 99, 2);
+	      tm->tm_year = val >= 69 ? val : val + 100;
+	      want_xday = 1;
+	      break;
+	    default:
+	      return NULL;
+	    }
+	  break;
+	default:
+	  return NULL;
+	}
+    }
+
+  if (have_I && is_pm)
+    tm->tm_hour += 12;
+
+  if (century != -1)
+    {
+      if (want_century)
+	tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
+      else
+	/* Only the century, but not the year.  Strange, but so be it.  */
+	tm->tm_year = (century - 19) * 100;
+    }
+
+#ifdef _NL_CURRENT
+  if (era_cnt != -1)
+    {
+      era = _nl_select_era_entry(era_cnt);
+      if (want_era)
+	tm->tm_year = (era->start_date[0]
+		       + ((tm->tm_year - era->offset)
+			  * era->absolute_direction));
+      else
+	/* Era start year assumed.  */
+	tm->tm_year = era->start_date[0];
+    }
+  else
+#endif
+    if (want_era)
+      return NULL;
+
+  if (want_xday && !have_wday)
+    {
+      if ( !(have_mon && have_mday) && have_yday)
+	{
+	  /* We don't have tm_mon and/or tm_mday, compute them.  */
+	  int t_mon = 0;
+	  while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
+	      t_mon++;
+	  if (!have_mon)
+	      tm->tm_mon = t_mon - 1;
+	  if (!have_mday)
+	      tm->tm_mday =
+		(tm->tm_yday
+		 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
+	}
+      day_of_the_week (tm);
+    }
+  if (want_xday && !have_yday)
+    day_of_the_year (tm);
+
+  return discard_const_p(char, rp);
+}
+
+
+char *rep_strptime(const char *buf, const char *format, struct tm *tm)
+{
+  enum locale_status decided;
+
+#ifdef _NL_CURRENT
+  decided = not;
+#else
+  decided = raw;
+#endif
+  return strptime_internal (buf, format, tm, &decided, -1);
+}

Added: branches/ctdb/squeeze-backports/lib/replace/strptime.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/strptime.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/strptime.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+AC_CACHE_CHECK([whether strptime is available and works],libreplace_cv_STRPTIME_OK,[
+	AC_TRY_RUN([
+		#define LIBREPLACE_CONFIGURE_TEST_STRPTIME
+		#include "$libreplacedir/test/strptime.c"
+		],
+		[libreplace_cv_STRPTIME_OK=yes],
+		[libreplace_cv_STRPTIME_OK=no],
+		[libreplace_cv_STRPTIME_OK="assuming not"])
+])
+if test x"$libreplace_cv_STRPTIME_OK" != x"yes"; then
+        AC_DEFINE(REPLACE_STRPTIME,1,[Whether strptime should be replaced])
+        LIBREPLACEOBJ="${LIBREPLACEOBJ} strptime.o"
+fi

Added: branches/ctdb/squeeze-backports/lib/replace/system/README
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,4 @@
+This directory contains wrappers around logical groups of system
+include files. The idea is to avoid #ifdef blocks in the main code,
+and instead put all the necessary conditional includes in subsystem
+specific header files in this directory.

Added: branches/ctdb/squeeze-backports/lib/replace/system/aio.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/aio.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/aio.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,32 @@
+#ifndef _system_aio_h
+#define _system_aio_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   AIO system include wrappers
+
+   Copyright (C) Andrew Tridgell 2006
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_LIBAIO_H
+#include <libaio.h>
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/capability.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/capability.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/capability.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,55 @@
+#ifndef _system_capability_h
+#define _system_capability_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   capability system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_SYS_CAPABILITY_H
+
+#if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H) && !defined(_PPC_STATFS_H)
+#define _I386_STATFS_H
+#define _PPC_STATFS_H
+#define BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
+
+#if defined(BROKEN_RHEL5_SYS_CAP_HEADER) && !defined(_LINUX_TYPES_H)
+#define BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#endif
+
+#include <sys/capability.h>
+
+#ifdef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#undef _LINUX_TYPES_H
+#undef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#endif
+
+#ifdef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#undef _PPC_STATFS_H
+#undef _I386_STATFS_H
+#undef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
+
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/config.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/config.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/config.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,104 @@
+# filesys
+AC_HEADER_DIRENT 
+AC_CHECK_HEADERS(fcntl.h sys/fcntl.h sys/resource.h sys/ioctl.h sys/mode.h sys/filio.h sys/fs/s5param.h sys/filsys.h)
+AC_CHECK_HEADERS(sys/acl.h acl/libacl.h)
+
+# select
+AC_CHECK_HEADERS(sys/select.h)
+
+# time
+AC_CHECK_HEADERS(sys/time.h utime.h)
+AC_HEADER_TIME
+
+# wait
+AC_HEADER_SYS_WAIT
+
+# capability
+AC_CHECK_HEADERS(sys/capability.h)
+
+case "$host_os" in
+*linux*)
+AC_CACHE_CHECK([for broken RedHat 7.2 system header files],samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS,[
+AC_TRY_COMPILE([
+	#ifdef HAVE_SYS_VFS_H
+	#include <sys/vfs.h>
+	#endif
+	#ifdef HAVE_SYS_CAPABILITY_H
+	#include <sys/capability.h>
+	#endif
+	],[
+	int i;
+	],
+	samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=no,
+	samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=yes
+)])
+if test x"$samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" = x"yes"; then
+	AC_DEFINE(BROKEN_REDHAT_7_SYSTEM_HEADERS,1,[Broken RedHat 7.2 system header files])
+fi
+
+AC_CACHE_CHECK([for broken RHEL5 sys/capability.h],samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER,[
+AC_TRY_COMPILE([
+	#ifdef HAVE_SYS_CAPABILITY_H
+	#include <sys/capability.h>
+	#endif
+	#include <linux/types.h>
+	],[
+	__s8 i;
+	],
+	samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER=no,
+	samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER=yes
+)])
+if test x"$samba_cv_BROKEN_RHEL5_SYS_CAP_HEADER" = x"yes"; then
+	AC_DEFINE(BROKEN_RHEL5_SYS_CAP_HEADER,1,[Broken RHEL5 sys/capability.h])
+fi
+;;
+esac
+
+# passwd
+AC_CHECK_HEADERS(grp.h sys/id.h compat.h shadow.h sys/priv.h pwd.h sys/security.h)
+AC_CHECK_FUNCS(getpwnam_r getpwuid_r getpwent_r)
+AC_HAVE_DECL(getpwent_r, [
+	#include <unistd.h>
+	#include <pwd.h>
+	])
+AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)],
+	[
+	#ifndef HAVE_GETPWENT_R_DECL
+	#error missing getpwent_r prototype
+	#endif
+	return NULL;
+	],[
+	AC_DEFINE(SOLARIS_GETPWENT_R, 1, [getpwent_r solaris function prototype])
+	],[],[
+	#include <unistd.h>
+	#include <pwd.h>
+	])
+AC_CHECK_FUNCS(getgrnam_r getgrgid_r getgrent_r)
+AC_HAVE_DECL(getgrent_r, [
+	#include <unistd.h>
+	#include <grp.h>
+	])
+AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, int buflen)],
+	[
+	#ifndef HAVE_GETGRENT_R_DECL
+	#error missing getgrent_r prototype
+	#endif
+	return NULL;
+	],[
+	AC_DEFINE(SOLARIS_GETGRENT_R, 1, [getgrent_r solaris function prototype])
+	],[],[
+	#include <unistd.h>
+	#include <grp.h>
+	])
+
+# locale
+AC_CHECK_HEADERS(ctype.h locale.h)
+
+# glob
+AC_CHECK_HEADERS(fnmatch.h)
+
+# shmem
+AC_CHECK_HEADERS(sys/ipc.h sys/mman.h sys/shm.h )
+
+# terminal
+AC_CHECK_HEADERS(termios.h termio.h sys/termio.h )

Added: branches/ctdb/squeeze-backports/lib/replace/system/dir.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/dir.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/dir.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,67 @@
+#ifndef _system_dir_h
+#define _system_dir_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   directory system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#ifndef HAVE_MKDIR_MODE
+#define mkdir(dir, mode) mkdir(dir)
+#endif
+
+/* Test whether a file name is the "." or ".." directory entries.
+ * These really should be inline functions.
+ */
+#ifndef ISDOT
+#define ISDOT(path) ( \
+			*((const char *)(path)) == '.' && \
+			*(((const char *)(path)) + 1) == '\0' \
+		    )
+#endif
+
+#ifndef ISDOTDOT
+#define ISDOTDOT(path)	( \
+			    *((const char *)(path)) == '.' && \
+			    *(((const char *)(path)) + 1) == '.' && \
+			    *(((const char *)(path)) + 2) == '\0' \
+			)
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/filesys.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/filesys.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/filesys.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,182 @@
+#ifndef _system_filesys_h
+#define _system_filesys_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   filesystem system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+
+#ifdef HAVE_ACL_LIBACL_H
+#include <acl/libacl.h>
+#endif
+
+#ifdef HAVE_SYS_FS_S5PARAM_H 
+#include <sys/fs/s5param.h>
+#endif
+
+#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY)
+#include <sys/filsys.h> 
+#endif
+
+#ifdef HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+#endif
+
+#ifdef HAVE_DUSTAT_H              
+#include <sys/dustat.h>
+#endif
+
+#ifdef HAVE_SYS_STATVFS_H          
+#include <sys/statvfs.h>
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#include <sys/file.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_MODE_H
+/* apparently AIX needs this for S_ISLNK */
+#ifndef S_ISLNK
+#include <sys/mode.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * Veritas File System.  Often in addition to native.
+ * Quotas different.
+ */
+#if defined(HAVE_SYS_FS_VX_QUOTA_H)
+#define VXFS_QUOTA
+#endif
+
+#if HAVE_SYS_ATTRIBUTES_H
+#include <sys/attributes.h>
+#endif
+
+/* mutually exclusive (SuSE 8.2) */
+#if HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#elif HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+/* Some POSIX definitions for those without */
+ 
+#ifndef S_IFDIR
+#define S_IFDIR         0x4000
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode)   ((mode & 0xF000) == S_IFDIR)
+#endif
+#ifndef S_IRWXU
+#define S_IRWXU 00700           /* read, write, execute: owner */
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 00400           /* read permission: owner */
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 00200           /* write permission: owner */
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100           /* execute permission: owner */
+#endif
+#ifndef S_IRWXG
+#define S_IRWXG 00070           /* read, write, execute: group */
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040           /* read permission: group */
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 00020           /* write permission: group */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010           /* execute permission: group */
+#endif
+#ifndef S_IRWXO
+#define S_IRWXO 00007           /* read, write, execute: other */
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004           /* read permission: other */
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 00002           /* write permission: other */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001           /* execute permission: other */
+#endif
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 256
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/glob.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/glob.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/glob.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,37 @@
+#ifndef _system_glob_h
+#define _system_glob_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   glob system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif
+
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/iconv.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/iconv.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/iconv.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,57 @@
+#ifndef _system_iconv_h
+#define _system_iconv_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   iconv memory system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined(HAVE_ICONV) && defined(HAVE_ICONV_H)
+#define HAVE_ICONV
+#endif
+
+#if !defined(HAVE_GICONV) && defined(HAVE_GICONV_H)
+#define HAVE_GICONV
+#endif
+
+#if !defined(HAVE_BICONV) && defined(HAVE_BICONV_H)
+#define HAVE_BICONV
+#endif
+
+#ifdef HAVE_NATIVE_ICONV
+#if defined(HAVE_ICONV)
+#include <iconv.h>
+#elif defined(HAVE_GICONV)
+#include <giconv.h>
+#elif defined(HAVE_BICONV)
+#include <biconv.h>
+#endif
+#endif /* HAVE_NATIVE_ICONV */
+
+/* needed for some systems without iconv. Doesn't really matter
+   what error code we use */
+#ifndef EILSEQ
+#define EILSEQ EIO
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/kerberos.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/kerberos.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/kerberos.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,136 @@
+#ifndef _system_kerberos_h
+#define _system_kerberos_h
+
+/* 
+   Unix SMB/CIFS implementation.
+
+   kerberos system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_KRB5
+/* Whether the krb5_address struct has a addrtype property */
+/* #undef HAVE_ADDRTYPE_IN_KRB5_ADDRESS */
+/* Whether the krb5_address struct has a addr_type property */
+#define HAVE_ADDR_TYPE_IN_KRB5_ADDRESS 1
+/* Define to 1 if you have the `gsskrb5_extract_authz_data_from_sec_context' */
+#define HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT 1
+/* Define to 1 if you have the `gsskrb5_get_initiator_subkey' function. */
+#define HAVE_GSSKRB5_GET_INITIATOR_SUBKEY 1
+/* Define to 1 if you have the `gsskrb5_register_acceptor_identity' function. */
+#define HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY 1
+/* Define to 1 if you have the `gss_krb5_ccache_name' function. */
+#define HAVE_GSS_KRB5_CCACHE_NAME 1
+/* Define to 1 if you have the `krb5_addlog_func' function. */
+#define HAVE_KRB5_ADDLOG_FUNC 1
+/* Define to 1 if you have the `krb5_auth_con_setkey' function. */
+#define HAVE_KRB5_AUTH_CON_SETKEY 1
+/* Define to 1 if you have the `krb5_auth_con_setuseruserkey' function. */
+/* #undef HAVE_KRB5_AUTH_CON_SETUSERUSERKEY */
+/* Define to 1 if you have the `krb5_c_enctype_compare' function. */
+#define HAVE_KRB5_C_ENCTYPE_COMPARE 1
+/* Define to 1 if you have the `krb5_c_verify_checksum' function. */
+#define HAVE_KRB5_C_VERIFY_CHECKSUM 1
+/* Whether the type krb5_encrypt_block exists */
+/* #undef HAVE_KRB5_ENCRYPT_BLOCK */
+/* Define to 1 if you have the `krb5_encrypt_data' function. */
+/* #undef HAVE_KRB5_ENCRYPT_DATA */
+/* Define to 1 if you have the `krb5_enctypes_compatible_keys' function. */
+#define HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS 1
+/* Define to 1 if you have the `krb5_free_data_contents' function. */
+#define HAVE_KRB5_FREE_DATA_CONTENTS 1
+/* Define to 1 if you have the `krb5_free_error_string' function. */
+#define HAVE_KRB5_FREE_ERROR_STRING 1
+/* Define to 1 if you have the `krb5_free_keytab_entry_contents' function. */
+/* #undef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS */
+/* Define to 1 if you have the `krb5_free_ktypes' function. */
+/* #undef HAVE_KRB5_FREE_KTYPES */
+/* Define to 1 if you have the `krb5_free_unparsed_name' function. */
+/* #undef HAVE_KRB5_FREE_UNPARSED_NAME */
+/* Define to 1 if you have the `krb5_get_default_in_tkt_etypes' function. */
+#define HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES 1
+/* Define to 1 if you have the `krb5_get_error_string' function. */
+#define HAVE_KRB5_GET_ERROR_STRING 1
+/* Define to 1 if you have the `krb5_get_permitted_enctypes' function. */
+/* #undef HAVE_KRB5_GET_PERMITTED_ENCTYPES */
+/* Define to 1 if you have the `krb5_get_pw_salt' function. */
+#define HAVE_KRB5_GET_PW_SALT 1
+/* Define to 1 if you have the <krb5.h> header file. */
+#define HAVE_KRB5_H 1
+/* Define to 1 if you have the `krb5_initlog' function. */
+#define HAVE_KRB5_INITLOG 1
+/* Define to 1 if you have the `krb5_kdc_default_config' function. */
+#define HAVE_KRB5_KDC_DEFAULT_CONFIG 1
+/* Whether the krb5_creds struct has a keyblock property */
+/* #undef HAVE_KRB5_KEYBLOCK_IN_CREDS */
+/* Whether the krb5_keyblock struct has a keyvalue property */
+#define HAVE_KRB5_KEYBLOCK_KEYVALUE 1
+/* Whether krb5_keytab_entry has key member */
+/* #undef HAVE_KRB5_KEYTAB_ENTRY_KEY */
+/* Whether krb5_keytab_entry has keyblock member */
+#define HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK 1
+/* Define to 1 if you have the `krb5_krbhst_get_addrinfo' function. */
+#define HAVE_KRB5_KRBHST_GET_ADDRINFO 1
+/* Define to 1 if you have the `krb5_kt_compare' function. */
+#define HAVE_KRB5_KT_COMPARE 1
+/* Define to 1 if you have the `krb5_kt_free_entry' function. */
+#define HAVE_KRB5_KT_FREE_ENTRY 1
+/* Whether the type krb5_log_facility exists */
+#define HAVE_KRB5_LOG_FACILITY 1
+/* Define to 1 if you have the `krb5_mk_req_extended' function. */
+#define HAVE_KRB5_MK_REQ_EXTENDED 1
+/* Define to 1 if you have the `krb5_principal2salt' function. */
+/* #undef HAVE_KRB5_PRINCIPAL2SALT */
+/* Define to 1 if you have the `krb5_principal_get_comp_string' function. */
+#define HAVE_KRB5_PRINCIPAL_GET_COMP_STRING 1
+/* Whether krb5_princ_component is available */
+/* #undef HAVE_KRB5_PRINC_COMPONENT */
+/* Whether the krb5_creds struct has a session property */
+#define HAVE_KRB5_SESSION_IN_CREDS 1
+/* Define to 1 if you have the `krb5_set_default_in_tkt_etypes' function. */
+#define HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES 1
+/* Define to 1 if you have the `krb5_set_default_tgs_ktypes' function. */
+/* #undef HAVE_KRB5_SET_DEFAULT_TGS_KTYPES */
+/* Define to 1 if you have the `krb5_set_real_time' function. */
+#define HAVE_KRB5_SET_REAL_TIME 1
+/* Define to 1 if you have the `krb5_set_warn_dest' function. */
+#define HAVE_KRB5_SET_WARN_DEST 1
+/* Define to 1 if you have the `krb5_string_to_key' function. */
+#define HAVE_KRB5_STRING_TO_KEY 1
+/* Define to 1 if you have the `krb5_string_to_key_salt' function. */
+#define HAVE_KRB5_STRING_TO_KEY_SALT 1
+/* Define to 1 if you have the `krb5_ticket_get_authorization_data_type' */
+#define HAVE_KRB5_TICKET_GET_AUTHORIZATION_DATA_TYPE 1
+/* Whether the krb5_ticket struct has a enc_part2 property */
+/* #undef HAVE_KRB5_TKT_ENC_PART2 */
+/* Define to 1 if you have the `krb5_use_enctype' function. */
+/* #undef HAVE_KRB5_USE_ENCTYPE */
+/* Define to 1 if you have the `krb5_verify_checksum' function. */
+#define HAVE_KRB5_VERIFY_CHECKSUM 1
+/* Whether krb5_princ_realm returns krb5_realm or krb5_data */
+#define KRB5_PRINC_REALM_RETURNS_REALM 1
+
+#include "heimdal/lib/krb5/krb5.h"
+#include "heimdal/lib/com_err/com_err.h"
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/locale.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/locale.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/locale.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,38 @@
+#ifndef _system_locale_h
+#define _system_locale_h
+
+/* 
+   Unix SMB/CIFS implementation.
+
+   locale include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/network.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/network.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/network.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,297 @@
+#ifndef _system_network_h
+#define _system_network_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   networking system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   Copyright (C) Jelmer Vernooij 2007
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_UNIXSOCKET
+#include <sys/un.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+/*
+ * The next three defines are needed to access the IPTOS_* options
+ * on some systems.
+ */
+
+#ifdef HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_IP_H
+#include <netinet/in_ip.h>
+#endif
+
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef REPLACE_INET_NTOA
+/* define is in "replace.h" */
+char *rep_inet_ntoa(struct in_addr ip);
+#endif
+
+#ifndef HAVE_INET_PTON
+/* define is in "replace.h" */
+int rep_inet_pton(int af, const char *src, void *dst);
+#endif
+
+#ifndef HAVE_INET_NTOP
+/* define is in "replace.h" */
+const char *rep_inet_ntop(int af, const void *src, char *dst, socklen_t size);
+#endif
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
+#ifndef HAVE_STRUCT_IFADDRS
+struct ifaddrs {
+	struct ifaddrs   *ifa_next;         /* Pointer to next struct */
+	char             *ifa_name;         /* Interface name */
+	unsigned int     ifa_flags;         /* Interface flags */
+	struct sockaddr  *ifa_addr;         /* Interface address */
+	struct sockaddr  *ifa_netmask;      /* Interface netmask */
+#undef ifa_dstaddr
+	struct sockaddr  *ifa_dstaddr;      /* P2P interface destination */
+	void             *ifa_data;         /* Address specific data */
+};
+#endif
+
+#ifndef HAVE_GETIFADDRS
+int rep_getifaddrs(struct ifaddrs **);
+#endif
+
+#ifndef HAVE_FREEIFADDRS
+void rep_freeifaddrs(struct ifaddrs *);
+#endif
+
+/*
+ * Some systems have getaddrinfo but not the
+ * defines needed to use it.
+ */
+
+/* Various macros that ought to be in <netdb.h>, but might not be */
+
+#ifndef EAI_FAIL
+#define EAI_BADFLAGS	(-1)
+#define EAI_NONAME	(-2)
+#define EAI_AGAIN	(-3)
+#define EAI_FAIL	(-4)
+#define EAI_FAMILY	(-6)
+#define EAI_SOCKTYPE	(-7)
+#define EAI_SERVICE	(-8)
+#define EAI_MEMORY	(-10)
+#define EAI_SYSTEM	(-11)
+#endif   /* !EAI_FAIL */
+
+#ifndef AI_PASSIVE
+#define AI_PASSIVE	0x0001
+#endif
+
+#ifndef AI_CANONNAME
+#define AI_CANONNAME	0x0002
+#endif
+
+#ifndef AI_NUMERICHOST
+/*
+ * some platforms don't support AI_NUMERICHOST; define as zero if using
+ * the system version of getaddrinfo...
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_NUMERICHOST	0
+#else
+#define AI_NUMERICHOST	0x0004
+#endif
+#endif
+
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG	0x0020
+#endif
+
+#ifndef AI_NUMERICSERV
+/*
+ * logic copied from AI_NUMERICHOST
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_NUMERICSERV	0
+#else
+#define AI_NUMERICSERV	0x0400
+#endif
+#endif
+
+#ifndef NI_NUMERICHOST
+#define NI_NUMERICHOST	1
+#endif
+
+#ifndef NI_NUMERICSERV
+#define NI_NUMERICSERV	2
+#endif
+
+#ifndef NI_NOFQDN
+#define NI_NOFQDN	4
+#endif
+
+#ifndef NI_NAMEREQD
+#define NI_NAMEREQD 	8
+#endif
+
+#ifndef NI_DGRAM
+#define NI_DGRAM	16
+#endif
+
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST	1025
+#endif
+
+#ifndef NI_MAXSERV
+#define NI_MAXSERV	32
+#endif
+
+/*
+ * glibc on linux doesn't seem to have MSG_WAITALL
+ * defined. I think the kernel has it though..
+ */
+#ifndef MSG_WAITALL
+#define MSG_WAITALL 0
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT EINVAL
+#endif
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 256
+#endif
+
+#ifndef HAVE_SOCKLEN_T
+#define HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#ifndef HAVE_SA_FAMILY_T
+#define HAVE_SA_FAMILY_T
+typedef unsigned short int sa_family_t;
+#endif
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+#define HAVE_STRUCT_SOCKADDR_STORAGE
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+#define sockaddr_storage sockaddr_in6
+#define ss_family sin6_family
+#define HAVE_SS_FAMILY 1
+#else
+#define sockaddr_storage sockaddr_in
+#define ss_family sin_family
+#define HAVE_SS_FAMILY 1
+#endif
+#endif
+
+#ifndef HAVE_SS_FAMILY
+#ifdef HAVE___SS_FAMILY
+#define ss_family __ss_family
+#define HAVE_SS_FAMILY 1
+#endif
+#endif
+
+#ifndef HAVE_STRUCT_ADDRINFO
+#define HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+	int			ai_flags;
+	int			ai_family;
+	int			ai_socktype;
+	int			ai_protocol;
+	socklen_t		ai_addrlen;
+	struct sockaddr 	*ai_addr;
+	char			*ai_canonname;
+	struct addrinfo		*ai_next;
+};
+#endif   /* HAVE_STRUCT_ADDRINFO */
+
+#if !defined(HAVE_GETADDRINFO)
+#include "getaddrinfo.h"
+#endif
+
+/* Needed for some systems that don't define it (Solaris). */
+#ifndef ifr_netmask
+#define ifr_netmask ifr_addrs
+#endif
+
+#ifdef SOCKET_WRAPPER
+#ifndef SOCKET_WRAPPER_NOT_REPLACE
+#define SOCKET_WRAPPER_REPLACE
+#endif
+#include "lib/socket_wrapper/socket_wrapper.h"
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/passwd.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/passwd.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/passwd.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,106 @@
+#ifndef _system_passwd_h
+#define _system_passwd_h
+
+/* 
+   Unix SMB/CIFS implementation.
+
+   passwd system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* this needs to be included before nss_wrapper.h on some systems */
+#include <unistd.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
+#endif
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#ifdef HAVE_SYS_SECURITY_H
+#include <sys/security.h>
+#include <prot.h>
+#define PASSWORD_LENGTH 16
+#endif  /* HAVE_SYS_SECURITY_H */
+
+#ifdef HAVE_GETPWANAM
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+
+#ifdef HAVE_COMPAT_H
+#include <compat.h>
+#endif
+
+#ifdef REPLACE_GETPASS
+#define getpass(prompt) rep_getpass(prompt)
+char *rep_getpass(const char *prompt);
+#endif
+
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX 32 /* Guess... */
+#endif
+
+/* what is the longest significant password available on your system? 
+ Knowing this speeds up password searches a lot */
+#ifndef PASSWORD_LENGTH
+#define PASSWORD_LENGTH 8
+#endif
+
+#if defined(HAVE_PUTPRPWNAM) && defined(AUTH_CLEARTEXT_SEG_CHARS)
+#define OSF1_ENH_SEC 1
+#endif
+
+#ifndef ALLOW_CHANGE_PASSWORD
+#if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
+#define ALLOW_CHANGE_PASSWORD 1
+#endif
+#endif
+
+#if defined(HAVE_CRYPT16) && defined(HAVE_GETAUTHUID)
+#define ULTRIX_AUTH 1
+#endif
+
+#ifdef NSS_WRAPPER
+#ifndef NSS_WRAPPER_NOT_REPLACE
+#define NSS_WRAPPER_REPLACE
+#endif
+#include "lib/nss_wrapper/nss_wrapper.h"
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/printing.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/printing.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/printing.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,50 @@
+#ifndef _system_printing_h
+#define _system_printing_h
+
+/* 
+   Unix SMB/CIFS implementation.
+
+   printing system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef AIX
+#define DEFAULT_PRINTING PRINT_AIX
+#define PRINTCAP_NAME "/etc/qconfig"
+#endif
+
+#ifdef HPUX
+#define DEFAULT_PRINTING PRINT_HPUX
+#endif
+
+#ifdef QNX
+#define DEFAULT_PRINTING PRINT_QNX
+#endif
+
+#ifndef DEFAULT_PRINTING
+#define DEFAULT_PRINTING PRINT_BSD
+#endif
+#ifndef PRINTCAP_NAME
+#define PRINTCAP_NAME "/etc/printcap"
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/readline.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/readline.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/readline.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,52 @@
+#ifndef _system_readline_h
+#define _system_readline_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   Readline wrappers
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_LIBREADLINE
+#  ifdef HAVE_READLINE_READLINE_H
+#    include <readline/readline.h>
+#    ifdef HAVE_READLINE_HISTORY_H
+#      include <readline/history.h>
+#    endif
+#  else
+#    ifdef HAVE_READLINE_H
+#      include <readline.h>
+#      ifdef HAVE_HISTORY_H
+#        include <history.h>
+#      endif
+#    else
+#      undef HAVE_LIBREADLINE
+#    endif
+#  endif
+#endif
+
+#ifdef HAVE_NEW_LIBREADLINE
+#  define RL_COMPLETION_CAST (rl_completion_func_t *)
+#else
+/* This type is missing from libreadline<4.0  (approximately) */
+#  define RL_COMPLETION_CAST
+#endif /* HAVE_NEW_LIBREADLINE */
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/select.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/select.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/select.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,41 @@
+#ifndef _system_select_h
+#define _system_select_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   select system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_EPOLL_H
+#include <sys/epoll.h>
+#endif
+
+#ifndef SELECT_CAST
+#define SELECT_CAST
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/shmem.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/shmem.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/shmem.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,59 @@
+#ifndef _system_shmem_h
+#define _system_shmem_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   shared memory system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#if defined(HAVE_SYS_IPC_H)
+#include <sys/ipc.h>
+#endif /* HAVE_SYS_IPC_H */
+
+#if defined(HAVE_SYS_SHM_H)
+#include <sys/shm.h>
+#endif /* HAVE_SYS_SHM_H */
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+/* NetBSD doesn't have these */
+#ifndef SHM_R
+#define SHM_R 0400
+#endif
+
+#ifndef SHM_W
+#define SHM_W 0200
+#endif
+
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/syslog.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/syslog.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/syslog.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,70 @@
+#ifndef _system_syslog_h
+#define _system_syslog_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   syslog system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#else
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif
+#endif
+
+/* For sys_adminlog(). */
+#ifndef LOG_EMERG
+#define LOG_EMERG       0       /* system is unusable */
+#endif
+
+#ifndef LOG_ALERT
+#define LOG_ALERT       1       /* action must be taken immediately */
+#endif
+
+#ifndef LOG_CRIT
+#define LOG_CRIT        2       /* critical conditions */
+#endif
+
+#ifndef LOG_ERR
+#define LOG_ERR         3       /* error conditions */
+#endif
+
+#ifndef LOG_WARNING
+#define LOG_WARNING     4       /* warning conditions */
+#endif
+
+#ifndef LOG_NOTICE
+#define LOG_NOTICE      5       /* normal but significant condition */
+#endif
+
+#ifndef LOG_INFO
+#define LOG_INFO        6       /* informational */
+#endif
+
+#ifndef LOG_DEBUG
+#define LOG_DEBUG       7       /* debug-level messages */
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/terminal.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/terminal.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/terminal.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,46 @@
+#ifndef _system_terminal_h
+#define _system_terminal_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   terminal system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef SUNOS4
+/* on SUNOS4 termios.h conflicts with sys/ioctl.h */
+#undef HAVE_TERMIOS_H
+#endif
+
+
+#if defined(HAVE_TERMIOS_H)
+/* POSIX terminal handling. */
+#include <termios.h>
+#elif defined(HAVE_TERMIO_H)
+/* Older SYSV terminal handling - don't use if we can avoid it. */
+#include <termio.h>
+#elif defined(HAVE_SYS_TERMIO_H)
+/* Older SYSV terminal handling - don't use if we can avoid it. */
+#include <sys/termio.h>
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/time.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/time.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/time.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,54 @@
+#ifndef _system_time_h
+#define _system_time_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   time system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+#ifndef HAVE_MKTIME
+/* define is in "replace.h" */
+time_t rep_mktime(struct tm *t);
+#endif
+
+#ifndef HAVE_TIMEGM
+/* define is in "replace.h" */
+time_t rep_timegm(struct tm *tm);
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/system/wait.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/system/wait.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/system/wait.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,55 @@
+#ifndef _system_wait_h
+#define _system_wait_h
+/* 
+   Unix SMB/CIFS implementation.
+
+   waitpid system include wrappers
+
+   Copyright (C) Andrew Tridgell 2004
+
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+#ifndef SIGNAL_CAST
+#define SIGNAL_CAST (RETSIGTYPE (*)(int))
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifndef SA_RESETHAND
+#define SA_RESETHAND SA_ONESHOT
+#endif
+
+#if !defined(HAVE_SIG_ATOMIC_T_TYPE)
+typedef int sig_atomic_t;
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/tests/os2_delete.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/tests/os2_delete.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/tests/os2_delete.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,115 @@
+/*
+  test readdir/unlink pattern that OS/2 uses
+  tridge at samba.org July 2005
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#define NUM_FILES 700
+#define READDIR_SIZE 100
+#define DELETE_SIZE 4
+
+#define TESTDIR "test.dir"
+
+static int test_readdir_os2_delete_ret;
+
+#define FAILED(d) (printf("failure: readdir [\nFailed for %s - %d = %s\n]\n", d, errno, strerror(errno)), test_readdir_os2_delete_ret = 1, 1)
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+static void cleanup(void)
+{
+	/* I'm a lazy bastard */
+	system("rm -rf " TESTDIR);
+	mkdir(TESTDIR, 0700) == 0 || FAILED("mkdir");
+}
+
+static void create_files(void)
+{
+	int i;
+	for (i=0;i<NUM_FILES;i++) {
+		char fname[40];
+		sprintf(fname, TESTDIR "/test%u.txt", i);
+		close(open(fname, O_CREAT|O_RDWR, 0600)) == 0 || FAILED("close");
+	}
+}
+
+static int os2_delete(DIR *d)
+{
+	off_t offsets[READDIR_SIZE];
+	int i, j;
+	struct dirent *de;
+	char names[READDIR_SIZE][30];
+
+	/* scan, remembering offsets */
+	for (i=0, de=readdir(d); 
+	     de && i < READDIR_SIZE; 
+	     de=readdir(d), i++) {
+		offsets[i] = telldir(d);
+		strcpy(names[i], de->d_name);
+	}
+
+	if (i == 0) {
+		return 0;
+	}
+
+	/* delete the first few */
+	for (j=0; j<MIN(i, DELETE_SIZE); j++) {
+		char fname[40];
+		sprintf(fname, TESTDIR "/%s", names[j]);
+		unlink(fname) == 0 || FAILED("unlink");
+	}
+
+	/* seek to just after the deletion */
+	seekdir(d, offsets[j-1]);
+
+	/* return number deleted */
+	return j;
+}
+
+int test_readdir_os2_delete(void)
+{
+	int total_deleted = 0;
+	DIR *d;
+	struct dirent *de;
+
+	test_readdir_os2_delete_ret = 0;
+
+	cleanup();
+	create_files();
+
+	d = opendir(TESTDIR "/test0.txt");
+	if (d != NULL) FAILED("opendir() on file succeed");
+	if (errno != ENOTDIR) FAILED("opendir() on file didn't give ENOTDIR");
+
+	d = opendir(TESTDIR);
+
+	/* skip past . and .. */
+	de = readdir(d);
+	strcmp(de->d_name, ".") == 0 || FAILED("match .");
+	de = readdir(d);
+	strcmp(de->d_name, "..") == 0 || FAILED("match ..");
+
+	while (1) {
+		int n = os2_delete(d);
+		if (n == 0) break;
+		total_deleted += n;
+	}
+	closedir(d);
+
+	fprintf(stderr, "Deleted %d files of %d\n", total_deleted, NUM_FILES);
+
+	rmdir(TESTDIR) == 0 || FAILED("rmdir");
+
+	return test_readdir_os2_delete_ret;
+}

Added: branches/ctdb/squeeze-backports/lib/replace/tests/shared_mmap.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/tests/shared_mmap.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/tests/shared_mmap.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,68 @@
+/* this tests whether we can use a shared writeable mmap on a file -
+   as needed for the mmap variant of FAST_SHARE_MODES */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define DATA "conftest.mmap"
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+main()
+{
+	int *buf;
+	int i; 
+	int fd = open(DATA,O_RDWR|O_CREAT|O_TRUNC,0666);
+	int count=7;
+
+	if (fd == -1) exit(1);
+
+	for (i=0;i<10000;i++) {
+		write(fd,&i,sizeof(i));
+	}
+
+	close(fd);
+
+	if (fork() == 0) {
+		fd = open(DATA,O_RDWR);
+		if (fd == -1) exit(1);
+
+		buf = (int *)mmap(NULL, 10000*sizeof(int), 
+				   (PROT_READ | PROT_WRITE), 
+				   MAP_FILE | MAP_SHARED, 
+				   fd, 0);
+
+		while (count-- && buf[9124] != 55732) sleep(1);
+
+		if (count <= 0) exit(1);
+
+		buf[1763] = 7268;
+		exit(0);
+	}
+
+	fd = open(DATA,O_RDWR);
+	if (fd == -1) exit(1);
+
+	buf = (int *)mmap(NULL, 10000*sizeof(int), 
+			   (PROT_READ | PROT_WRITE), 
+			   MAP_FILE | MAP_SHARED, 
+			   fd, 0);
+
+	if (buf == (int *)-1) exit(1);
+
+	buf[9124] = 55732;
+
+	while (count-- && buf[1763] != 7268) sleep(1);
+
+	unlink(DATA);
+		
+	if (count > 0) exit(0);
+	exit(1);
+}

Added: branches/ctdb/squeeze-backports/lib/replace/tests/testsuite.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/tests/testsuite.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/tests/testsuite.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,480 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   libreplace tests
+
+   Copyright (C) Jelmer Vernooij 2006
+
+     ** NOTE! The following LGPL license applies to the talloc
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+/*
+  we include all the system/ include files here so that libreplace tests
+  them in the build farm
+*/
+#include "system/capability.h"
+#include "system/dir.h"
+#include "system/filesys.h"
+#include "system/glob.h"
+#include "system/iconv.h"
+#include "system/locale.h"
+#include "system/network.h"
+#include "system/passwd.h"
+#include "system/printing.h"
+#include "system/readline.h"
+#include "system/select.h"
+#include "system/shmem.h"
+#include "system/syslog.h"
+#include "system/terminal.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/aio.h"
+
+#define TESTFILE "testfile.dat"
+
+/*
+  test ftruncate() function
+ */
+static int test_ftruncate(void)
+{
+	struct stat st;
+	int fd;
+	const int size = 1234;
+	printf("test: ftruncate\n");
+	unlink(TESTFILE);
+	fd = open(TESTFILE, O_RDWR|O_CREAT, 0600);
+	if (fd == -1) {
+		printf("failure: ftruncate [\n"
+			   "creating '%s' failed - %s\n]\n", TESTFILE, strerror(errno));
+		return false;
+	}
+	if (ftruncate(fd, size) != 0) {
+		printf("failure: ftruncate [\n%s\n]\n", strerror(errno));
+		return false;
+	}
+	if (fstat(fd, &st) != 0) {
+		printf("failure: ftruncate [\nfstat failed - %s\n]\n", strerror(errno));
+		return false;
+	}
+	if (st.st_size != size) {
+		printf("failure: ftruncate [\ngave wrong size %d - expected %d\n]\n",
+		       (int)st.st_size, size);
+		return false;
+	}
+	unlink(TESTFILE);
+	printf("success: ftruncate\n");
+	return true;
+}
+
+/*
+  test strlcpy() function.
+  see http://www.gratisoft.us/todd/papers/strlcpy.html
+ */
+static int test_strlcpy(void)
+{
+	char buf[4];
+	const struct {
+		const char *src;
+		size_t result;
+	} tests[] = {
+		{ "abc", 3 },
+		{ "abcdef", 6 },
+		{ "abcd", 4 },
+		{ "", 0 },
+		{ NULL, 0 }
+	};
+	int i;
+	printf("test: strlcpy\n");
+	for (i=0;tests[i].src;i++) {
+		if (strlcpy(buf, tests[i].src, sizeof(buf)) != tests[i].result) {
+			printf("failure: strlcpy [\ntest %d failed\n]\n", i);
+			return false;
+		}
+	}
+	printf("success: strlcpy\n");
+	return true;
+}
+
+static int test_strlcat(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_mktime(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_innetgr(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_initgroups(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_memmove(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_strdup(void)
+{
+	/* FIXME */
+	return true;
+}	
+
+static int test_setlinebuf(void)
+{
+	printf("test: setlinebuf\n");
+	setlinebuf(stdout);
+	printf("success: setlinebuf\n");
+	return true;
+}
+
+static int test_vsyslog(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_timegm(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_setenv(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_strndup(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_strnlen(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_waitpid(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_seteuid(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_setegid(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_asprintf(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_snprintf(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_vasprintf(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_vsnprintf(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_opendir(void)
+{
+	/* FIXME */
+	return true;
+}
+
+extern int test_readdir_os2_delete(void);
+
+static int test_readdir(void)
+{
+	printf("test: readdir\n");
+	if (test_readdir_os2_delete() != 0) {
+		return false;
+	}
+	printf("success: readdir\n");
+	return true;
+}
+
+static int test_telldir(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_seekdir(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_dlopen(void)
+{
+	/* FIXME: test dlopen, dlsym, dlclose, dlerror */
+	return true;
+}
+
+
+static int test_chroot(void)
+{
+	/* FIXME: chroot() */
+	return true;
+}
+
+static int test_bzero(void)
+{
+	/* FIXME: bzero */
+	return true;
+}
+
+static int test_strerror(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_errno(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_mkdtemp(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_mkstemp(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_pread(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_pwrite(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_getpass(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_inet_ntoa(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_strtoll(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_strtoull(void)
+{
+	/* FIXME */
+	return true;
+}
+
+/* 
+FIXME:
+Types:
+bool
+socklen_t
+uint_t
+uint{8,16,32,64}_t
+int{8,16,32,64}_t
+intptr_t
+
+Constants:
+PATH_NAME_MAX
+UINT{16,32,64}_MAX
+INT32_MAX
+*/
+
+static int test_va_copy(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_FUNCTION(void)
+{
+	/* FIXME: test __FUNCTION__ macro */
+	return true;
+}
+
+static int test_MIN(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_MAX(void)
+{
+	/* FIXME */
+	return true;
+}
+
+static int test_socketpair(void)
+{
+	int sock[2];
+	char buf[20];
+
+	printf("test: socketpair\n");
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == -1) {
+		printf("failure: socketpair [\n"
+			   "socketpair() failed\n"
+			   "]\n");
+		return false;
+	}
+
+	if (write(sock[1], "automatisch", 12) == -1) {
+		printf("failure: socketpair [\n"
+			   "write() failed: %s\n"
+			   "]\n", strerror(errno));
+		return false;
+	}
+
+	if (read(sock[0], buf, 12) == -1) {
+		printf("failure: socketpair [\n"
+			   "read() failed: %s\n"
+			   "]\n", strerror(errno));
+		return false;
+	}
+
+	if (strcmp(buf, "automatisch") != 0) {
+		printf("failure: socketpair [\n"
+			   "expected: automatisch, got: %s\n"
+			   "]\n", buf);
+		return false;
+	}
+
+	printf("success: socketpair\n");
+
+	return true;
+}
+
+struct torture_context;
+bool torture_local_replace(struct torture_context *ctx)
+{
+	bool ret = true;
+	ret &= test_ftruncate();
+	ret &= test_strlcpy();
+	ret &= test_strlcat();
+	ret &= test_mktime();
+	ret &= test_innetgr();
+	ret &= test_initgroups();
+	ret &= test_memmove();
+	ret &= test_strdup();
+	ret &= test_setlinebuf();
+	ret &= test_vsyslog();
+	ret &= test_timegm();
+	ret &= test_setenv();
+	ret &= test_strndup();
+	ret &= test_strnlen();
+	ret &= test_waitpid();
+	ret &= test_seteuid();
+	ret &= test_setegid();
+	ret &= test_asprintf();
+	ret &= test_snprintf();
+	ret &= test_vasprintf();
+	ret &= test_vsnprintf();
+	ret &= test_opendir();
+	ret &= test_readdir();
+	ret &= test_telldir();
+	ret &= test_seekdir();
+	ret &= test_dlopen();
+	ret &= test_chroot();
+	ret &= test_bzero();
+	ret &= test_strerror();
+	ret &= test_errno();
+	ret &= test_mkdtemp();
+	ret &= test_mkstemp();
+	ret &= test_pread();
+	ret &= test_pwrite();
+	ret &= test_getpass();
+	ret &= test_inet_ntoa();
+	ret &= test_strtoll();
+	ret &= test_strtoll();
+	ret &= test_strtoull();
+	ret &= test_va_copy();
+	ret &= test_FUNCTION();
+	ret &= test_MIN();
+	ret &= test_MAX();
+	ret &= test_socketpair();
+
+	return ret;
+}
+
+#if _SAMBA_BUILD_<4
+int main(void)
+{
+	bool ret = torture_local_replace(NULL);
+	if (ret) 
+		return 0;
+	return -1;
+}
+#endif

Added: branches/ctdb/squeeze-backports/lib/replace/timegm.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/timegm.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/timegm.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden). 
+ * All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in the 
+ *    documentation and/or other materials provided with the distribution. 
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE. 
+ */
+
+/*
+  adapted for Samba4 by Andrew Tridgell
+*/
+
+#include "replace.h"
+#include "system/time.h"
+
+static int is_leap(unsigned y)
+{
+	y += 1900;
+	return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
+}
+
+time_t rep_timegm(struct tm *tm)
+{
+	static const unsigned ndays[2][12] ={
+		{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+		{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
+	time_t res = 0;
+	unsigned i;
+
+	if (tm->tm_mon > 12 ||
+	    tm->tm_mon < 0 ||
+	    tm->tm_mday > 31 ||
+	    tm->tm_min > 60 ||
+	    tm->tm_sec > 60 ||
+	    tm->tm_hour > 24) {
+		/* invalid tm structure */
+		return 0;
+	}
+	
+	for (i = 70; i < tm->tm_year; ++i)
+		res += is_leap(i) ? 366 : 365;
+	
+	for (i = 0; i < tm->tm_mon; ++i)
+		res += ndays[is_leap(tm->tm_year)][i];
+	res += tm->tm_mday - 1;
+	res *= 24;
+	res += tm->tm_hour;
+	res *= 60;
+	res += tm->tm_min;
+	res *= 60;
+	res += tm->tm_sec;
+	return res;
+}

Added: branches/ctdb/squeeze-backports/lib/replace/timegm.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/timegm.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/timegm.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+AC_CHECK_FUNCS(timegm,[],[LIBREPLACEOBJ="${LIBREPLACEOBJ} timegm.o"])

Added: branches/ctdb/squeeze-backports/lib/replace/win32.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/win32.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/win32.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,20 @@
+AC_CHECK_HEADERS(direct.h windows.h winsock2.h ws2tcpip.h)
+
+#######################################
+# Check for mkdir mode
+AC_CACHE_CHECK( [whether mkdir supports mode], ac_cv_mkdir_has_mode,
+	AC_TRY_COMPILE([
+		#include <stdio.h>
+		#ifdef HAVE_DIRECT_H
+		#include <direct.h>
+		#endif],[
+			mkdir("foo",0777);
+			return 0;
+	],
+    ac_cv_mkdir_has_mode="yes",
+    ac_cv_mkdir_has_mode="no") )
+
+if test "$ac_cv_mkdir_has_mode" = "yes"
+then
+    AC_DEFINE(HAVE_MKDIR_MODE, 1, [Define if target mkdir supports mode option])
+fi

Added: branches/ctdb/squeeze-backports/lib/replace/win32_replace.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/replace/win32_replace.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/replace/win32_replace.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,159 @@
+#ifndef _WIN32_REPLACE_H
+#define _WIN32_REPLACE_H
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+/* Map BSD Socket errorcodes to the WSA errorcodes (if possible) */ 
+
+#define EAFNOSUPPORT	WSAEAFNOSUPPORT
+#define ECONNREFUSED    WSAECONNREFUSED 
+#define EINPROGRESS	WSAEINPROGRESS
+#define EMSGSIZE	WSAEMSGSIZE 
+#define ENOBUFS         WSAENOBUFS
+#define ENOTSOCK	WSAENOTSOCK
+#define ENETUNREACH	WSAENETUNREACH
+#define ENOPROTOOPT	WSAENOPROTOOPT
+#define ENOTCONN	WSAENOTCONN 
+#define ENOTSUP		134 
+
+/* We undefine the following constants due to conflicts with the w32api headers
+ * and the Windows Platform SDK/DDK.
+ */
+
+#undef interface
+
+#undef ERROR_INVALID_PARAMETER
+#undef ERROR_INSUFFICIENT_BUFFER
+#undef ERROR_INVALID_DATATYPE
+
+#undef FILE_GENERIC_READ
+#undef FILE_GENERIC_WRITE
+#undef FILE_GENERIC_EXECUTE
+#undef FILE_ATTRIBUTE_READONLY
+#undef FILE_ATTRIBUTE_HIDDEN
+#undef FILE_ATTRIBUTE_SYSTEM
+#undef FILE_ATTRIBUTE_DIRECTORY
+#undef FILE_ATTRIBUTE_ARCHIVE
+#undef FILE_ATTRIBUTE_DEVICE
+#undef FILE_ATTRIBUTE_NORMAL
+#undef FILE_ATTRIBUTE_TEMPORARY
+#undef FILE_ATTRIBUTE_REPARSE_POINT
+#undef FILE_ATTRIBUTE_COMPRESSED
+#undef FILE_ATTRIBUTE_OFFLINE
+#undef FILE_ATTRIBUTE_ENCRYPTED
+#undef FILE_FLAG_WRITE_THROUGH
+#undef FILE_FLAG_NO_BUFFERING
+#undef FILE_FLAG_RANDOM_ACCESS
+#undef FILE_FLAG_SEQUENTIAL_SCAN
+#undef FILE_FLAG_DELETE_ON_CLOSE
+#undef FILE_FLAG_BACKUP_SEMANTICS
+#undef FILE_FLAG_POSIX_SEMANTICS
+#undef FILE_TYPE_DISK
+#undef FILE_TYPE_UNKNOWN
+#undef FILE_CASE_SENSITIVE_SEARCH
+#undef FILE_CASE_PRESERVED_NAMES
+#undef FILE_UNICODE_ON_DISK
+#undef FILE_PERSISTENT_ACLS
+#undef FILE_FILE_COMPRESSION
+#undef FILE_VOLUME_QUOTAS
+#undef FILE_VOLUME_IS_COMPRESSED
+#undef FILE_NOTIFY_CHANGE_FILE_NAME
+#undef FILE_NOTIFY_CHANGE_DIR_NAME
+#undef FILE_NOTIFY_CHANGE_ATTRIBUTES
+#undef FILE_NOTIFY_CHANGE_SIZE
+#undef FILE_NOTIFY_CHANGE_LAST_WRITE
+#undef FILE_NOTIFY_CHANGE_LAST_ACCESS
+#undef FILE_NOTIFY_CHANGE_CREATION
+#undef FILE_NOTIFY_CHANGE_EA
+#undef FILE_NOTIFY_CHANGE_SECURITY
+#undef FILE_NOTIFY_CHANGE_STREAM_NAME
+#undef FILE_NOTIFY_CHANGE_STREAM_SIZE
+#undef FILE_NOTIFY_CHANGE_STREAM_WRITE
+#undef FILE_NOTIFY_CHANGE_NAME
+
+#undef PRINTER_ATTRIBUTE_QUEUED
+#undef PRINTER_ATTRIBUTE_DIRECT
+#undef PRINTER_ATTRIBUTE_DEFAULT
+#undef PRINTER_ATTRIBUTE_SHARED
+#undef PRINTER_ATTRIBUTE_NETWORK
+#undef PRINTER_ATTRIBUTE_HIDDEN
+#undef PRINTER_ATTRIBUTE_LOCAL
+#undef PRINTER_ATTRIBUTE_ENABLE_DEVQ
+#undef PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
+#undef PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST
+#undef PRINTER_ATTRIBUTE_WORK_OFFLINE
+#undef PRINTER_ATTRIBUTE_ENABLE_BIDI
+#undef PRINTER_ATTRIBUTE_RAW_ONLY
+#undef PRINTER_ATTRIBUTE_PUBLISHED
+#undef PRINTER_ENUM_DEFAULT
+#undef PRINTER_ENUM_LOCAL
+#undef PRINTER_ENUM_CONNECTIONS
+#undef PRINTER_ENUM_FAVORITE
+#undef PRINTER_ENUM_NAME
+#undef PRINTER_ENUM_REMOTE
+#undef PRINTER_ENUM_SHARED
+#undef PRINTER_ENUM_NETWORK
+#undef PRINTER_ENUM_EXPAND
+#undef PRINTER_ENUM_CONTAINER
+#undef PRINTER_ENUM_ICON1
+#undef PRINTER_ENUM_ICON2
+#undef PRINTER_ENUM_ICON3
+#undef PRINTER_ENUM_ICON4
+#undef PRINTER_ENUM_ICON5
+#undef PRINTER_ENUM_ICON6
+#undef PRINTER_ENUM_ICON7
+#undef PRINTER_ENUM_ICON8
+#undef PRINTER_STATUS_PAUSED
+#undef PRINTER_STATUS_ERROR
+#undef PRINTER_STATUS_PENDING_DELETION
+#undef PRINTER_STATUS_PAPER_JAM
+#undef PRINTER_STATUS_PAPER_OUT
+#undef PRINTER_STATUS_MANUAL_FEED
+#undef PRINTER_STATUS_PAPER_PROBLEM
+#undef PRINTER_STATUS_OFFLINE
+#undef PRINTER_STATUS_IO_ACTIVE
+#undef PRINTER_STATUS_BUSY
+#undef PRINTER_STATUS_PRINTING
+#undef PRINTER_STATUS_OUTPUT_BIN_FULL
+#undef PRINTER_STATUS_NOT_AVAILABLE
+#undef PRINTER_STATUS_WAITING
+#undef PRINTER_STATUS_PROCESSING
+#undef PRINTER_STATUS_INITIALIZING
+#undef PRINTER_STATUS_WARMING_UP
+#undef PRINTER_STATUS_TONER_LOW
+#undef PRINTER_STATUS_NO_TONER
+#undef PRINTER_STATUS_PAGE_PUNT
+#undef PRINTER_STATUS_USER_INTERVENTION
+#undef PRINTER_STATUS_OUT_OF_MEMORY
+#undef PRINTER_STATUS_DOOR_OPEN
+#undef PRINTER_STATUS_SERVER_UNKNOWN
+#undef PRINTER_STATUS_POWER_SAVE
+
+#undef DWORD
+#undef HKEY_CLASSES_ROOT
+#undef HKEY_CURRENT_USER
+#undef HKEY_LOCAL_MACHINE
+#undef HKEY_USERS
+#undef HKEY_PERFORMANCE_DATA
+#undef HKEY_CURRENT_CONFIG
+#undef HKEY_DYN_DATA
+#undef REG_DWORD
+#undef REG_QWORD
+
+#undef SERVICE_STATE_ALL
+
+#undef SE_GROUP_MANDATORY
+#undef SE_GROUP_ENABLED_BY_DEFAULT
+#undef SE_GROUP_ENABLED
+
+#endif /* _WIN32_REPLACE_H */

Added: branches/ctdb/squeeze-backports/lib/talloc/Makefile.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/Makefile.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/Makefile.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,72 @@
+#!gmake
+#
+prefix = @prefix@
+datarootdir = @datarootdir@
+exec_prefix = @exec_prefix@
+includedir = @includedir@
+libdir = @libdir@
+mandir = @mandir@
+VPATH = @srcdir@:@libreplacedir@
+srcdir = @srcdir@
+builddir = @builddir@
+XSLTPROC = @XSLTPROC@
+INSTALLCMD = @INSTALL@
+CC = @CC@
+CFLAGS = @CFLAGS@ -DHAVE_CONFIG_H= -I. -I at srcdir@
+EXTRA_TARGETS = @DOC_TARGET@
+
+.SUFFIXES: .c .o .3 .3.xml .xml .html
+
+LIBOBJ = @TALLOC_OBJ@ @LIBREPLACEOBJ@
+
+all: showflags libtalloc.a testsuite $(EXTRA_TARGETS)
+
+showflags:
+	@echo 'talloc will be compiled with flags:'
+	@echo '  CFLAGS = $(CFLAGS)'
+	@echo '  LIBS = $(LIBS)'
+
+testsuite: $(LIBOBJ) testsuite.o
+	$(CC) $(CFLAGS) -o testsuite testsuite.o $(LIBOBJ) $(LIBS)
+
+libtalloc.a: $(LIBOBJ)
+	ar -rv $@ $(LIBOBJ)
+	@-ranlib $@
+
+install: all 
+	${INSTALLCMD} -d $(DESTDIR)$(libdir)
+	${INSTALLCMD} -d $(DESTDIR)$(libdir)/pkgconfig
+	${INSTALLCMD} -m 755 libtalloc.a $(DESTDIR)$(libdir)
+	${INSTALLCMD} -d $(DESTDIR)${includedir}
+	${INSTALLCMD} -m 644 $(srcdir)/talloc.h $(DESTDIR)$(includedir)
+	${INSTALLCMD} -m 644 talloc.pc $(DESTDIR)$(libdir)/pkgconfig
+	if [ -f talloc.3 ];then ${INSTALLCMD} -d $(DESTDIR)$(mandir)/man3; fi
+	if [ -f talloc.3 ];then ${INSTALLCMD} -m 644 talloc.3 $(DESTDIR)$(mandir)/man3; fi
+
+doc: talloc.3 talloc.3.html
+
+.3.xml.3:
+	-test -z "$(XSLTPROC)" || $(XSLTPROC) --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+
+.xml.html:
+	-test -z "$(XSLTPROC)" || $(XSLTPROC) --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl $<
+
+clean:
+	rm -f *~ $(LIBOBJ) libtalloc.a testsuite testsuite.o *.gc?? talloc.3 talloc.3.html
+
+test: testsuite
+	./testsuite
+
+gcov:
+	gcov talloc.c
+
+installcheck: 
+	$(MAKE) test
+
+distclean: clean
+	rm -f *~ */*~
+	rm -f Makefile
+	rm -f config.log config.status config.h config.cache
+
+realdistclean: distclean
+	rm -f configure config.h.in

Added: branches/ctdb/squeeze-backports/lib/talloc/aclocal.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/aclocal.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/aclocal.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+m4_include(libreplace.m4)

Added: branches/ctdb/squeeze-backports/lib/talloc/autogen.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/autogen.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/autogen.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace"
+autoconf $IPATHS || exit 1
+autoheader $IPATHS || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/lib/talloc/autogen.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/talloc/config.guess
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/config.guess	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/config.guess	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1533 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-06-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd | genuineintel)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel at ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/lib/talloc/config.guess
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/talloc/config.h.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/config.h.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/config.h.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,702 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Whether strndup is broken */
+#undef BROKEN_STRNDUP
+
+/* Whether strnlen is broken */
+#undef BROKEN_STRNLEN
+
+/* Whether dlopen takes unsinged int flags */
+#undef DLOPEN_TAKES_UNSIGNED_FLAGS
+
+/* Define to 1 if you have the <acl/libacl.h> header file. */
+#undef HAVE_ACL_LIBACL_H
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Whether the bool type is available */
+#undef HAVE_BOOL
+
+/* Define to 1 if you have the `bzero' function. */
+#undef HAVE_BZERO
+
+/* Whether there is a C99 compliant vsnprintf */
+#undef HAVE_C99_VSNPRINTF
+
+/* Define to 1 if you have the `chroot' function. */
+#undef HAVE_CHROOT
+
+/* Define to 1 if you have the `chsize' function. */
+#undef HAVE_CHSIZE
+
+/* Whether or not we have comparison_fn_t */
+#undef HAVE_COMPARISON_FN_T
+
+/* Define to 1 if you have the <compat.h> header file. */
+#undef HAVE_COMPAT_H
+
+/* Define to 1 if you have the <ctype.h> header file. */
+#undef HAVE_CTYPE_H
+
+/* Define to 1 if you have the declaration of `asprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_ASPRINTF
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SNPRINTF
+
+/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VASPRINTF
+
+/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VSNPRINTF
+
+/* Define to 1 if you have the <direct.h> header file. */
+#undef HAVE_DIRECT_H
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dlclose' function. */
+#undef HAVE_DLCLOSE
+
+/* Define to 1 if you have the `dlerror' function. */
+#undef HAVE_DLERROR
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `dlopen' function. */
+#undef HAVE_DLOPEN
+
+/* Define to 1 if you have the `dlsym' function. */
+#undef HAVE_DLSYM
+
+/* Whether errno() is available */
+#undef HAVE_ERRNO_DECL
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <fnmatch.h> header file. */
+#undef HAVE_FNMATCH_H
+
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* Whether there is a __FUNCTION__ macro */
+#undef HAVE_FUNCTION_MACRO
+
+/* Define to 1 if you have the `getdents' function. */
+#undef HAVE_GETDENTS
+
+/* Define to 1 if you have the `getdirentries' function. */
+#undef HAVE_GETDIRENTRIES
+
+/* Define to 1 if you have the `getpgrp' function. */
+#undef HAVE_GETPGRP
+
+/* Define to 1 if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Whether the compiler supports immediate structures */
+#undef HAVE_IMMEDIATE_STRUCTURES
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the `memcpy' function. */
+#undef HAVE_MEMCPY
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define if target mkdir supports mode option */
+#undef HAVE_MKDIR_MODE
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#undef HAVE_MKDTEMP
+
+/* Define to 1 if you have the `mktime' function. */
+#undef HAVE_MKTIME
+
+/* Whether mmap works */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <mntent.h> header file. */
+#undef HAVE_MNTENT_H
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/in_ip.h> header file. */
+#undef HAVE_NETINET_IN_IP_H
+
+/* Define to 1 if you have the <netinet/in_systm.h> header file. */
+#undef HAVE_NETINET_IN_SYSTM_H
+
+/* Define to 1 if you have the <netinet/ip.h> header file. */
+#undef HAVE_NETINET_IP_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* usability of net/if.h */
+#undef HAVE_NET_IF_H
+
+/* Whether the open(2) accepts O_DIRECT */
+#undef HAVE_OPEN_O_DIRECT
+
+/* Define to 1 if you have the `pipe' function. */
+#undef HAVE_PIPE
+
+/* Define to 1 if you have the `pread' function. */
+#undef HAVE_PREAD
+
+/* Define to 1 if you have the `printf' function. */
+#undef HAVE_PRINTF
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define to 1 if you have the `pwrite' function. */
+#undef HAVE_PWRITE
+
+/* Define to 1 if you have the `rand' function. */
+#undef HAVE_RAND
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have the `rename' function. */
+#undef HAVE_RENAME
+
+/* Whether mkstemp is secure */
+#undef HAVE_SECURE_MKSTEMP
+
+/* Define to 1 if you have the `setbuffer' function. */
+#undef HAVE_SETBUFFER
+
+/* Define to 1 if you have the `setegid' function. */
+#undef HAVE_SETEGID
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Whether setenv() is available */
+#undef HAVE_SETENV_DECL
+
+/* Define to 1 if you have the `seteuid' function. */
+#undef HAVE_SETEUID
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#undef HAVE_SETJMP_H
+
+/* Define to 1 if you have the `setlinebuf' function. */
+#undef HAVE_SETLINEBUF
+
+/* Define to 1 if you have the `setresgid' function. */
+#undef HAVE_SETRESGID
+
+/* Whether setresgid() is available */
+#undef HAVE_SETRESGID_DECL
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Whether setresuid() is available */
+#undef HAVE_SETRESUID_DECL
+
+/* Define to 1 if you have the <shadow.h> header file. */
+#undef HAVE_SHADOW_H
+
+/* Whether we have the atomic_t variable type */
+#undef HAVE_SIG_ATOMIC_T_TYPE
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define to 1 if you have the `srand' function. */
+#undef HAVE_SRAND
+
+/* Define to 1 if you have the `srandom' function. */
+#undef HAVE_SRANDOM
+
+/* Define to 1 if you have the <standards.h> header file. */
+#undef HAVE_STANDARDS_H
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasestr' function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
+/* Define to 1 if you have the `strnlen' function. */
+#undef HAVE_STRNLEN
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define to 1 if you have the `strtoq' function. */
+#undef HAVE_STRTOQ
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define to 1 if you have the `strtouq' function. */
+#undef HAVE_STRTOUQ
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_RDEV
+
+/* Define to 1 if your `struct stat' has `st_rdev'. Deprecated, use
+   `HAVE_STRUCT_STAT_ST_RDEV' instead. */
+#undef HAVE_ST_RDEV
+
+/* Define to 1 if you have the `syslog' function. */
+#undef HAVE_SYSLOG
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/acl.h> header file. */
+#undef HAVE_SYS_ACL_H
+
+/* Define to 1 if you have the <sys/capability.h> header file. */
+#undef HAVE_SYS_CAPABILITY_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/fcntl.h> header file. */
+#undef HAVE_SYS_FCNTL_H
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/filsys.h> header file. */
+#undef HAVE_SYS_FILSYS_H
+
+/* Define to 1 if you have the <sys/fs/s5param.h> header file. */
+#undef HAVE_SYS_FS_S5PARAM_H
+
+/* Define to 1 if you have the <sys/id.h> header file. */
+#undef HAVE_SYS_ID_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#undef HAVE_SYS_IPC_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/mode.h> header file. */
+#undef HAVE_SYS_MODE_H
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#undef HAVE_SYS_MOUNT_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/priv.h> header file. */
+#undef HAVE_SYS_PRIV_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/security.h> header file. */
+#undef HAVE_SYS_SECURITY_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+#undef HAVE_SYS_SHM_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syslog.h> header file. */
+#undef HAVE_SYS_SYSLOG_H
+
+/* Define to 1 if you have the <sys/termio.h> header file. */
+#undef HAVE_SYS_TERMIO_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define to 1 if you have the `timegm' function. */
+#undef HAVE_TIMEGM
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define to 1 if you have the `usleep' function. */
+#undef HAVE_USLEEP
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if you have the <vararg.h> header file. */
+#undef HAVE_VARARG_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Whether va_copy() is available */
+#undef HAVE_VA_COPY
+
+/* Whether the C compiler understands volatile */
+#undef HAVE_VOLATILE
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `vsyslog' function. */
+#undef HAVE_VSYSLOG
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+#undef HAVE_WS2TCPIP_H
+
+/* Whether the _Bool type is available */
+#undef HAVE__Bool
+
+/* Whether the __VA_ARGS__ macro is available */
+#undef HAVE__VA_ARGS__MACRO
+
+/* Define to 1 if you have the `__strtoll' function. */
+#undef HAVE___STRTOLL
+
+/* Define to 1 if you have the `__strtoull' function. */
+#undef HAVE___STRTOULL
+
+/* Whether __va_copy() is available */
+#undef HAVE___VA_COPY
+
+/* Whether there is a __func__ macro */
+#undef HAVE_func_MACRO
+
+/* Whether MMAP is broken */
+#undef MMAP_BLACKLIST
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Whether getpass should be replaced */
+#undef REPLACE_GETPASS
+
+/* Whether inet_ntoa should be replaced */
+#undef REPLACE_INET_NTOA
+
+/* replace readdir */
+#undef REPLACE_READDIR
+
+/* replace readdir using getdents() */
+#undef REPLACE_READDIR_GETDENTS
+
+/* replace readdir using getdirentries() */
+#undef REPLACE_READDIR_GETDIRENTRIES
+
+/* Whether strptime should be replaced */
+#undef REPLACE_STRPTIME
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Whether seekdir returns an int */
+#undef SEEKDIR_RETURNS_INT
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `off_t', as computed by sizeof. */
+#undef SIZEOF_OFF_T
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of `ssize_t', as computed by sizeof. */
+#undef SIZEOF_SSIZE_T
+
+/* The size of `void *', as computed by sizeof. */
+#undef SIZEOF_VOID_P
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Whether telldir takes a const pointer */
+#undef TELLDIR_TAKES_CONST_DIR
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+#ifndef _OSF_SOURCE
+# define _OSF_SOURCE 1
+#endif
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Whether to enable POSIX support */
+#undef _POSIX_C_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Whether to enable System V compatibility */
+#undef _SYSV
+
+#ifndef _XOPEN_SOURCE_EXTENDED
+# define _XOPEN_SOURCE_EXTENDED 1
+#endif
+
+/* Enable extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef ino_t
+
+/* Define to `short' if <sys/types.h> does not define. */
+#undef int16_t
+
+/* Define to `long' if <sys/types.h> does not define. */
+#undef int32_t
+
+/* Define to `long long' if <sys/types.h> does not define. */
+#undef int64_t
+
+/* Define to `char' if <sys/types.h> does not define. */
+#undef int8_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef intptr_t
+
+/* Define to `off_t' if <sys/types.h> does not define. */
+#undef loff_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef mode_t
+
+/* Define to `long int' if <sys/types.h> does not define. */
+#undef off_t
+
+/* Define to `loff_t' if <sys/types.h> does not define. */
+#undef offset_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef ptrdiff_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Socket length type */
+#undef socklen_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to `unsigned short' if <sys/types.h> does not define. */
+#undef uint16_t
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#undef uint32_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef uint64_t
+
+/* Define to `unsigned char' if <sys/types.h> does not define. */
+#undef uint8_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef uint_t

Added: branches/ctdb/squeeze-backports/lib/talloc/config.mk
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/config.mk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/config.mk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+################################################
+# Start LIBRARY LIBTALLOC
+[LIBRARY::LIBTALLOC]
+VERSION = 0.0.1
+SO_VERSION = 0
+OBJ_FILES = talloc.o
+MANPAGE = talloc.3
+CFLAGS = -Ilib/talloc
+PUBLIC_HEADERS = talloc.h
+DESCRIPTION = A hierarchical pool based memory system with destructors
+#
+# End LIBRARY LIBTALLOC
+################################################

Added: branches/ctdb/squeeze-backports/lib/talloc/config.sub
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/config.sub	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/config.sub	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1693 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-06-11'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray)
+		os=
+		basic_machine=$1
+		;;
+        -bluegene*)
+	        os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/lib/talloc/config.sub
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/talloc/configure.ac
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/configure.ac	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/configure.ac	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,49 @@
+AC_PREREQ(2.50)
+AC_INIT(talloc, 2.0.3)
+AC_CONFIG_SRCDIR([talloc.c])
+AC_SUBST(datarootdir)
+AC_CONFIG_HEADER(config.h)
+
+TALLOC_VERSION=${PACKAGE_VERSION}
+TALLOC_VERSION_MAJOR=`echo ${PACKAGE_VERSION} | cut -d '.' -f1`
+TALLOC_VERSION_MINOR=`echo ${PACKAGE_VERSION} | cut -d '.' -f2`
+TALLOC_VERSION_RELEASE=`echo ${PACKAGE_VERSION} | cut -d '.' -f3`
+
+AC_SUBST(TALLOC_VERSION)
+AC_SUBST(TALLOC_VERSION_MAJOR)
+AC_SUBST(TALLOC_VERSION_MINOR)
+AC_SUBST(TALLOC_VERSION_RELEASE)
+
+AC_DEFINE_UNQUOTED(TALLOC_BUILD_VERSION_MAJOR,
+	[${TALLOC_VERSION_MAJOR}],
+	[talloc major version])
+AC_DEFINE_UNQUOTED(TALLOC_BUILD_VERSION_MINOR,
+	[${TALLOC_VERSION_MINOR}],
+	[talloc minor version])
+AC_DEFINE_UNQUOTED(TALLOC_BUILD_VERSION_RELEASE,
+	[${TALLOC_VERSION_RELEASE}],
+	[talloc release version])
+
+AC_LIBREPLACE_ALL_CHECKS
+
+AC_LD_PICFLAG
+AC_LD_SHLIBEXT
+AC_LD_SONAMEFLAG
+AC_LD_VERSIONSCRIPT
+AC_LIBREPLACE_SHLD
+AC_LIBREPLACE_SHLD_FLAGS
+
+m4_include(libtalloc.m4)
+m4_include(compat/talloc_compat1.m4)
+
+AC_PATH_PROG(XSLTPROC,xsltproc)
+DOC_TARGET=""
+if test -n "$XSLTPROC"; then
+	DOC_TARGET=doc
+fi
+AC_SUBST(DOC_TARGET)
+
+m4_include(build_macros.m4)
+BUILD_WITH_SHARED_BUILD_DIR
+
+AC_OUTPUT(Makefile talloc.pc)

Added: branches/ctdb/squeeze-backports/lib/talloc/doc/mainpage.dox
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/doc/mainpage.dox	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/doc/mainpage.dox	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,105 @@
+/**
+ * @mainpage
+ *
+ * talloc is a hierarchical, reference counted memory pool system with
+ * destructors. It is the core memory allocator used in Samba.
+ *
+ * @section talloc_download Download
+ *
+ * You can download the latest releases of talloc from the
+ * <a href="http://samba.org/ftp/talloc" target="_blank">talloc directory</a>
+ * on the samba public source archive.
+ *
+ * @section talloc_bugs Discussion and bug reports
+ *
+ * talloc does not currently have its own mailing list or bug tracking system.
+ * For now, please use the
+ * <a href="https://lists.samba.org/mailman/listinfo/samba-technical" target="_blank">samba-technical</a>
+ * mailing list, and the
+ * <a href="http://bugzilla.samba.org/" target="_blank">Samba bugzilla</a>
+ * bug tracking system.
+ *
+ * @section talloc_devel Development
+ * You can download the latest code either via git or rsync.
+ *
+ * To fetch via git see the following guide:
+ *
+ * <a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development" target="_blank">Using Git for Samba Development</a>
+ *
+ * Once you have cloned the tree switch to the master branch and cd into the
+ * lib/tevent directory.
+ *
+ * To fetch via rsync use this command:
+ *
+ * rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/talloc .
+ *
+ * @section talloc_preample Preamble
+ *
+ * talloc is a hierarchical, reference counted memory pool system with
+ * destructors.
+ *
+ * Perhaps the biggest difference from other memory pool systems is that there
+ * is no distinction between a "talloc context" and a "talloc pointer". Any
+ * pointer returned from talloc() is itself a valid talloc context. This means
+ * you can do this:
+ *
+ * @code
+ *      struct foo *X = talloc(mem_ctx, struct foo);
+ *      X->name = talloc_strdup(X, "foo");
+ * @endcode
+ *
+ * The pointer X->name would be a "child" of the talloc context "X" which is
+ * itself a child of mem_ctx. So if you do talloc_free(mem_ctx) then it is all
+ * destroyed, whereas if you do talloc_free(X) then just X and X->name are
+ * destroyed, and if you do talloc_free(X->name) then just the name element of
+ * X is destroyed.
+ *
+ * If you think about this, then what this effectively gives you is an n-ary
+ * tree, where you can free any part of the tree with talloc_free().
+ *
+ * If you find this confusing, then run the testsuite to watch talloc in
+ * action. You may also like to add your own tests to testsuite.c to clarify
+ * how some particular situation is handled.
+ *
+ * @section talloc_performance Performance
+ *
+ * All the additional features of talloc() over malloc() do come at a price. We
+ * have a simple performance test in Samba4 that measures talloc() versus
+ * malloc() performance, and it seems that talloc() is about 4% slower than
+ * malloc() on my x86 Debian Linux box. For Samba, the great reduction in code
+ * complexity that we get by using talloc makes this worthwhile, especially as
+ * the total overhead of talloc/malloc in Samba is already quite small.
+ *
+ * @section talloc_named Named blocks
+ *
+ * Every talloc chunk has a name that can be used as a dynamic type-checking
+ * system. If for some reason like a callback function you had to cast a
+ * "struct foo *" to a "void *" variable, later you can safely reassign the
+ * "void *" pointer to a "struct foo *" by using the talloc_get_type() or
+ * talloc_get_type_abort() macros.
+ *
+ * @code
+ *      struct foo *X = talloc_get_type_abort(ptr, struct foo);
+ * @endcode
+ *
+ * This will abort if "ptr" does not contain a pointer that has been created
+ * with talloc(mem_ctx, struct foo).
+ *
+ * @section talloc_threading Multi-threading
+ *
+ * talloc itself does not deal with threads. It is thread-safe (assuming the
+ * underlying "malloc" is), as long as each thread uses different memory
+ * contexts.
+ *
+ * If two threads uses the same context then they need to synchronize in order
+ * to be safe. In particular:
+ *
+ *   - when using talloc_enable_leak_report(), giving directly NULL as a parent
+ *     context implicitly refers to a hidden "null context" global variable, so
+ *     this should not be used in a multi-threaded environment without proper
+ *     synchronization.
+ *   - the context returned by talloc_autofree_context() is also global so
+ *     shouldn't be used by several threads simultaneously without
+ *     synchronization.
+ *
+ */

Added: branches/ctdb/squeeze-backports/lib/talloc/doxy.config
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/doxy.config	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/doxy.config	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1538 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = talloc
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 2.0
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = . doc
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.cpp \
+                         *.cc \
+                         *.c \
+                         *.h \
+                         *.hh \
+                         *.hpp \
+                         *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = */.git/* \
+                         */.svn/* \
+                         */cmake/* \
+                         */build/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# If the HTML_FOOTER_DESCRIPTION tag is set to YES, Doxygen will
+# add generated date, project name and doxygen version to HTML footer.
+
+HTML_FOOTER_DESCRIPTION= NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NONE
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = DOXYGEN PRINTF_ATTRIBUTE(x,y)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES

Added: branches/ctdb/squeeze-backports/lib/talloc/install-sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/install-sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/install-sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/lib/talloc/install-sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/talloc/libtalloc.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/libtalloc.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/libtalloc.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,38 @@
+dnl find the talloc sources. This is meant to work both for 
+dnl talloc standalone builds, and builds of packages using talloc
+tallocdir=""
+tallocpaths=". lib/talloc talloc ../talloc ../lib/talloc"
+for d in $tallocpaths; do
+	if test -f "$srcdir/$d/talloc.c"; then
+		tallocdir="$d"
+		AC_SUBST(tallocdir)
+		break;
+	fi
+done
+if test x"$tallocdir" = "x"; then
+   AC_MSG_ERROR([cannot find talloc source in $tallocpaths])
+fi
+TALLOC_OBJ="talloc.o"
+AC_SUBST(TALLOC_OBJ)
+
+TALLOC_CFLAGS="-I$srcdir/$tallocdir"
+AC_SUBST(TALLOC_CFLAGS)
+
+TALLOC_LIBS=""
+AC_SUBST(TALLOC_LIBS)
+
+AC_CHECK_SIZEOF(size_t,cross)
+AC_CHECK_SIZEOF(void *,cross)
+
+if test $ac_cv_sizeof_size_t -lt $ac_cv_sizeof_void_p; then
+	AC_WARN([size_t cannot represent the amount of used memory of a process])
+	AC_WARN([please report this to <samba-technical at samba.org>])
+	AC_WARN([sizeof(size_t) = $ac_cv_sizeof_size_t])
+	AC_WARN([sizeof(void *) = $ac_cv_sizeof_void_p])
+	AC_ERROR([sizeof(size_t) < sizeof(void *)])
+fi
+
+if test x"$VERSIONSCRIPT" != "x"; then
+    EXPORTSFILE=talloc.exports
+    AC_SUBST(EXPORTSFILE)
+fi

Added: branches/ctdb/squeeze-backports/lib/talloc/talloc.3
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/talloc.3	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/talloc.3	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,500 @@
+.\"     Title: talloc
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.71.0 <http://docbook.sf.net/>
+.\"      Date: 02/26/2007
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "TALLOC" "3" "02/26/2007" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+talloc \- hierarchical reference counted memory pool system with destructors
+.SH "SYNOPSIS"
+.sp
+.RS 3n
+.nf
+#include <talloc/talloc.h>
+.fi
+.RE
+.SH "DESCRIPTION"
+.PP
+If you are used to talloc from Samba3 then please read this carefully, as talloc has changed a lot.
+.PP
+The new talloc is a hierarchical, reference counted memory pool system with destructors. Quite a mouthful really, but not too bad once you get used to it.
+.PP
+Perhaps the biggest change from Samba3 is that there is no distinction between a "talloc context" and a "talloc pointer". Any pointer returned from talloc() is itself a valid talloc context. This means you can do this:
+.sp
+.RS 3n
+.nf
+    struct foo *X = talloc(mem_ctx, struct foo);
+    X\->name = talloc_strdup(X, "foo");
+    
+.fi
+.RE
+.PP
+and the pointer
+X\->name
+would be a "child" of the talloc context
+X
+which is itself a child of
+mem_ctx. So if you do
+talloc_free(mem_ctx)
+then it is all destroyed, whereas if you do
+talloc_free(X)
+then just
+X
+and
+X\->name
+are destroyed, and if you do
+talloc_free(X\->name)
+then just the name element of
+X
+is destroyed.
+.PP
+If you think about this, then what this effectively gives you is an n\-ary tree, where you can free any part of the tree with talloc_free().
+.PP
+If you find this confusing, then I suggest you run the
+testsuite
+program to watch talloc in action. You may also like to add your own tests to
+testsuite.c
+to clarify how some particular situation is handled.
+.SH "TALLOC API"
+.PP
+The following is a complete guide to the talloc API. Read it all at least twice.
+.SS "(type *)talloc(const void *ctx, type);"
+.PP
+The talloc() macro is the core of the talloc library. It takes a memory
+\fIctx\fR
+and a
+\fItype\fR, and returns a pointer to a new area of memory of the given
+\fItype\fR.
+.PP
+The returned pointer is itself a talloc context, so you can use it as the
+\fIctx\fR
+argument to more calls to talloc() if you wish.
+.PP
+The returned pointer is a "child" of the supplied context. This means that if you talloc_free() the
+\fIctx\fR
+then the new child disappears as well. Alternatively you can free just the child.
+.PP
+The
+\fIctx\fR
+argument to talloc() can be NULL, in which case a new top level context is created.
+.SS "void *talloc_size(const void *ctx, size_t size);"
+.PP
+The function talloc_size() should be used when you don't have a convenient type to pass to talloc(). Unlike talloc(), it is not type safe (as it returns a void *), so you are on your own for type checking.
+.SS "(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);"
+.PP
+The talloc_ptrtype() macro should be used when you have a pointer and want to allocate memory to point at with this pointer. When compiling with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size() and talloc_get_name() will return the current location in the source file. and not the type.
+.SS "int talloc_free(void *ptr);"
+.PP
+The talloc_free() function frees a piece of talloc memory, and all its children. You can call talloc_free() on any pointer returned by talloc().
+.PP
+The return value of talloc_free() indicates success or failure, with 0 returned for success and \-1 for failure. The only possible failure condition is if
+\fIptr\fR
+had a destructor attached to it and the destructor returned \-1. See
+\(lqtalloc_set_destructor()\(rq
+for details on destructors.
+.PP
+If this pointer has an additional parent when talloc_free() is called then the memory is not actually released, but instead the most recently established parent is destroyed. See
+\(lqtalloc_reference()\(rq
+for details on establishing additional parents.
+.PP
+For more control on which parent is removed, see
+\(lqtalloc_unlink()\(rq.
+.PP
+talloc_free() operates recursively on its children.
+.SS "void *talloc_reference(const void *ctx, const void *ptr);"
+.PP
+The talloc_reference() function makes
+\fIctx\fR
+an additional parent of
+\fIptr\fR.
+.PP
+The return value of talloc_reference() is always the original pointer
+\fIptr\fR, unless talloc ran out of memory in creating the reference in which case it will return NULL (each additional reference consumes around 48 bytes of memory on intel x86 platforms).
+.PP
+If
+\fIptr\fR
+is NULL, then the function is a no\-op, and simply returns NULL.
+.PP
+After creating a reference you can free it in one of the following ways:
+.PP
+.TP 3n
+\(bu
+you can talloc_free() any parent of the original pointer. That will reduce the number of parents of this pointer by 1, and will cause this pointer to be freed if it runs out of parents.
+.TP 3n
+\(bu
+you can talloc_free() the pointer itself. That will destroy the most recently established parent to the pointer and leave the pointer as a child of its current parent.
+.sp
+.RE
+.PP
+For more control on which parent to remove, see
+\(lqtalloc_unlink()\(rq.
+.SS "int talloc_unlink(const void *ctx, const void *ptr);"
+.PP
+The talloc_unlink() function removes a specific parent from
+\fIptr\fR. The
+\fIctx\fR
+passed must either be a context used in talloc_reference() with this pointer, or must be a direct parent of ptr.
+.PP
+Note that if the parent has already been removed using talloc_free() then this function will fail and will return \-1. Likewise, if
+\fIptr\fR
+is NULL, then the function will make no modifications and return \-1.
+.PP
+Usually you can just use talloc_free() instead of talloc_unlink(), but sometimes it is useful to have the additional control on which parent is removed.
+.SS "void talloc_set_destructor(const void *ptr, int (*destructor)(void *));"
+.PP
+The function talloc_set_destructor() sets the
+\fIdestructor\fR
+for the pointer
+\fIptr\fR. A
+\fIdestructor\fR
+is a function that is called when the memory used by a pointer is about to be released. The destructor receives
+\fIptr\fR
+as an argument, and should return 0 for success and \-1 for failure.
+.PP
+The
+\fIdestructor\fR
+can do anything it wants to, including freeing other pieces of memory. A common use for destructors is to clean up operating system resources (such as open file descriptors) contained in the structure the destructor is placed on.
+.PP
+You can only place one destructor on a pointer. If you need more than one destructor then you can create a zero\-length child of the pointer and place an additional destructor on that.
+.PP
+To remove a destructor call talloc_set_destructor() with NULL for the destructor.
+.PP
+If your destructor attempts to talloc_free() the pointer that it is the destructor for then talloc_free() will return \-1 and the free will be ignored. This would be a pointless operation anyway, as the destructor is only called when the memory is just about to go away.
+.SS "int talloc_increase_ref_count(const void *\fIptr\fR);"
+.PP
+The talloc_increase_ref_count(\fIptr\fR) function is exactly equivalent to:
+.sp
+.RS 3n
+.nf
+talloc_reference(NULL, ptr);
+.fi
+.RE
+.PP
+You can use either syntax, depending on which you think is clearer in your code.
+.PP
+It returns 0 on success and \-1 on failure.
+.SS "size_t talloc_reference_count(const void *\fIptr\fR);"
+.PP
+Return the number of references to the pointer.
+.SS "void talloc_set_name(const void *ptr, const char *fmt, ...);"
+.PP
+Each talloc pointer has a "name". The name is used principally for debugging purposes, although it is also possible to set and get the name on a pointer in as a way of "marking" pointers in your code.
+.PP
+The main use for names on pointer is for "talloc reports". See
+\(lqtalloc_report_depth_cb()\(rq,
+\(lqtalloc_report_depth_file()\(rq,
+\(lqtalloc_report()\(rq
+\(lqtalloc_report()\(rq
+and
+\(lqtalloc_report_full()\(rq
+for details. Also see
+\(lqtalloc_enable_leak_report()\(rq
+and
+\(lqtalloc_enable_leak_report_full()\(rq.
+.PP
+The talloc_set_name() function allocates memory as a child of the pointer. It is logically equivalent to:
+.sp
+.RS 3n
+.nf
+talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));
+.fi
+.RE
+.PP
+Note that multiple calls to talloc_set_name() will allocate more memory without releasing the name. All of the memory is released when the ptr is freed using talloc_free().
+.SS "void talloc_set_name_const(const void *\fIptr\fR, const char *\fIname\fR);"
+.PP
+The function talloc_set_name_const() is just like talloc_set_name(), but it takes a string constant, and is much faster. It is extensively used by the "auto naming" macros, such as talloc_p().
+.PP
+This function does not allocate any memory. It just copies the supplied pointer into the internal representation of the talloc ptr. This means you must not pass a
+\fIname\fR
+pointer to memory that will disappear before
+\fIptr\fR
+is freed with talloc_free().
+.SS "void *talloc_named(const void *\fIctx\fR, size_t \fIsize\fR, const char *\fIfmt\fR, ...);"
+.PP
+The talloc_named() function creates a named talloc pointer. It is equivalent to:
+.sp
+.RS 3n
+.nf
+ptr = talloc_size(ctx, size);
+talloc_set_name(ptr, fmt, ....);
+.fi
+.RE
+.SS "void *talloc_named_const(const void *\fIctx\fR, size_t \fIsize\fR, const char *\fIname\fR);"
+.PP
+This is equivalent to:
+.sp
+.RS 3n
+.nf
+ptr = talloc_size(ctx, size);
+talloc_set_name_const(ptr, name);
+.fi
+.RE
+.SS "const char *talloc_get_name(const void *\fIptr\fR);"
+.PP
+This returns the current name for the given talloc pointer,
+\fIptr\fR. See
+\(lqtalloc_set_name()\(rq
+for details.
+.SS "void *talloc_init(const char *\fIfmt\fR, ...);"
+.PP
+This function creates a zero length named talloc context as a top level context. It is equivalent to:
+.sp
+.RS 3n
+.nf
+talloc_named(NULL, 0, fmt, ...);
+.fi
+.RE
+.SS "void *talloc_new(void *\fIctx\fR);"
+.PP
+This is a utility macro that creates a new memory context hanging off an exiting context, automatically naming it "talloc_new: __location__" where __location__ is the source line it is called from. It is particularly useful for creating a new temporary working context.
+.SS "(\fItype\fR *)talloc_realloc(const void *\fIctx\fR, void *\fIptr\fR, \fItype\fR, \fIcount\fR);"
+.PP
+The talloc_realloc() macro changes the size of a talloc pointer. It has the following equivalences:
+.sp
+.RS 3n
+.nf
+talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
+talloc_realloc(ctx, ptr, type, 0)  ==> talloc_free(ptr);
+.fi
+.RE
+.PP
+The
+\fIctx\fR
+argument is only used if
+\fIptr\fR
+is not NULL, otherwise it is ignored.
+.PP
+talloc_realloc() returns the new pointer, or NULL on failure. The call will fail either due to a lack of memory, or because the pointer has more than one parent (see
+\(lqtalloc_reference()\(rq).
+.SS "void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);"
+.PP
+the talloc_realloc_size() function is useful when the type is not known so the type\-safe talloc_realloc() cannot be used.
+.SS "TYPE *talloc_steal(const void *\fInew_ctx\fR, const TYPE *\fIptr\fR);"
+.PP
+The talloc_steal() function changes the parent context of a talloc pointer. It is typically used when the context that the pointer is currently a child of is going to be freed and you wish to keep the memory for a longer time.
+.PP
+The talloc_steal() function returns the pointer that you pass it. It does not have any failure modes.
+.PP
+NOTE: It is possible to produce loops in the parent/child relationship if you are not careful with talloc_steal(). No guarantees are provided as to your sanity or the safety of your data if you do this.
+.SS "TYPE *talloc_move(const void *\fInew_ctx\fR, TYPE **\fIptr\fR);"
+.PP
+The talloc_move() function is a wrapper around talloc_steal() which zeros the source pointer after the move. This avoids a potential source of bugs where a programmer leaves a pointer in two structures, and uses the pointer from the old structure after it has been moved to a new one.
+.SS "size_t talloc_total_size(const void *\fIptr\fR);"
+.PP
+The talloc_total_size() function returns the total size in bytes used by this pointer and all child pointers. Mostly useful for debugging.
+.PP
+Passing NULL is allowed, but it will only give a meaningful result if talloc_enable_leak_report() or talloc_enable_leak_report_full() has been called.
+.SS "size_t talloc_total_blocks(const void *\fIptr\fR);"
+.PP
+The talloc_total_blocks() function returns the total memory block count used by this pointer and all child pointers. Mostly useful for debugging.
+.PP
+Passing NULL is allowed, but it will only give a meaningful result if talloc_enable_leak_report() or talloc_enable_leak_report_full() has been called.
+.SS "void talloc_report(const void *ptr, FILE *f);"
+.PP
+The talloc_report() function prints a summary report of all memory used by
+\fIptr\fR. One line of report is printed for each immediate child of ptr, showing the total memory and number of blocks used by that child.
+.PP
+You can pass NULL for the pointer, in which case a report is printed for the top level memory context, but only if talloc_enable_leak_report() or talloc_enable_leak_report_full() has been called.
+.SS "void talloc_report_full(const void *\fIptr\fR, FILE *\fIf\fR);"
+.PP
+This provides a more detailed report than talloc_report(). It will recursively print the entire tree of memory referenced by the pointer. References in the tree are shown by giving the name of the pointer that is referenced.
+.PP
+You can pass NULL for the pointer, in which case a report is printed for the top level memory context, but only if talloc_enable_leak_report() or talloc_enable_leak_report_full() has been called.
+.SS ""
+.HP 28
+.BI "void talloc_report_depth_cb(" "const\ void\ *ptr" ", " "int\ depth" ", " "int\ max_depth" ", " "void\ (*callback)(const\ void\ *ptr,\ int\ depth,\ int\ max_depth,\ int\ is_ref,\ void\ *priv)" ", " "void\ *priv" ");"
+.PP
+This provides a more flexible reports than talloc_report(). It will recursively call the callback for the entire tree of memory referenced by the pointer. References in the tree are passed with
+\fIis_ref = 1\fR
+and the pointer that is referenced.
+.PP
+You can pass NULL for the pointer, in which case a report is printed for the top level memory context, but only if talloc_enable_leak_report() or talloc_enable_leak_report_full() has been called.
+.PP
+The recursion is stopped when depth >= max_depth. max_depth = \-1 means only stop at leaf nodes.
+.SS ""
+.HP 30
+.BI "void talloc_report_depth_file(" "const\ void\ *ptr" ", " "int\ depth" ", " "int\ max_depth" ", " "FILE\ *f" ");"
+.PP
+This provides a more flexible reports than talloc_report(). It will let you specify the depth and max_depth.
+.SS "void talloc_enable_leak_report(void);"
+.PP
+This enables calling of talloc_report(NULL, stderr) when the program exits. In Samba4 this is enabled by using the \-\-leak\-report command line option.
+.PP
+For it to be useful, this function must be called before any other talloc function as it establishes a "null context" that acts as the top of the tree. If you don't call this function first then passing NULL to talloc_report() or talloc_report_full() won't give you the full tree printout.
+.PP
+Here is a typical talloc report:
+.sp
+.RS 3n
+.nf
+talloc report on 'null_context' (total 267 bytes in 15 blocks)
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+iconv(UTF8,CP850)              contains   42 bytes in   2 blocks
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+iconv(CP850,UTF8)              contains   42 bytes in   2 blocks
+iconv(UTF8,UTF\-16LE)           contains   45 bytes in   2 blocks
+iconv(UTF\-16LE,UTF8)           contains   45 bytes in   2 blocks
+      
+.fi
+.RE
+.SS "void talloc_enable_leak_report_full(void);"
+.PP
+This enables calling of talloc_report_full(NULL, stderr) when the program exits. In Samba4 this is enabled by using the \-\-leak\-report\-full command line option.
+.PP
+For it to be useful, this function must be called before any other talloc function as it establishes a "null context" that acts as the top of the tree. If you don't call this function first then passing NULL to talloc_report() or talloc_report_full() won't give you the full tree printout.
+.PP
+Here is a typical full report:
+.sp
+.RS 3n
+.nf
+full talloc report on 'root' (total 18 bytes in 8 blocks)
+p1               contains     18 bytes in   7 blocks (ref 0)
+    r1               contains     13 bytes in   2 blocks (ref 0)
+        reference to: p2
+    p2               contains      1 bytes in   1 blocks (ref 1)
+    x3               contains      1 bytes in   1 blocks (ref 0)
+    x2               contains      1 bytes in   1 blocks (ref 0)
+    x1               contains      1 bytes in   1 blocks (ref 0)
+      
+.fi
+.RE
+.SS "(\fItype\fR *)talloc_zero(const void *\fIctx\fR, \fItype\fR);"
+.PP
+The talloc_zero() macro is equivalent to:
+.sp
+.RS 3n
+.nf
+ptr = talloc(ctx, type);
+if (ptr) memset(ptr, 0, sizeof(type));
+.fi
+.RE
+.SS "void *talloc_zero_size(const void *\fIctx\fR, size_t \fIsize\fR)"
+.PP
+The talloc_zero_size() function is useful when you don't have a known type.
+.SS "void *talloc_memdup(const void *\fIctx\fR, const void *\fIp\fR, size_t size);"
+.PP
+The talloc_memdup() function is equivalent to:
+.sp
+.RS 3n
+.nf
+ptr = talloc_size(ctx, size);
+if (ptr) memcpy(ptr, p, size);
+.fi
+.RE
+.SS "char *talloc_strdup(const void *\fIctx\fR, const char *\fIp\fR);"
+.PP
+The talloc_strdup() function is equivalent to:
+.sp
+.RS 3n
+.nf
+ptr = talloc_size(ctx, strlen(p)+1);
+if (ptr) memcpy(ptr, p, strlen(p)+1);
+.fi
+.RE
+.PP
+This function sets the name of the new pointer to the passed string. This is equivalent to:
+.sp
+.RS 3n
+.nf
+talloc_set_name_const(ptr, ptr)
+.fi
+.RE
+.SS "char *talloc_strndup(const void *\fIt\fR, const char *\fIp\fR, size_t \fIn\fR);"
+.PP
+The talloc_strndup() function is the talloc equivalent of the C library function strndup(3).
+.PP
+This function sets the name of the new pointer to the passed string. This is equivalent to:
+.sp
+.RS 3n
+.nf
+talloc_set_name_const(ptr, ptr)
+.fi
+.RE
+.SS "char *talloc_vasprintf(const void *\fIt\fR, const char *\fIfmt\fR, va_list \fIap\fR);"
+.PP
+The talloc_vasprintf() function is the talloc equivalent of the C library function vasprintf(3).
+.SS "char *talloc_asprintf(const void *\fIt\fR, const char *\fIfmt\fR, ...);"
+.PP
+The talloc_asprintf() function is the talloc equivalent of the C library function asprintf(3).
+.PP
+This function sets the name of the new pointer to the passed string. This is equivalent to:
+.sp
+.RS 3n
+.nf
+talloc_set_name_const(ptr, ptr)
+.fi
+.RE
+.SS "char *talloc_asprintf_append(char *s, const char *fmt, ...);"
+.PP
+The talloc_asprintf_append() function appends the given formatted string to the given string.
+.SS "(type *)talloc_array(const void *ctx, type, uint_t count);"
+.PP
+The talloc_array() macro is equivalent to:
+.sp
+.RS 3n
+.nf
+(type *)talloc_size(ctx, sizeof(type) * count);
+.fi
+.RE
+.PP
+except that it provides integer overflow protection for the multiply, returning NULL if the multiply overflows.
+.SS "void *talloc_array_size(const void *ctx, size_t size, uint_t count);"
+.PP
+The talloc_array_size() function is useful when the type is not known. It operates in the same way as talloc_array(), but takes a size instead of a type.
+.SS "(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, uint_t count);"
+.PP
+The talloc_ptrtype() macro should be used when you have a pointer to an array and want to allocate memory of an array to point at with this pointer. When compiling with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size() and talloc_get_name() will return the current location in the source file. and not the type.
+.SS "void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size)"
+.PP
+This is a non\-macro version of talloc_realloc(), which is useful as libraries sometimes want a realloc function pointer. A realloc(3) implementation encapsulates the functionality of malloc(3), free(3) and realloc(3) in one call, which is why it is useful to be able to pass around a single function pointer.
+.SS "void *talloc_autofree_context(void);"
+.PP
+This is a handy utility function that returns a talloc context which will be automatically freed on program exit. This can be used to reduce the noise in memory leak reports.
+.SS "void *talloc_check_name(const void *ptr, const char *name);"
+.PP
+This function checks if a pointer has the specified
+\fIname\fR. If it does then the pointer is returned. It it doesn't then NULL is returned.
+.SS "(type *)talloc_get_type(const void *ptr, type);"
+.PP
+This macro allows you to do type checking on talloc pointers. It is particularly useful for void* private pointers. It is equivalent to this:
+.sp
+.RS 3n
+.nf
+(type *)talloc_check_name(ptr, #type)
+.fi
+.RE
+.SS "talloc_set_type(const void *ptr, type);"
+.PP
+This macro allows you to force the name of a pointer to be a particular
+\fItype\fR. This can be used in conjunction with talloc_get_type() to do type checking on void* pointers.
+.PP
+It is equivalent to this:
+.sp
+.RS 3n
+.nf
+talloc_set_name_const(ptr, #type)
+.fi
+.RE
+.SH "PERFORMANCE"
+.PP
+All the additional features of talloc(3) over malloc(3) do come at a price. We have a simple performance test in Samba4 that measures talloc() versus malloc() performance, and it seems that talloc() is about 10% slower than malloc() on my x86 Debian Linux box. For Samba, the great reduction in code complexity that we get by using talloc makes this worthwhile, especially as the total overhead of talloc/malloc in Samba is already quite small.
+.SH "SEE ALSO"
+.PP
+malloc(3), strndup(3), vasprintf(3), asprintf(3),
+\fI\%http://talloc.samba.org/\fR
+.SH "COPYRIGHT/LICENSE"
+.PP
+Copyright (C) Andrew Tridgell 2004
+.PP
+This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
+.PP
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+.PP
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Added: branches/ctdb/squeeze-backports/lib/talloc/talloc.3.html
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/talloc.3.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/talloc.3.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,433 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>talloc</title><meta name="generator" content="DocBook XSL Stylesheets V1.71.0"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en"><a name="id2478730"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>talloc — hierarchical reference counted memory pool system with destructors</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><pre class="synopsis">#include <talloc/talloc.h></pre></div><div class="refsect1" lang="en"><a name="id2517362"></a><h2>DESCRIPTION</h2><p>
+      If you are used to talloc from Samba3 then please read this
+      carefully, as talloc has changed a lot.
+    </p><p>
+      The new talloc is a hierarchical, reference counted memory pool
+      system with destructors.	Quite a mouthful really, but not too bad
+      once you get used to it.
+    </p><p>
+      Perhaps the biggest change from Samba3 is that there is no
+      distinction between a "talloc context" and a "talloc pointer".  Any
+      pointer returned from talloc() is itself a valid talloc context. 
+      This means you can do this:
+    </p><pre class="programlisting">
+    struct foo *X = talloc(mem_ctx, struct foo);
+    X->name = talloc_strdup(X, "foo");
+    </pre><p>
+      and the pointer <code class="literal">X->name</code>
+      would be a "child" of the talloc context <code class="literal">X</code> which is itself a child of
+      <code class="literal">mem_ctx</code>.  So if you do
+      <code class="literal">talloc_free(mem_ctx)</code> then
+      it is all destroyed, whereas if you do <code class="literal">talloc_free(X)</code> then just <code class="literal">X</code> and <code class="literal">X->name</code> are destroyed, and if
+      you do <code class="literal">talloc_free(X->name)</code> then just
+      the name element of <code class="literal">X</code> is
+      destroyed.
+    </p><p>
+      If you think about this, then what this effectively gives you is an
+      n-ary tree, where you can free any part of the tree with
+      talloc_free().
+    </p><p>
+      If you find this confusing, then I suggest you run the <code class="literal">testsuite</code> program to watch talloc
+      in action.  You may also like to add your own tests to <code class="literal">testsuite.c</code> to clarify how some
+      particular situation is handled.
+    </p></div><div class="refsect1" lang="en"><a name="id2478829"></a><h2>TALLOC API</h2><p>
+      The following is a complete guide to the talloc API. Read it all at
+      least twice.
+    </p><div class="refsect2" lang="en"><a name="id2478838"></a><h3>(type *)talloc(const void *ctx, type);</h3><p>
+	  The talloc() macro is the core of the talloc library.  It takes a
+	  memory <span class="italic">ctx</span> and a <span class="italic">type</span>, and returns a pointer to a new
+	  area of memory of the given <span class="italic">type</span>.
+        </p><p>
+	  The returned pointer is itself a talloc context, so you can use
+	  it as the <span class="italic">ctx</span> argument to more
+	  calls to talloc() if you wish.
+        </p><p>
+	  The returned pointer is a "child" of the supplied context.  This
+	  means that if you talloc_free() the <span class="italic">ctx</span> then the new child disappears as
+	  well.  Alternatively you can free just the child.
+        </p><p>
+	  The <span class="italic">ctx</span> argument to talloc()
+	  can be NULL, in which case a new top level context is created.
+        </p></div><div class="refsect2" lang="en"><a name="id2478902"></a><h3>void *talloc_size(const void *ctx, size_t size);</h3><p>
+	  The function talloc_size() should be used when you don't have a
+	  convenient type to pass to talloc().	Unlike talloc(), it is not
+	  type safe (as it returns a void *), so you are on your own for
+	  type checking.
+        </p></div><div class="refsect2" lang="en"><a name="id2478915"></a><h3>(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);</h3><p>
+	  The talloc_ptrtype() macro should be used when you have a pointer and
+	  want to allocate memory to point at with this pointer. When compiling
+	  with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+	  and talloc_get_name() will return the current location in the source file.
+	  and not the type.
+        </p></div><div class="refsect2" lang="en"><a name="id2478930"></a><h3>int talloc_free(void *ptr);</h3><p>
+	  The talloc_free() function frees a piece of talloc memory, and
+	  all its children.  You can call talloc_free() on any pointer
+	  returned by talloc().
+        </p><p>
+	  The return value of talloc_free() indicates success or failure,
+	  with 0 returned for success and -1 for failure.  The only
+	  possible failure condition is if <span class="italic">ptr</span> had a destructor attached to it and
+	  the destructor returned -1.  See <a href="#talloc_set_destructor" title="void talloc_set_destructor(const void *ptr, int (*destructor)(void *));">“<span class="quote">talloc_set_destructor()</span>”</a>
+	  for details on destructors.
+        </p><p>
+	  If this pointer has an additional parent when talloc_free() is
+	  called then the memory is not actually released, but instead the
+	  most recently established parent is destroyed.  See <a href="#talloc_reference" title="void *talloc_reference(const void *ctx, const void *ptr);">“<span class="quote">talloc_reference()</span>”</a>
+	  for details on establishing additional parents.
+        </p><p>
+	  For more control on which parent is removed, see <a href="#talloc_unlink" title="int talloc_unlink(const void *ctx, const void *ptr);">“<span class="quote">talloc_unlink()</span>”</a>.
+        </p><p>
+	  talloc_free() operates recursively on its children.
+        </p></div><div class="refsect2" lang="en"><a name="talloc_reference"></a><h3>void *talloc_reference(const void *ctx, const void *ptr);</h3><p>
+	  The talloc_reference() function makes <span class="italic">ctx</span> an additional parent of <span class="italic">ptr</span>.
+        </p><p>
+	  The return value of talloc_reference() is always the original
+	  pointer <span class="italic">ptr</span>, unless talloc ran
+	  out of memory in creating the reference in which case it will
+	  return NULL (each additional reference consumes around 48 bytes
+	  of memory on intel x86 platforms).
+        </p><p>
+	  If <span class="italic">ptr</span> is NULL, then the
+	  function is a no-op, and simply returns NULL.
+        </p><p>
+	  After creating a reference you can free it in one of the
+	  following ways:
+        </p><p>
+        </p><div class="itemizedlist"><ul type="disc"><li><p>
+	      you can talloc_free() any parent of the original pointer. 
+	      That will reduce the number of parents of this pointer by 1,
+	      and will cause this pointer to be freed if it runs out of
+	      parents.
+            </p></li><li><p>
+	      you can talloc_free() the pointer itself.  That will destroy
+	      the most recently established parent to the pointer and leave
+	      the pointer as a child of its current parent.
+            </p></li></ul></div><p>
+      </p><p>
+	For more control on which parent to remove, see <a href="#talloc_unlink" title="int talloc_unlink(const void *ctx, const void *ptr);">“<span class="quote">talloc_unlink()</span>”</a>.
+      </p></div><div class="refsect2" lang="en"><a name="talloc_unlink"></a><h3>int talloc_unlink(const void *ctx, const void *ptr);</h3><p>
+	  The talloc_unlink() function removes a specific parent from
+	  <span class="italic">ptr</span>. The <span class="italic">ctx</span> passed must either be a context used
+	  in talloc_reference() with this pointer, or must be a direct
+	  parent of ptr.
+        </p><p>
+	  Note that if the parent has already been removed using
+	  talloc_free() then this function will fail and will return -1. 
+	  Likewise, if <span class="italic">ptr</span> is NULL, then
+	  the function will make no modifications and return -1.
+        </p><p>
+	  Usually you can just use talloc_free() instead of
+	  talloc_unlink(), but sometimes it is useful to have the
+	  additional control on which parent is removed.
+        </p></div><div class="refsect2" lang="en"><a name="talloc_set_destructor"></a><h3>void talloc_set_destructor(const void *ptr, int (*destructor)(void *));</h3><p>
+	  The function talloc_set_destructor() sets the <span class="italic">destructor</span> for the pointer <span class="italic">ptr</span>.  A <span class="italic">destructor</span> is a function that is called
+	  when the memory used by a pointer is about to be released.  The
+	  destructor receives <span class="italic">ptr</span> as an
+	  argument, and should return 0 for success and -1 for failure.
+        </p><p>
+	  The <span class="italic">destructor</span> can do anything
+	  it wants to, including freeing other pieces of memory.  A common
+	  use for destructors is to clean up operating system resources
+	  (such as open file descriptors) contained in the structure the
+	  destructor is placed on.
+        </p><p>
+	  You can only place one destructor on a pointer.  If you need more
+	  than one destructor then you can create a zero-length child of
+	  the pointer and place an additional destructor on that.
+        </p><p>
+	  To remove a destructor call talloc_set_destructor() with NULL for
+	  the destructor.
+        </p><p>
+	  If your destructor attempts to talloc_free() the pointer that it
+	  is the destructor for then talloc_free() will return -1 and the
+	  free will be ignored.  This would be a pointless operation
+	  anyway, as the destructor is only called when the memory is just
+	  about to go away.
+        </p></div><div class="refsect2" lang="en"><a name="id2479748"></a><h3>int talloc_increase_ref_count(const void *<span class="italic">ptr</span>);</h3><p>
+	  The talloc_increase_ref_count(<span class="italic">ptr</span>) function is exactly equivalent to:
+        </p><pre class="programlisting">talloc_reference(NULL, ptr);</pre><p>
+	  You can use either syntax, depending on which you think is
+	  clearer in your code.
+        </p><p>
+	  It returns 0 on success and -1 on failure.
+        </p></div><div class="refsect2" lang="en"><a name="id2479785"></a><h3>size_t talloc_reference_count(const void *<span class="italic">ptr</span>);</h3><p>
+	  Return the number of references to the pointer.
+        </p></div><div class="refsect2" lang="en"><a name="talloc_set_name"></a><h3>void talloc_set_name(const void *ptr, const char *fmt, ...);</h3><p>
+	  Each talloc pointer has a "name".  The name is used principally
+	  for debugging purposes, although it is also possible to set and
+	  get the name on a pointer in as a way of "marking" pointers in
+	  your code.
+        </p><p>
+	  The main use for names on pointer is for "talloc reports".  See
+	  <a href="#talloc_report" title="void talloc_report(const void *ptr, FILE *f);">“<span class="quote">talloc_report_depth_cb()</span>”</a>,
+	  <a href="#talloc_report" title="void talloc_report(const void *ptr, FILE *f);">“<span class="quote">talloc_report_depth_file()</span>”</a>,
+	  <a href="#talloc_report" title="void talloc_report(const void *ptr, FILE *f);">“<span class="quote">talloc_report()</span>”</a>
+	  <a href="#talloc_report" title="void talloc_report(const void *ptr, FILE *f);">“<span class="quote">talloc_report()</span>”</a>
+	  and <a href="#talloc_report_full" title="void talloc_report_full(const void *ptr, FILE *f);">“<span class="quote">talloc_report_full()</span>”</a>
+	  for details.	Also see <a href="#talloc_enable_leak_report" title="void talloc_enable_leak_report(void);">“<span class="quote">talloc_enable_leak_report()</span>”</a>
+	  and <a href="#talloc_enable_leak_report_full" title="void talloc_enable_leak_report_full(void);">“<span class="quote">talloc_enable_leak_report_full()</span>”</a>.
+        </p><p>
+	  The talloc_set_name() function allocates memory as a child of the
+	  pointer.  It is logically equivalent to:
+        </p><pre class="programlisting">talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));</pre><p>
+	  Note that multiple calls to talloc_set_name() will allocate more
+	  memory without releasing the name.  All of the memory is released
+	  when the ptr is freed using talloc_free().
+        </p></div><div class="refsect2" lang="en"><a name="id2479904"></a><h3>void talloc_set_name_const(const void *<span class="italic">ptr</span>, const char *<span class="italic">name</span>);</h3><p>
+	  The function talloc_set_name_const() is just like
+	  talloc_set_name(), but it takes a string constant, and is much
+	  faster.  It is extensively used by the "auto naming" macros, such
+	  as talloc_p().
+        </p><p>
+	  This function does not allocate any memory.  It just copies the
+	  supplied pointer into the internal representation of the talloc
+	  ptr. This means you must not pass a <span class="italic">name</span> pointer to memory that will
+	  disappear before <span class="italic">ptr</span> is freed
+	  with talloc_free().
+        </p></div><div class="refsect2" lang="en"><a name="id2479948"></a><h3>void *talloc_named(const void *<span class="italic">ctx</span>, size_t <span class="italic">size</span>, const char *<span class="italic">fmt</span>, ...);</h3><p>
+	  The talloc_named() function creates a named talloc pointer.  It
+	  is equivalent to:
+        </p><pre class="programlisting">ptr = talloc_size(ctx, size);
+talloc_set_name(ptr, fmt, ....);</pre></div><div class="refsect2" lang="en"><a name="id2479983"></a><h3>void *talloc_named_const(const void *<span class="italic">ctx</span>, size_t <span class="italic">size</span>, const char *<span class="italic">name</span>);</h3><p>
+	  This is equivalent to:
+        </p><pre class="programlisting">ptr = talloc_size(ctx, size);
+talloc_set_name_const(ptr, name);</pre></div><div class="refsect2" lang="en"><a name="id2480018"></a><h3>const char *talloc_get_name(const void *<span class="italic">ptr</span>);</h3><p>
+	  This returns the current name for the given talloc pointer,
+	  <span class="italic">ptr</span>. See <a href="#talloc_set_name" title="void talloc_set_name(const void *ptr, const char *fmt, ...);">“<span class="quote">talloc_set_name()</span>”</a>
+	  for details.
+        </p></div><div class="refsect2" lang="en"><a name="id2480049"></a><h3>void *talloc_init(const char *<span class="italic">fmt</span>, ...);</h3><p>
+	  This function creates a zero length named talloc context as a top
+	  level context.  It is equivalent to:
+        </p><pre class="programlisting">talloc_named(NULL, 0, fmt, ...);</pre></div><div class="refsect2" lang="en"><a name="id2480072"></a><h3>void *talloc_new(void *<span class="italic">ctx</span>);</h3><p>
+	  This is a utility macro that creates a new memory context hanging
+	  off an exiting context, automatically naming it "talloc_new:
+	  __location__" where __location__ is the source line it is called
+	  from.  It is particularly useful for creating a new temporary
+	  working context.
+        </p></div><div class="refsect2" lang="en"><a name="id2526763"></a><h3>(<span class="italic">type</span> *)talloc_realloc(const void *<span class="italic">ctx</span>, void *<span class="italic">ptr</span>, <span class="italic">type</span>, <span class="italic">count</span>);</h3><p>
+	  The talloc_realloc() macro changes the size of a talloc pointer. 
+	  It has the following equivalences:
+        </p><pre class="programlisting">talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
+talloc_realloc(ctx, ptr, type, 0)  ==> talloc_free(ptr);</pre><p>
+	  The <span class="italic">ctx</span> argument is only used
+	  if <span class="italic">ptr</span> is not NULL, otherwise
+	  it is ignored.
+        </p><p>
+	  talloc_realloc() returns the new pointer, or NULL on failure. 
+	  The call will fail either due to a lack of memory, or because the
+	  pointer has more than one parent (see <a href="#talloc_reference" title="void *talloc_reference(const void *ctx, const void *ptr);">“<span class="quote">talloc_reference()</span>”</a>).
+        </p></div><div class="refsect2" lang="en"><a name="id2526841"></a><h3>void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);</h3><p>
+	  the talloc_realloc_size() function is useful when the type is not
+	  known so the type-safe talloc_realloc() cannot be used.
+        </p></div><div class="refsect2" lang="en"><a name="id2526853"></a><h3>TYPE *talloc_steal(const void *<span class="italic">new_ctx</span>, const TYPE *<span class="italic">ptr</span>);</h3><p>
+	  The talloc_steal() function changes the parent context of a
+	  talloc pointer.  It is typically used when the context that the
+	  pointer is currently a child of is going to be freed and you wish
+	  to keep the memory for a longer time.
+        </p><p>
+	  The talloc_steal() function returns the pointer that you pass it.
+	   It does not have any failure modes.
+        </p><p>
+	  NOTE: It is possible to produce loops in the parent/child
+	  relationship if you are not careful with talloc_steal().  No
+	  guarantees are provided as to your sanity or the safety of your
+	  data if you do this.
+        </p></div><div class="refsect2" lang="en"><a name="id2526890"></a><h3>TYPE *talloc_move(const void *<span class="italic">new_ctx</span>, TYPE **<span class="italic">ptr</span>);</h3><p>
+	  The talloc_move() function is a wrapper around
+	  talloc_steal() which zeros the source pointer after the
+	  move. This avoids a potential source of bugs where a
+	  programmer leaves a pointer in two structures, and uses the
+	  pointer from the old structure after it has been moved to a
+	  new one.
+        </p></div><div class="refsect2" lang="en"><a name="id2526916"></a><h3>size_t talloc_total_size(const void *<span class="italic">ptr</span>);</h3><p>
+	  The talloc_total_size() function returns the total size in bytes
+	  used by this pointer and all child pointers.	Mostly useful for
+	  debugging.
+        </p><p>
+	  Passing NULL is allowed, but it will only give a meaningful
+	  result if talloc_enable_leak_report() or
+	  talloc_enable_leak_report_full() has been called.
+        </p></div><div class="refsect2" lang="en"><a name="id2526940"></a><h3>size_t talloc_total_blocks(const void *<span class="italic">ptr</span>);</h3><p>
+	  The talloc_total_blocks() function returns the total memory block
+	  count used by this pointer and all child pointers.  Mostly useful
+	  for debugging.
+        </p><p>
+	  Passing NULL is allowed, but it will only give a meaningful
+	  result if talloc_enable_leak_report() or
+	  talloc_enable_leak_report_full() has been called.
+        </p></div><div class="refsect2" lang="en"><a name="talloc_report"></a><h3>void talloc_report(const void *ptr, FILE *f);</h3><p>
+	  The talloc_report() function prints a summary report of all
+	  memory used by <span class="italic">ptr</span>.  One line
+	  of report is printed for each immediate child of ptr, showing the
+	  total memory and number of blocks used by that child.
+        </p><p>
+	  You can pass NULL for the pointer, in which case a report is
+	  printed for the top level memory context, but only if
+	  talloc_enable_leak_report() or talloc_enable_leak_report_full()
+	  has been called.
+        </p></div><div class="refsect2" lang="en"><a name="talloc_report_full"></a><h3>void talloc_report_full(const void *<span class="italic">ptr</span>, FILE *<span class="italic">f</span>);</h3><p>
+	  This provides a more detailed report than talloc_report().  It
+	  will recursively print the entire tree of memory referenced by
+	  the pointer. References in the tree are shown by giving the name
+	  of the pointer that is referenced.
+        </p><p>
+	  You can pass NULL for the pointer, in which case a report is
+	  printed for the top level memory context, but only if
+	  talloc_enable_leak_report() or talloc_enable_leak_report_full()
+	  has been called.
+        </p></div><div class="refsect2" lang="en"><a name="talloc_report_depth_cb"></a><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr><td><code class="funcdef">void <b class="fsfunc">talloc_report_depth_cb</b>(</code></td><td><var class="pdparam">const void *ptr</var>, </td><td> </td></tr><tr><td> </td><td><var class="pdparam">int depth</var>, </td><td> </td></tr><tr><td> </td><td><var class="pdparam">int max_depth</var>, </td><td> </td></tr><tr><td> </td><td><var class="pdparam">void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *priv)</var>, </td><td> </td></tr><tr><td> </td><td><var class="pdparam">void *priv</var><code>)</code>;</td><td> </td></tr></table><table border="0" summary="Function argument synopsis" cellspacing="0" cellpadding="0"><tr><td><code></code> </td><td><code><var class="pdparam">const void *ptr</var>;</code></td></tr><tr><td><code></code> </td><td><code><var class="pdparam">int depth</var>;</code></td></tr><tr><td><code></code> </td><td><code><var class="pdparam">int max_depth</var>;</code></td></tr><tr><td><code></code> </td><td><code><var class="pdparam">void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *priv)</var>;</code></td></tr><tr><td><code></code> </td><td><code><var class="pdparam">void *priv</var>;</code></td></tr></table></div><p>
+	  This provides a more flexible reports than talloc_report(). It
+	  will recursively call the callback for the entire tree of memory
+	  referenced by the pointer. References in the tree are passed with
+	  <span class="italic">is_ref = 1</span> and the pointer that is referenced.
+        </p><p>
+	  You can pass NULL for the pointer, in which case a report is
+	  printed for the top level memory context, but only if
+	  talloc_enable_leak_report() or talloc_enable_leak_report_full()
+	  has been called.
+        </p><p>
+	  The recursion is stopped when depth >= max_depth.
+	  max_depth = -1 means only stop at leaf nodes.
+        </p></div><div class="refsect2" lang="en"><a name="talloc_report_depth_file"></a><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr><td><code class="funcdef">void <b class="fsfunc">talloc_report_depth_file</b>(</code></td><td><var class="pdparam">const void *ptr</var>, </td><td> </td></tr><tr><td> </td><td><var class="pdparam">int depth</var>, </td><td> </td></tr><tr><td> </td><td><var class="pdparam">int max_depth</var>, </td><td> </td></tr><tr><td> </td><td><var class="pdparam">FILE *f</var><code>)</code>;</td><td> </td></tr></table><table border="0" summary="Function argument synopsis" cellspacing="0" cellpadding="0"><tr><td><code></code> </td><td><code><var class="pdparam">const void *ptr</var>;</code></td></tr><tr><td><code></code> </td><td><code><var class="pdparam">int depth</var>;</code></td></tr><tr><td><code></code> </td><td><code><var class="pdparam">int max_depth</var>;</code></td></tr><tr><td><code></code> </td><td><code><var class="pdparam">FILE *f</var>;</code></td></tr></table></div><p>
+	  This provides a more flexible reports than talloc_report(). It
+	  will let you specify the depth and max_depth.
+        </p></div><div class="refsect2" lang="en"><a name="talloc_enable_leak_report"></a><h3>void talloc_enable_leak_report(void);</h3><p>
+	  This enables calling of talloc_report(NULL, stderr) when the
+	  program exits.  In Samba4 this is enabled by using the
+	  --leak-report command line option.
+        </p><p>
+	  For it to be useful, this function must be called before any
+	  other talloc function as it establishes a "null context" that
+	  acts as the top of the tree.	If you don't call this function
+	  first then passing NULL to talloc_report() or
+	  talloc_report_full() won't give you the full tree printout.
+        </p><p>
+	  Here is a typical talloc report:
+        </p><pre class="screen">talloc report on 'null_context' (total 267 bytes in 15 blocks)
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+iconv(UTF8,CP850)              contains   42 bytes in   2 blocks
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+iconv(CP850,UTF8)              contains   42 bytes in   2 blocks
+iconv(UTF8,UTF-16LE)           contains   45 bytes in   2 blocks
+iconv(UTF-16LE,UTF8)           contains   45 bytes in   2 blocks
+      </pre></div><div class="refsect2" lang="en"><a name="talloc_enable_leak_report_full"></a><h3>void talloc_enable_leak_report_full(void);</h3><p>
+	  This enables calling of talloc_report_full(NULL, stderr) when the
+	  program exits.  In Samba4 this is enabled by using the
+	  --leak-report-full command line option.
+        </p><p>
+	  For it to be useful, this function must be called before any
+	  other talloc function as it establishes a "null context" that
+	  acts as the top of the tree.	If you don't call this function
+	  first then passing NULL to talloc_report() or
+	  talloc_report_full() won't give you the full tree printout.
+        </p><p>
+	  Here is a typical full report:
+        </p><pre class="screen">full talloc report on 'root' (total 18 bytes in 8 blocks)
+p1               contains     18 bytes in   7 blocks (ref 0)
+    r1               contains     13 bytes in   2 blocks (ref 0)
+        reference to: p2
+    p2               contains      1 bytes in   1 blocks (ref 1)
+    x3               contains      1 bytes in   1 blocks (ref 0)
+    x2               contains      1 bytes in   1 blocks (ref 0)
+    x1               contains      1 bytes in   1 blocks (ref 0)
+      </pre></div><div class="refsect2" lang="en"><a name="id2527248"></a><h3>(<span class="italic">type</span> *)talloc_zero(const void *<span class="italic">ctx</span>, <span class="italic">type</span>);</h3><p>
+	  The talloc_zero() macro is equivalent to:
+        </p><pre class="programlisting">ptr = talloc(ctx, type);
+if (ptr) memset(ptr, 0, sizeof(type));</pre></div><div class="refsect2" lang="en"><a name="id2527281"></a><h3>void *talloc_zero_size(const void *<span class="italic">ctx</span>, size_t <span class="italic">size</span>)</h3><p>
+	  The talloc_zero_size() function is useful when you don't have a
+	  known type.
+        </p></div><div class="refsect2" lang="en"><a name="id2527304"></a><h3>void *talloc_memdup(const void *<span class="italic">ctx</span>, const void *<span class="italic">p</span>, size_t size);</h3><p>
+	  The talloc_memdup() function is equivalent to:
+        </p><pre class="programlisting">ptr = talloc_size(ctx, size);
+if (ptr) memcpy(ptr, p, size);</pre></div><div class="refsect2" lang="en"><a name="id2527332"></a><h3>char *talloc_strdup(const void *<span class="italic">ctx</span>, const char *<span class="italic">p</span>);</h3><p>
+	  The talloc_strdup() function is equivalent to:
+        </p><pre class="programlisting">ptr = talloc_size(ctx, strlen(p)+1);
+if (ptr) memcpy(ptr, p, strlen(p)+1);</pre><p>
+	  This function sets the name of the new pointer to the passed
+	  string. This is equivalent to:
+        </p><pre class="programlisting">talloc_set_name_const(ptr, ptr)</pre></div><div class="refsect2" lang="en"><a name="id2527372"></a><h3>char *talloc_strndup(const void *<span class="italic">t</span>, const char *<span class="italic">p</span>, size_t <span class="italic">n</span>);</h3><p>
+	  The talloc_strndup() function is the talloc equivalent of the C
+	  library function strndup(3).
+        </p><p>
+	  This function sets the name of the new pointer to the passed
+	  string. This is equivalent to:
+        </p><pre class="programlisting">talloc_set_name_const(ptr, ptr)</pre></div><div class="refsect2" lang="en"><a name="id2527412"></a><h3>char *talloc_vasprintf(const void *<span class="italic">t</span>, const char *<span class="italic">fmt</span>, va_list <span class="italic">ap</span>);</h3><p>
+	  The talloc_vasprintf() function is the talloc equivalent of the C
+	  library function vasprintf(3).
+        </p></div><div class="refsect2" lang="en"><a name="id2527441"></a><h3>char *talloc_asprintf(const void *<span class="italic">t</span>, const char *<span class="italic">fmt</span>, ...);</h3><p>
+	  The talloc_asprintf() function is the talloc equivalent of the C
+	  library function asprintf(3).
+        </p><p>
+	  This function sets the name of the new pointer to the passed
+	  string. This is equivalent to:
+        </p><pre class="programlisting">talloc_set_name_const(ptr, ptr)</pre></div><div class="refsect2" lang="en"><a name="id2527475"></a><h3>char *talloc_asprintf_append(char *s, const char *fmt, ...);</h3><p>
+	  The talloc_asprintf_append() function appends the given formatted
+	  string to the given string.
+        </p></div><div class="refsect2" lang="en"><a name="id2527486"></a><h3>(type *)talloc_array(const void *ctx, type, uint_t count);</h3><p>
+	  The talloc_array() macro is equivalent to:
+        </p><pre class="programlisting">(type *)talloc_size(ctx, sizeof(type) * count);</pre><p>
+	  except that it provides integer overflow protection for the
+	  multiply, returning NULL if the multiply overflows.
+        </p></div><div class="refsect2" lang="en"><a name="id2527509"></a><h3>void *talloc_array_size(const void *ctx, size_t size, uint_t count);</h3><p>
+	  The talloc_array_size() function is useful when the type is not
+	  known. It operates in the same way as talloc_array(), but takes a
+	  size instead of a type.
+        </p></div><div class="refsect2" lang="en"><a name="id2527522"></a><h3>(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, uint_t count);</h3><p>
+	  The talloc_ptrtype() macro should be used when you have a pointer to an array
+	  and want to allocate memory of an array to point at with this pointer. When compiling
+	  with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+	  and talloc_get_name() will return the current location in the source file.
+	  and not the type.
+        </p></div><div class="refsect2" lang="en"><a name="id2527538"></a><h3>void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size)</h3><p>
+	  This is a non-macro version of talloc_realloc(), which is useful
+	  as libraries sometimes want a realloc function pointer.  A
+	  realloc(3) implementation encapsulates the functionality of
+	  malloc(3), free(3) and realloc(3) in one call, which is why it is
+	  useful to be able to pass around a single function pointer.
+        </p></div><div class="refsect2" lang="en"><a name="id2527554"></a><h3>void *talloc_autofree_context(void);</h3><p>
+	  This is a handy utility function that returns a talloc context
+	  which will be automatically freed on program exit.  This can be
+	  used to reduce the noise in memory leak reports.
+        </p></div><div class="refsect2" lang="en"><a name="id2527566"></a><h3>void *talloc_check_name(const void *ptr, const char *name);</h3><p>
+	  This function checks if a pointer has the specified <span class="italic">name</span>.  If it does then the pointer is
+	  returned.  It it doesn't then NULL is returned.
+        </p></div><div class="refsect2" lang="en"><a name="id2527584"></a><h3>(type *)talloc_get_type(const void *ptr, type);</h3><p>
+	  This macro allows you to do type checking on talloc pointers.  It
+	  is particularly useful for void* private pointers.  It is
+	  equivalent to this:
+        </p><pre class="programlisting">(type *)talloc_check_name(ptr, #type)</pre></div><div class="refsect2" lang="en"><a name="id2527603"></a><h3>talloc_set_type(const void *ptr, type);</h3><p>
+	  This macro allows you to force the name of a pointer to be a
+	  particular <span class="emphasis"><em>type</em></span>.  This can be
+	  used in conjunction with talloc_get_type() to do type checking on
+	  void* pointers.
+        </p><p>
+	  It is equivalent to this:
+        </p><pre class="programlisting">talloc_set_name_const(ptr, #type)</pre></div></div><div class="refsect1" lang="en"><a name="id2527631"></a><h2>PERFORMANCE</h2><p>
+      All the additional features of talloc(3) over malloc(3) do come at a
+      price.  We have a simple performance test in Samba4 that measures
+      talloc() versus malloc() performance, and it seems that talloc() is
+      about 10% slower than malloc() on my x86 Debian Linux box.  For
+      Samba, the great reduction in code complexity that we get by using
+      talloc makes this worthwhile, especially as the total overhead of
+      talloc/malloc in Samba is already quite small.
+    </p></div><div class="refsect1" lang="en"><a name="id2527648"></a><h2>SEE ALSO</h2><p>
+      malloc(3), strndup(3), vasprintf(3), asprintf(3), 
+      <a href="http://talloc.samba.org/" target="_top">http://talloc.samba.org/</a>
+    </p></div><div class="refsect1" lang="en"><a name="id2527662"></a><h2>COPYRIGHT/LICENSE</h2><p>
+      Copyright (C) Andrew Tridgell 2004
+    </p><p>
+      This program is free software; you can redistribute it and/or modify
+      it under the terms of the GNU General Public License as published by
+      the Free Software Foundation; either version 3 of the License, or (at
+      your option) any later version.
+    </p><p>
+      This program is distributed in the hope that it will be useful, but
+      WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      General Public License for more details.
+    </p><p>
+      You should have received a copy of the GNU General Public License
+      along with this program; if not, write to the Free Software
+      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    </p></div></div></body></html>

Added: branches/ctdb/squeeze-backports/lib/talloc/talloc.3.xml
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/talloc.3.xml	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/talloc.3.xml	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,812 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry>
+  <refmeta>
+    <refentrytitle>talloc</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>talloc</refname>
+<refpurpose>hierarchical reference counted memory pool system with destructors</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+<synopsis>#include <talloc/talloc.h></synopsis>
+  </refsynopsisdiv>
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      If you are used to talloc from Samba3 then please read this
+      carefully, as talloc has changed a lot.
+    </para>
+    <para>
+      The new talloc is a hierarchical, reference counted memory pool
+      system with destructors.	Quite a mouthful really, but not too bad
+      once you get used to it.
+    </para>
+    <para>
+      Perhaps the biggest change from Samba3 is that there is no
+      distinction between a "talloc context" and a "talloc pointer".  Any
+      pointer returned from talloc() is itself a valid talloc context. 
+      This means you can do this:
+    </para>
+    <programlisting>
+    struct foo *X = talloc(mem_ctx, struct foo);
+    X->name = talloc_strdup(X, "foo");
+    </programlisting>
+    <para>
+      and the pointer <literal role="code">X->name</literal>
+      would be a "child" of the talloc context <literal
+      role="code">X</literal> which is itself a child of
+      <literal role="code">mem_ctx</literal>.  So if you do
+      <literal role="code">talloc_free(mem_ctx)</literal> then
+      it is all destroyed, whereas if you do <literal
+      role="code">talloc_free(X)</literal> then just <literal
+      role="code">X</literal> and <literal
+      role="code">X->name</literal> are destroyed, and if
+      you do <literal
+      role="code">talloc_free(X->name)</literal> then just
+      the name element of <literal role="code">X</literal> is
+      destroyed.
+    </para>
+    <para>
+      If you think about this, then what this effectively gives you is an
+      n-ary tree, where you can free any part of the tree with
+      talloc_free().
+    </para>
+    <para>
+      If you find this confusing, then I suggest you run the <literal
+      role="code">testsuite</literal> program to watch talloc
+      in action.  You may also like to add your own tests to <literal
+      role="code">testsuite.c</literal> to clarify how some
+      particular situation is handled.
+    </para>
+  </refsect1>
+  <refsect1><title>TALLOC API</title>
+    <para>
+      The following is a complete guide to the talloc API. Read it all at
+      least twice.
+    </para>
+    <refsect2><title>(type *)talloc(const void *ctx, type);</title>
+        <para>
+	  The talloc() macro is the core of the talloc library.  It takes a
+	  memory <emphasis role="italic">ctx</emphasis> and a <emphasis
+	  role="italic">type</emphasis>, and returns a pointer to a new
+	  area of memory of the given <emphasis
+	  role="italic">type</emphasis>.
+        </para>
+        <para>
+	  The returned pointer is itself a talloc context, so you can use
+	  it as the <emphasis role="italic">ctx</emphasis> argument to more
+	  calls to talloc() if you wish.
+        </para>
+        <para>
+	  The returned pointer is a "child" of the supplied context.  This
+	  means that if you talloc_free() the <emphasis
+	  role="italic">ctx</emphasis> then the new child disappears as
+	  well.  Alternatively you can free just the child.
+        </para>
+        <para>
+	  The <emphasis role="italic">ctx</emphasis> argument to talloc()
+	  can be NULL, in which case a new top level context is created.
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_size(const void *ctx, size_t size);</title>
+        <para>
+	  The function talloc_size() should be used when you don't have a
+	  convenient type to pass to talloc().	Unlike talloc(), it is not
+	  type safe (as it returns a void *), so you are on your own for
+	  type checking.
+        </para>
+    </refsect2>
+    <refsect2><title>(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);</title>
+        <para>
+	  The talloc_ptrtype() macro should be used when you have a pointer and
+	  want to allocate memory to point at with this pointer. When compiling
+	  with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+	  and talloc_get_name() will return the current location in the source file.
+	  and not the type.
+        </para>
+    </refsect2>
+    <refsect2><title>int talloc_free(void *ptr);</title>
+        <para>
+	  The talloc_free() function frees a piece of talloc memory, and
+	  all its children.  You can call talloc_free() on any pointer
+	  returned by talloc().
+        </para>
+        <para>
+	  The return value of talloc_free() indicates success or failure,
+	  with 0 returned for success and -1 for failure.  The only
+	  possible failure condition is if <emphasis
+	  role="italic">ptr</emphasis> had a destructor attached to it and
+	  the destructor returned -1.  See <link
+	  linkend="talloc_set_destructor"><quote>talloc_set_destructor()</quote></link>
+	  for details on destructors.
+        </para>
+        <para>
+	  If this pointer has an additional parent when talloc_free() is
+	  called then the memory is not actually released, but instead the
+	  most recently established parent is destroyed.  See <link
+	  linkend="talloc_reference"><quote>talloc_reference()</quote></link>
+	  for details on establishing additional parents.
+        </para>
+        <para>
+	  For more control on which parent is removed, see <link
+	  linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
+        </para>
+        <para>
+	  talloc_free() operates recursively on its children.
+        </para>
+	<para>
+	  From the 2.0 version of talloc, as a special case,
+	  talloc_free() is refused on pointers that have more than one
+	  parent, as talloc would have no way of knowing which parent
+	  should be removed. To free a pointer that has more than one
+	  parent please use talloc_unlink().
+	</para>
+	<para>
+	  To help you find problems in your code caused by this behaviour, if
+	  you do try and free a pointer with more than one parent then the
+	  talloc logging function will be called to give output like this:
+	</para>
+	<para>
+	  <screen format="linespecific">
+	    ERROR: talloc_free with references at some_dir/source/foo.c:123
+		reference at some_dir/source/other.c:325
+		reference at some_dir/source/third.c:121
+	  </screen>
+	</para>
+	<para>
+	  Please see the documentation for talloc_set_log_fn() and
+	  talloc_set_log_stderr() for more information on talloc logging
+	  functions.
+	</para>
+    </refsect2>
+    <refsect2 id="talloc_reference"><title>void *talloc_reference(const void *ctx, const void *ptr);</title>
+        <para>
+	  The talloc_reference() function makes <emphasis
+	  role="italic">ctx</emphasis> an additional parent of <emphasis
+	  role="italic">ptr</emphasis>.
+        </para>
+        <para>
+	  The return value of talloc_reference() is always the original
+	  pointer <emphasis role="italic">ptr</emphasis>, unless talloc ran
+	  out of memory in creating the reference in which case it will
+	  return NULL (each additional reference consumes around 48 bytes
+	  of memory on intel x86 platforms).
+        </para>
+        <para>
+	  If <emphasis role="italic">ptr</emphasis> is NULL, then the
+	  function is a no-op, and simply returns NULL.
+        </para>
+        <para>
+	  After creating a reference you can free it in one of the
+	  following ways:
+        </para>
+      <para>
+        <itemizedlist>
+          <listitem>
+            <para>
+	      you can talloc_free() any parent of the original pointer. 
+	      That will reduce the number of parents of this pointer by 1,
+	      and will cause this pointer to be freed if it runs out of
+	      parents.
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+	      you can talloc_free() the pointer itself.  That will destroy
+	      the most recently established parent to the pointer and leave
+	      the pointer as a child of its current parent.
+            </para>
+          </listitem>
+        </itemizedlist>
+      </para>
+      <para>
+	For more control on which parent to remove, see <link
+	linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
+      </para>
+    </refsect2>
+    <refsect2 id="talloc_unlink"><title>int talloc_unlink(const void *ctx, const void *ptr);</title>
+        <para>
+	  The talloc_unlink() function removes a specific parent from
+	  <emphasis role="italic">ptr</emphasis>. The <emphasis
+	  role="italic">ctx</emphasis> passed must either be a context used
+	  in talloc_reference() with this pointer, or must be a direct
+	  parent of ptr.
+        </para>
+        <para>
+	  Note that if the parent has already been removed using
+	  talloc_free() then this function will fail and will return -1. 
+	  Likewise, if <emphasis role="italic">ptr</emphasis> is NULL, then
+	  the function will make no modifications and return -1.
+        </para>
+        <para>
+	  Usually you can just use talloc_free() instead of
+	  talloc_unlink(), but sometimes it is useful to have the
+	  additional control on which parent is removed.
+        </para>
+    </refsect2>
+    <refsect2 id="talloc_set_destructor"><title>void talloc_set_destructor(const void *ptr, int (*destructor)(void *));</title>
+        <para>
+	  The function talloc_set_destructor() sets the <emphasis
+	  role="italic">destructor</emphasis> for the pointer <emphasis
+	  role="italic">ptr</emphasis>.  A <emphasis
+	  role="italic">destructor</emphasis> is a function that is called
+	  when the memory used by a pointer is about to be released.  The
+	  destructor receives <emphasis role="italic">ptr</emphasis> as an
+	  argument, and should return 0 for success and -1 for failure.
+        </para>
+        <para>
+	  The <emphasis role="italic">destructor</emphasis> can do anything
+	  it wants to, including freeing other pieces of memory.  A common
+	  use for destructors is to clean up operating system resources
+	  (such as open file descriptors) contained in the structure the
+	  destructor is placed on.
+        </para>
+        <para>
+	  You can only place one destructor on a pointer.  If you need more
+	  than one destructor then you can create a zero-length child of
+	  the pointer and place an additional destructor on that.
+        </para>
+        <para>
+	  To remove a destructor call talloc_set_destructor() with NULL for
+	  the destructor.
+        </para>
+        <para>
+	  If your destructor attempts to talloc_free() the pointer that it
+	  is the destructor for then talloc_free() will return -1 and the
+	  free will be ignored.  This would be a pointless operation
+	  anyway, as the destructor is only called when the memory is just
+	  about to go away.
+        </para>
+    </refsect2>
+    <refsect2><title>int talloc_increase_ref_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
+        <para>
+	  The talloc_increase_ref_count(<emphasis
+	  role="italic">ptr</emphasis>) function is exactly equivalent to:
+        </para>
+        <programlisting>talloc_reference(NULL, ptr);</programlisting>
+        <para>
+	  You can use either syntax, depending on which you think is
+	  clearer in your code.
+        </para>
+        <para>
+	  It returns 0 on success and -1 on failure.
+        </para>
+    </refsect2>
+    <refsect2><title>size_t talloc_reference_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
+        <para>
+	  Return the number of references to the pointer.
+        </para>
+    </refsect2>
+    <refsect2 id="talloc_set_name"><title>void talloc_set_name(const void *ptr, const char *fmt, ...);</title>
+        <para>
+	  Each talloc pointer has a "name".  The name is used principally
+	  for debugging purposes, although it is also possible to set and
+	  get the name on a pointer in as a way of "marking" pointers in
+	  your code.
+        </para>
+        <para>
+	  The main use for names on pointer is for "talloc reports".  See
+	  <link
+	  linkend="talloc_report"><quote>talloc_report_depth_cb()</quote></link>,
+	  <link
+	  linkend="talloc_report"><quote>talloc_report_depth_file()</quote></link>,
+	  <link
+	  linkend="talloc_report"><quote>talloc_report()</quote></link>
+	  <link
+	  linkend="talloc_report"><quote>talloc_report()</quote></link>
+	  and <link
+	  linkend="talloc_report_full"><quote>talloc_report_full()</quote></link>
+	  for details.	Also see <link
+	  linkend="talloc_enable_leak_report"><quote>talloc_enable_leak_report()</quote></link>
+	  and <link
+	  linkend="talloc_enable_leak_report_full"><quote>talloc_enable_leak_report_full()</quote></link>.
+        </para>
+        <para>
+	  The talloc_set_name() function allocates memory as a child of the
+	  pointer.  It is logically equivalent to:
+        </para>
+        <programlisting>talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));</programlisting>
+        <para>
+	  Note that multiple calls to talloc_set_name() will allocate more
+	  memory without releasing the name.  All of the memory is released
+	  when the ptr is freed using talloc_free().
+        </para>
+    </refsect2>
+    <refsect2><title>void talloc_set_name_const(const void *<emphasis role="italic">ptr</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
+        <para>
+	  The function talloc_set_name_const() is just like
+	  talloc_set_name(), but it takes a string constant, and is much
+	  faster.  It is extensively used by the "auto naming" macros, such
+	  as talloc_p().
+        </para>
+        <para>
+	  This function does not allocate any memory.  It just copies the
+	  supplied pointer into the internal representation of the talloc
+	  ptr. This means you must not pass a <emphasis
+	  role="italic">name</emphasis> pointer to memory that will
+	  disappear before <emphasis role="italic">ptr</emphasis> is freed
+	  with talloc_free().
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_named(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+        <para>
+	  The talloc_named() function creates a named talloc pointer.  It
+	  is equivalent to:
+        </para>
+        <programlisting>ptr = talloc_size(ctx, size);
+talloc_set_name(ptr, fmt, ....);</programlisting>
+    </refsect2>
+    <refsect2><title>void *talloc_named_const(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
+        <para>
+	  This is equivalent to:
+        </para>
+        <programlisting>ptr = talloc_size(ctx, size);
+talloc_set_name_const(ptr, name);</programlisting>
+    </refsect2>
+    <refsect2><title>const char *talloc_get_name(const void *<emphasis role="italic">ptr</emphasis>);</title>
+        <para>
+	  This returns the current name for the given talloc pointer,
+	  <emphasis role="italic">ptr</emphasis>. See <link
+	  linkend="talloc_set_name"><quote>talloc_set_name()</quote></link>
+	  for details.
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_init(const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+        <para>
+	  This function creates a zero length named talloc context as a top
+	  level context.  It is equivalent to:
+        </para>
+        <programlisting>talloc_named(NULL, 0, fmt, ...);</programlisting>
+    </refsect2>
+    <refsect2><title>void *talloc_new(void *<emphasis role="italic">ctx</emphasis>);</title>
+        <para>
+	  This is a utility macro that creates a new memory context hanging
+	  off an existing context, automatically naming it "talloc_new:
+	  __location__" where __location__ is the source line it is called
+	  from.  It is particularly useful for creating a new temporary
+	  working context.
+        </para>
+    </refsect2>
+    <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_realloc(const void *<emphasis role="italic">ctx</emphasis>, void *<emphasis role="italic">ptr</emphasis>, <emphasis role="italic">type</emphasis>, <emphasis role="italic">count</emphasis>);</title>
+        <para>
+	  The talloc_realloc() macro changes the size of a talloc pointer. 
+	  It has the following equivalences:
+        </para>
+        <programlisting>talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
+talloc_realloc(ctx, ptr, type, 0)  ==> talloc_free(ptr);</programlisting>
+        <para>
+	  The <emphasis role="italic">ctx</emphasis> argument is only used
+	  if <emphasis role="italic">ptr</emphasis> is not NULL, otherwise
+	  it is ignored.
+        </para>
+        <para>
+	  talloc_realloc() returns the new pointer, or NULL on failure. 
+	  The call will fail either due to a lack of memory, or because the
+	  pointer has more than one parent (see <link
+	  linkend="talloc_reference"><quote>talloc_reference()</quote></link>).
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);</title>
+        <para>
+	  the talloc_realloc_size() function is useful when the type is not
+	  known so the type-safe talloc_realloc() cannot be used.
+        </para>
+    </refsect2>
+    <refsect2><title>TYPE *talloc_steal(const void *<emphasis role="italic">new_ctx</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title>
+        <para>
+	  The talloc_steal() function changes the parent context of a
+	  talloc pointer.  It is typically used when the context that the
+	  pointer is currently a child of is going to be freed and you wish
+	  to keep the memory for a longer time.
+        </para>
+        <para>
+	  The talloc_steal() function returns the pointer that you pass it.
+	   It does not have any failure modes.
+        </para>
+        <para>
+	  It is possible to produce loops in the parent/child
+	  relationship if you are not careful with talloc_steal().  No
+	  guarantees are provided as to your sanity or the safety of your
+	  data if you do this.
+        </para>
+        <para>
+	  Note that if you try and call talloc_steal() on a pointer that has
+	  more than one parent then the result is ambiguous. Talloc will choose
+	  to remove the parent that is currently indicated by talloc_parent()
+	  and replace it with the chosen parent. You will also get a message
+	  like this via the talloc logging functions:
+        </para>
+        <para>
+	  <screen format="linespecific">
+	  WARNING: talloc_steal with references at some_dir/source/foo.c:123
+		reference at some_dir/source/other.c:325
+		reference at some_dir/source/third.c:121
+	  </screen>
+        </para>
+        <para>
+	  To unambiguously change the parent of a pointer please see
+	  the
+	  function <link linkend="talloc_reference"><quote>talloc_reparent()</quote></link>. See
+	  the talloc_set_log_fn() documentation for more information
+	  on talloc logging.
+	</para>
+    </refsect2>
+    <refsect2><title>TYPE *talloc_reparent(const void *<emphasis role="italic">old_parent</emphasis>, const void *<emphasis role="italic">new_parent</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title>
+        <para>
+	  The talloc_reparent() function changes the parent context of a talloc
+	  pointer. It is typically used when the context that the pointer is
+	  currently a child of is going to be freed and you wish to keep the
+	  memory for a longer time.
+        </para>
+        <para>
+	  The talloc_reparent() function returns the pointer that you pass it. It
+	  does not have any failure modes.
+        </para>
+        <para>
+	  The difference between talloc_reparent() and talloc_steal() is that
+	  talloc_reparent() can specify which parent you wish to change. This is
+	  useful when a pointer has multiple parents via references.
+        </para>
+    </refsect2>
+    <refsect2><title>TYPE *talloc_move(const void *<emphasis role="italic">new_ctx</emphasis>, TYPE **<emphasis role="italic">ptr</emphasis>);</title>
+        <para>
+	  The talloc_move() function is a wrapper around
+	  talloc_steal() which zeros the source pointer after the
+	  move. This avoids a potential source of bugs where a
+	  programmer leaves a pointer in two structures, and uses the
+	  pointer from the old structure after it has been moved to a
+	  new one.
+        </para>
+    </refsect2>
+    <refsect2><title>size_t talloc_total_size(const void *<emphasis role="italic">ptr</emphasis>);</title>
+        <para>
+	  The talloc_total_size() function returns the total size in bytes
+	  used by this pointer and all child pointers.	Mostly useful for
+	  debugging.
+        </para>
+        <para>
+	  Passing NULL is allowed, but it will only give a meaningful
+	  result if talloc_enable_leak_report() or
+	  talloc_enable_leak_report_full() has been called.
+        </para>
+    </refsect2>
+    <refsect2><title>size_t talloc_total_blocks(const void *<emphasis role="italic">ptr</emphasis>);</title>
+        <para>
+	  The talloc_total_blocks() function returns the total memory block
+	  count used by this pointer and all child pointers.  Mostly useful
+	  for debugging.
+        </para>
+        <para>
+	  Passing NULL is allowed, but it will only give a meaningful
+	  result if talloc_enable_leak_report() or
+	  talloc_enable_leak_report_full() has been called.
+        </para>
+    </refsect2>
+    <refsect2 id="talloc_report"><title>void talloc_report(const void *ptr, FILE *f);</title>
+        <para>
+	  The talloc_report() function prints a summary report of all
+	  memory used by <emphasis role="italic">ptr</emphasis>.  One line
+	  of report is printed for each immediate child of ptr, showing the
+	  total memory and number of blocks used by that child.
+        </para>
+        <para>
+	  You can pass NULL for the pointer, in which case a report is
+	  printed for the top level memory context, but only if
+	  talloc_enable_leak_report() or talloc_enable_leak_report_full()
+	  has been called.
+        </para>
+    </refsect2>
+    <refsect2 id="talloc_report_full"><title>void talloc_report_full(const void *<emphasis role="italic">ptr</emphasis>, FILE *<emphasis role="italic">f</emphasis>);</title>
+        <para>
+	  This provides a more detailed report than talloc_report().  It
+	  will recursively print the entire tree of memory referenced by
+	  the pointer. References in the tree are shown by giving the name
+	  of the pointer that is referenced.
+        </para>
+        <para>
+	  You can pass NULL for the pointer, in which case a report is
+	  printed for the top level memory context, but only if
+	  talloc_enable_leak_report() or talloc_enable_leak_report_full()
+	  has been called.
+        </para>
+    </refsect2>
+    <refsect2 id="talloc_report_depth_cb">
+     <funcsynopsis><funcprototype>
+      <funcdef>void <function>talloc_report_depth_cb</function></funcdef>
+      <paramdef><parameter>const void *ptr</parameter></paramdef>
+      <paramdef><parameter>int depth</parameter></paramdef>
+      <paramdef><parameter>int max_depth</parameter></paramdef>
+      <paramdef><parameter>void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *priv)</parameter></paramdef>
+      <paramdef><parameter>void *priv</parameter></paramdef>
+     </funcprototype></funcsynopsis>
+        <para>
+	  This provides a more flexible reports than talloc_report(). It
+	  will recursively call the callback for the entire tree of memory
+	  referenced by the pointer. References in the tree are passed with
+	  <emphasis role="italic">is_ref = 1</emphasis> and the pointer that is referenced.
+        </para>
+        <para>
+	  You can pass NULL for the pointer, in which case a report is
+	  printed for the top level memory context, but only if
+	  talloc_enable_leak_report() or talloc_enable_leak_report_full()
+	  has been called.
+        </para>
+        <para>
+	  The recursion is stopped when depth >= max_depth.
+	  max_depth = -1 means only stop at leaf nodes.
+        </para>
+    </refsect2>
+    <refsect2 id="talloc_report_depth_file">
+     <funcsynopsis><funcprototype>
+      <funcdef>void <function>talloc_report_depth_file</function></funcdef>
+      <paramdef><parameter>const void *ptr</parameter></paramdef>
+      <paramdef><parameter>int depth</parameter></paramdef>
+      <paramdef><parameter>int max_depth</parameter></paramdef>
+      <paramdef><parameter>FILE *f</parameter></paramdef>
+     </funcprototype></funcsynopsis>
+        <para>
+	  This provides a more flexible reports than talloc_report(). It
+	  will let you specify the depth and max_depth.
+        </para>
+    </refsect2>
+    <refsect2 id="talloc_enable_leak_report"><title>void talloc_enable_leak_report(void);</title>
+        <para>
+	  This enables calling of talloc_report(NULL, stderr) when the
+	  program exits.  In Samba4 this is enabled by using the
+	  --leak-report command line option.
+        </para>
+        <para>
+	  For it to be useful, this function must be called before any
+	  other talloc function as it establishes a "null context" that
+	  acts as the top of the tree.	If you don't call this function
+	  first then passing NULL to talloc_report() or
+	  talloc_report_full() won't give you the full tree printout.
+        </para>
+        <para>
+	  Here is a typical talloc report:
+        </para>
+        <screen format="linespecific">talloc report on 'null_context' (total 267 bytes in 15 blocks)
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+iconv(UTF8,CP850)              contains   42 bytes in   2 blocks
+libcli/auth/spnego_parse.c:55  contains   31 bytes in   2 blocks
+iconv(CP850,UTF8)              contains   42 bytes in   2 blocks
+iconv(UTF8,UTF-16LE)           contains   45 bytes in   2 blocks
+iconv(UTF-16LE,UTF8)           contains   45 bytes in   2 blocks
+      </screen>
+    </refsect2>
+    <refsect2 id="talloc_enable_leak_report_full"><title>void talloc_enable_leak_report_full(void);</title>
+        <para>
+	  This enables calling of talloc_report_full(NULL, stderr) when the
+	  program exits.  In Samba4 this is enabled by using the
+	  --leak-report-full command line option.
+        </para>
+        <para>
+	  For it to be useful, this function must be called before any
+	  other talloc function as it establishes a "null context" that
+	  acts as the top of the tree.	If you don't call this function
+	  first then passing NULL to talloc_report() or
+	  talloc_report_full() won't give you the full tree printout.
+        </para>
+        <para>
+	  Here is a typical full report:
+        </para>
+        <screen format="linespecific">full talloc report on 'root' (total 18 bytes in 8 blocks)
+p1               contains     18 bytes in   7 blocks (ref 0)
+    r1               contains     13 bytes in   2 blocks (ref 0)
+        reference to: p2
+    p2               contains      1 bytes in   1 blocks (ref 1)
+    x3               contains      1 bytes in   1 blocks (ref 0)
+    x2               contains      1 bytes in   1 blocks (ref 0)
+    x1               contains      1 bytes in   1 blocks (ref 0)
+      </screen>
+    </refsect2>
+    <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_zero(const void *<emphasis role="italic">ctx</emphasis>, <emphasis role="italic">type</emphasis>);</title>
+        <para>
+	  The talloc_zero() macro is equivalent to:
+        </para>
+        <programlisting>ptr = talloc(ctx, type);
+if (ptr) memset(ptr, 0, sizeof(type));</programlisting>
+    </refsect2>
+    <refsect2><title>void *talloc_zero_size(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>)</title>
+        <para>
+	  The talloc_zero_size() function is useful when you don't have a
+	  known type.
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_memdup(const void *<emphasis role="italic">ctx</emphasis>, const void *<emphasis role="italic">p</emphasis>, size_t size);</title>
+        <para>
+	  The talloc_memdup() function is equivalent to:
+        </para>
+        <programlisting>ptr = talloc_size(ctx, size);
+if (ptr) memcpy(ptr, p, size);</programlisting>
+    </refsect2>
+    <refsect2><title>char *talloc_strdup(const void *<emphasis role="italic">ctx</emphasis>, const char *<emphasis role="italic">p</emphasis>);</title>
+        <para>
+	  The talloc_strdup() function is equivalent to:
+        </para>
+        <programlisting>ptr = talloc_size(ctx, strlen(p)+1);
+if (ptr) memcpy(ptr, p, strlen(p)+1);</programlisting>
+        <para>
+	  This function sets the name of the new pointer to the passed
+	  string. This is equivalent to:
+        </para>
+        <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+    </refsect2>
+    <refsect2><title>char *talloc_strndup(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">p</emphasis>, size_t <emphasis role="italic">n</emphasis>);</title>
+        <para>
+	  The talloc_strndup() function is the talloc equivalent of the C
+	  library function strndup(3).
+        </para>
+        <para>
+	  This function sets the name of the new pointer to the passed
+	  string. This is equivalent to:
+        </para>
+        <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+    </refsect2>
+    <refsect2><title>char *talloc_append_string(const void *<emphasis role="italic">t</emphasis>, char *<emphasis role="italic">orig</emphasis>, const char *<emphasis role="italic">append</emphasis>);</title>
+        <para>
+	  The talloc_append_string() function appends the given formatted
+	  string to the given string.
+        </para>
+        <para>
+	  This function sets the name of the new pointer to the new
+	  string. This is equivalent to:
+        </para>
+        <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+    </refsect2>
+    <refsect2><title>char *talloc_vasprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, va_list <emphasis role="italic">ap</emphasis>);</title>
+        <para>
+	  The talloc_vasprintf() function is the talloc equivalent of the C
+	  library function vasprintf(3).
+        </para>
+        <para>
+	  This function sets the name of the new pointer to the new
+	  string. This is equivalent to:
+        </para>
+        <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+    </refsect2>
+    <refsect2><title>char *talloc_asprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+        <para>
+	  The talloc_asprintf() function is the talloc equivalent of the C
+	  library function asprintf(3).
+        </para>
+        <para>
+	  This function sets the name of the new pointer to the passed
+	  string. This is equivalent to:
+        </para>
+        <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+    </refsect2>
+    <refsect2><title>char *talloc_asprintf_append(char *s, const char *fmt, ...);</title>
+        <para>
+	  The talloc_asprintf_append() function appends the given formatted
+	  string to the given string.
+        </para>
+        <para>
+	  This function sets the name of the new pointer to the new
+	  string. This is equivalent to:
+        </para>
+        <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+    </refsect2>
+    <refsect2><title>(type *)talloc_array(const void *ctx, type, unsigned int count);</title>
+        <para>
+	  The talloc_array() macro is equivalent to:
+        </para>
+        <programlisting>(type *)talloc_size(ctx, sizeof(type) * count);</programlisting>
+        <para>
+	  except that it provides integer overflow protection for the
+	  multiply, returning NULL if the multiply overflows.
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_array_size(const void *ctx, size_t size, unsigned int count);</title>
+        <para>
+	  The talloc_array_size() function is useful when the type is not
+	  known. It operates in the same way as talloc_array(), but takes a
+	  size instead of a type.
+        </para>
+    </refsect2>
+    <refsect2><title>(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, unsigned int count);</title>
+        <para>
+	  The talloc_ptrtype() macro should be used when you have a pointer to an array
+	  and want to allocate memory of an array to point at with this pointer. When compiling
+	  with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+	  and talloc_get_name() will return the current location in the source file.
+	  and not the type.
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size)</title>
+        <para>
+	  This is a non-macro version of talloc_realloc(), which is useful
+	  as libraries sometimes want a realloc function pointer.  A
+	  realloc(3) implementation encapsulates the functionality of
+	  malloc(3), free(3) and realloc(3) in one call, which is why it is
+	  useful to be able to pass around a single function pointer.
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_autofree_context(void);</title>
+        <para>
+	  This is a handy utility function that returns a talloc context
+	  which will be automatically freed on program exit.  This can be
+	  used to reduce the noise in memory leak reports.
+        </para>
+    </refsect2>
+    <refsect2><title>void *talloc_check_name(const void *ptr, const char *name);</title>
+        <para>
+	  This function checks if a pointer has the specified <emphasis
+	  role="italic">name</emphasis>.  If it does then the pointer is
+	  returned.  It it doesn't then NULL is returned.
+        </para>
+    </refsect2>
+    <refsect2><title>(type *)talloc_get_type(const void *ptr, type);</title>
+        <para>
+	  This macro allows you to do type checking on talloc pointers.  It
+	  is particularly useful for void* private pointers.  It is
+	  equivalent to this:
+        </para>
+        <programlisting>(type *)talloc_check_name(ptr, #type)</programlisting>
+    </refsect2>
+    <refsect2><title>talloc_set_type(const void *ptr, type);</title>
+        <para>
+	  This macro allows you to force the name of a pointer to be a
+	  particular <emphasis>type</emphasis>.  This can be
+	  used in conjunction with talloc_get_type() to do type checking on
+	  void* pointers.
+        </para>
+        <para>
+	  It is equivalent to this:
+        </para>
+        <programlisting>talloc_set_name_const(ptr, #type)</programlisting>
+    </refsect2>
+    <refsect2><title>talloc_set_log_fn(void (*log_fn)(const char *message));</title>
+        <para>
+	  This function sets a logging function that talloc will use for
+	  warnings and errors. By default talloc will not print any warnings or
+	  errors.
+	</para>
+    </refsect2>
+    <refsect2><title>talloc_set_log_stderr(void);</title>
+        <para>
+	  This sets the talloc log function to write log messages to stderr
+	</para>
+    </refsect2>
+  </refsect1>
+  <refsect1><title>PERFORMANCE</title>
+    <para>
+      All the additional features of talloc(3) over malloc(3) do come at a
+      price.  We have a simple performance test in Samba4 that measures
+      talloc() versus malloc() performance, and it seems that talloc() is
+      about 10% slower than malloc() on my x86 Debian Linux box.  For
+      Samba, the great reduction in code complexity that we get by using
+      talloc makes this worthwhile, especially as the total overhead of
+      talloc/malloc in Samba is already quite small.
+    </para>
+  </refsect1>
+  <refsect1><title>SEE ALSO</title>
+    <para>
+      malloc(3), strndup(3), vasprintf(3), asprintf(3), 
+      <ulink url="http://talloc.samba.org/"/>
+    </para>
+  </refsect1>
+  <refsect1><title>COPYRIGHT/LICENSE</title>
+    <para>
+      Copyright (C) Andrew Tridgell 2004
+    </para>
+    <para>
+      This program is free software; you can redistribute it and/or modify
+      it under the terms of the GNU General Public License as published by
+      the Free Software Foundation; either version 3 of the License, or (at
+      your option) any later version.
+    </para>
+    <para>
+      This program is distributed in the hope that it will be useful, but
+      WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      General Public License for more details.
+    </para>
+    <para>
+      You should have received a copy of the GNU General Public License
+      along with this program; if not, see http://www.gnu.org/licenses/.
+    </para>
+  </refsect1>
+</refentry>

Added: branches/ctdb/squeeze-backports/lib/talloc/talloc.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/talloc.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/talloc.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,2019 @@
+/* 
+   Samba Unix SMB/CIFS implementation.
+
+   Samba trivial allocation library - new interface
+
+   NOTE: Please read talloc_guide.txt for full documentation
+
+   Copyright (C) Andrew Tridgell 2004
+   Copyright (C) Stefan Metzmacher 2006
+   
+     ** NOTE! The following LGPL license applies to the talloc
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  inspired by http://swapped.cc/halloc/
+*/
+
+#include "replace.h"
+#include "talloc.h"
+#include "includes.h"
+
+#ifdef TALLOC_BUILD_VERSION_MAJOR
+#if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR)
+#error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR"
+#endif
+#endif
+
+#ifdef TALLOC_BUILD_VERSION_MINOR
+#if (TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR)
+#error "TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR"
+#endif
+#endif
+
+/* use this to force every realloc to change the pointer, to stress test
+   code that might not cope */
+#define ALWAYS_REALLOC 0
+
+
+#define MAX_TALLOC_SIZE 0x10000000
+#define TALLOC_MAGIC_BASE 0xe814ec70
+#define TALLOC_MAGIC ( \
+	TALLOC_MAGIC_BASE + \
+	(TALLOC_VERSION_MAJOR << 12) + \
+	(TALLOC_VERSION_MINOR << 4) \
+)
+
+#define TALLOC_FLAG_FREE 0x01
+#define TALLOC_FLAG_LOOP 0x02
+#define TALLOC_FLAG_POOL 0x04		/* This is a talloc pool */
+#define TALLOC_FLAG_POOLMEM 0x08	/* This is allocated in a pool */
+#define TALLOC_MAGIC_REFERENCE ((const char *)1)
+
+/* by default we abort when given a bad pointer (such as when talloc_free() is called 
+   on a pointer that came from malloc() */
+#ifndef TALLOC_ABORT
+#define TALLOC_ABORT(reason) abort()
+#endif
+
+#ifndef discard_const_p
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
+#else
+# define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+#endif
+
+/* these macros gain us a few percent of speed on gcc */
+#if (__GNUC__ >= 3)
+/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
+   as its first argument */
+#ifndef likely
+#define likely(x)   __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+/* this null_context is only used if talloc_enable_leak_report() or
+   talloc_enable_leak_report_full() is called, otherwise it remains
+   NULL
+*/
+static void *null_context;
+static void *autofree_context;
+
+struct talloc_reference_handle {
+	struct talloc_reference_handle *next, *prev;
+	void *ptr;
+	const char *location;
+};
+
+typedef int (*talloc_destructor_t)(void *);
+
+struct talloc_chunk {
+	struct talloc_chunk *next, *prev;
+	struct talloc_chunk *parent, *child;
+	struct talloc_reference_handle *refs;
+	talloc_destructor_t destructor;
+	const char *name;
+	size_t size;
+	unsigned flags;
+
+	/*
+	 * "pool" has dual use:
+	 *
+	 * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
+	 * marks the end of the currently allocated area.
+	 *
+	 * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
+	 * is a pointer to the struct talloc_chunk of the pool that it was
+	 * allocated from. This way children can quickly find the pool to chew
+	 * from.
+	 */
+	void *pool;
+};
+
+/* 16 byte alignment seems to keep everyone happy */
+#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
+#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
+
+_PUBLIC_ int talloc_version_major(void)
+{
+	return TALLOC_VERSION_MAJOR;
+}
+
+_PUBLIC_ int talloc_version_minor(void)
+{
+	return TALLOC_VERSION_MINOR;
+}
+
+static void (*talloc_log_fn)(const char *message);
+
+_PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message))
+{
+	talloc_log_fn = log_fn;
+}
+
+static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+static void talloc_log(const char *fmt, ...)
+{
+	va_list ap;
+	char *message;
+
+	if (!talloc_log_fn) {
+		return;
+	}
+
+	va_start(ap, fmt);
+	message = talloc_vasprintf(NULL, fmt, ap);
+	va_end(ap);
+
+	talloc_log_fn(message);
+	talloc_free(message);
+}
+
+static void talloc_log_stderr(const char *message)
+{
+	fprintf(stderr, "%s", message);
+}
+
+_PUBLIC_ void talloc_set_log_stderr(void)
+{
+	talloc_set_log_fn(talloc_log_stderr);
+}
+
+static void (*talloc_abort_fn)(const char *reason);
+
+_PUBLIC_ void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+	talloc_abort_fn = abort_fn;
+}
+
+static void talloc_abort(const char *reason)
+{
+	talloc_log("%s\n", reason);
+
+	if (!talloc_abort_fn) {
+		TALLOC_ABORT(reason);
+	}
+
+	talloc_abort_fn(reason);
+}
+
+static void talloc_abort_magic(unsigned magic)
+{
+	unsigned striped = magic - TALLOC_MAGIC_BASE;
+	unsigned major = (striped & 0xFFFFF000) >> 12;
+	unsigned minor = (striped & 0x00000FF0) >> 4;
+	talloc_log("Bad talloc magic[0x%08X/%u/%u] expected[0x%08X/%u/%u]\n",
+		   magic, major, minor,
+		   TALLOC_MAGIC, TALLOC_VERSION_MAJOR, TALLOC_VERSION_MINOR);
+	talloc_abort("Bad talloc magic value - wrong talloc version used/mixed");
+}
+
+static void talloc_abort_double_free(void)
+{
+	talloc_abort("Bad talloc magic value - double free");
+}
+
+static void talloc_abort_unknown_value(void)
+{
+	talloc_abort("Bad talloc magic value - unknown value");
+}
+
+/* panic if we get a bad magic value */
+static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
+{
+	const char *pp = (const char *)ptr;
+	struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
+	if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { 
+		if ((tc->flags & (~0xFFF)) == TALLOC_MAGIC_BASE) {
+			talloc_abort_magic(tc->flags & (~0xF));
+			return NULL;
+		}
+
+		if (tc->flags & TALLOC_FLAG_FREE) {
+			talloc_log("talloc: double free error - first free may be at %s\n", tc->name);
+			talloc_abort_double_free();
+			return NULL;
+		} else {
+			talloc_abort_unknown_value();
+			return NULL;
+		}
+	}
+	return tc;
+}
+
+/* hook into the front of the list */
+#define _TLIST_ADD(list, p) \
+do { \
+        if (!(list)) { \
+		(list) = (p); \
+		(p)->next = (p)->prev = NULL; \
+	} else { \
+		(list)->prev = (p); \
+		(p)->next = (list); \
+		(p)->prev = NULL; \
+		(list) = (p); \
+	}\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define _TLIST_REMOVE(list, p) \
+do { \
+	if ((p) == (list)) { \
+		(list) = (p)->next; \
+		if (list) (list)->prev = NULL; \
+	} else { \
+		if ((p)->prev) (p)->prev->next = (p)->next; \
+		if ((p)->next) (p)->next->prev = (p)->prev; \
+	} \
+	if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+
+/*
+  return the parent chunk of a pointer
+*/
+static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
+{
+	struct talloc_chunk *tc;
+
+	if (unlikely(ptr == NULL)) {
+		return NULL;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+	while (tc->prev) tc=tc->prev;
+
+	return tc->parent;
+}
+
+_PUBLIC_ void *talloc_parent(const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+	return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
+}
+
+/*
+  find parents name
+*/
+_PUBLIC_ const char *talloc_parent_name(const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+	return tc? tc->name : NULL;
+}
+
+/*
+  A pool carries an in-pool object count count in the first 16 bytes.
+  bytes. This is done to support talloc_steal() to a parent outside of the
+  pool. The count includes the pool itself, so a talloc_free() on a pool will
+  only destroy the pool if the count has dropped to zero. A talloc_free() of a
+  pool member will reduce the count, and eventually also call free(3) on the
+  pool memory.
+
+  The object count is not put into "struct talloc_chunk" because it is only
+  relevant for talloc pools and the alignment to 16 bytes would increase the
+  memory footprint of each talloc chunk by those 16 bytes.
+*/
+
+#define TALLOC_POOL_HDR_SIZE 16
+
+static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
+{
+	return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
+}
+
+/*
+  Allocate from a pool
+*/
+
+static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
+					      size_t size)
+{
+	struct talloc_chunk *pool_ctx = NULL;
+	size_t space_left;
+	struct talloc_chunk *result;
+	size_t chunk_size;
+
+	if (parent == NULL) {
+		return NULL;
+	}
+
+	if (parent->flags & TALLOC_FLAG_POOL) {
+		pool_ctx = parent;
+	}
+	else if (parent->flags & TALLOC_FLAG_POOLMEM) {
+		pool_ctx = (struct talloc_chunk *)parent->pool;
+	}
+
+	if (pool_ctx == NULL) {
+		return NULL;
+	}
+
+	space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
+		- ((char *)pool_ctx->pool);
+
+	/*
+	 * Align size to 16 bytes
+	 */
+	chunk_size = ((size + 15) & ~15);
+
+	if (space_left < chunk_size) {
+		return NULL;
+	}
+
+	result = (struct talloc_chunk *)pool_ctx->pool;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+	VALGRIND_MAKE_MEM_UNDEFINED(result, size);
+#endif
+
+	pool_ctx->pool = (void *)((char *)result + chunk_size);
+
+	result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
+	result->pool = pool_ctx;
+
+	*talloc_pool_objectcount(pool_ctx) += 1;
+
+	return result;
+}
+
+/* 
+   Allocate a bit of memory as a child of an existing pointer
+*/
+static inline void *__talloc(const void *context, size_t size)
+{
+	struct talloc_chunk *tc = NULL;
+
+	if (unlikely(context == NULL)) {
+		context = null_context;
+	}
+
+	if (unlikely(size >= MAX_TALLOC_SIZE)) {
+		return NULL;
+	}
+
+	if (context != NULL) {
+		tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
+				       TC_HDR_SIZE+size);
+	}
+
+	if (tc == NULL) {
+		tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
+		if (unlikely(tc == NULL)) return NULL;
+		tc->flags = TALLOC_MAGIC;
+		tc->pool  = NULL;
+	}
+
+	tc->size = size;
+	tc->destructor = NULL;
+	tc->child = NULL;
+	tc->name = NULL;
+	tc->refs = NULL;
+
+	if (likely(context)) {
+		struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
+
+		if (parent->child) {
+			parent->child->parent = NULL;
+			tc->next = parent->child;
+			tc->next->prev = tc;
+		} else {
+			tc->next = NULL;
+		}
+		tc->parent = parent;
+		tc->prev = NULL;
+		parent->child = tc;
+	} else {
+		tc->next = tc->prev = tc->parent = NULL;
+	}
+
+	return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+ * Create a talloc pool
+ */
+
+_PUBLIC_ void *talloc_pool(const void *context, size_t size)
+{
+	void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
+	struct talloc_chunk *tc;
+
+	if (unlikely(result == NULL)) {
+		return NULL;
+	}
+
+	tc = talloc_chunk_from_ptr(result);
+
+	tc->flags |= TALLOC_FLAG_POOL;
+	tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
+
+	*talloc_pool_objectcount(tc) = 1;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+	VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
+#endif
+
+	return result;
+}
+
+/*
+  setup a destructor to be called on free of a pointer
+  the destructor should return 0 on success, or -1 on failure.
+  if the destructor fails then the free is failed, and the memory can
+  be continued to be used
+*/
+_PUBLIC_ void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	tc->destructor = destructor;
+}
+
+/*
+  increase the reference count on a piece of memory. 
+*/
+_PUBLIC_ int talloc_increase_ref_count(const void *ptr)
+{
+	if (unlikely(!talloc_reference(null_context, ptr))) {
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  helper for talloc_reference()
+
+  this is referenced by a function pointer and should not be inline
+*/
+static int talloc_reference_destructor(struct talloc_reference_handle *handle)
+{
+	struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
+	_TLIST_REMOVE(ptr_tc->refs, handle);
+	return 0;
+}
+
+/*
+   more efficient way to add a name to a pointer - the name must point to a 
+   true string constant
+*/
+static inline void _talloc_set_name_const(const void *ptr, const char *name)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	tc->name = name;
+}
+
+/*
+  internal talloc_named_const()
+*/
+static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
+{
+	void *ptr;
+
+	ptr = __talloc(context, size);
+	if (unlikely(ptr == NULL)) {
+		return NULL;
+	}
+
+	_talloc_set_name_const(ptr, name);
+
+	return ptr;
+}
+
+/*
+  make a secondary reference to a pointer, hanging off the given context.
+  the pointer remains valid until both the original caller and this given
+  context are freed.
+  
+  the major use for this is when two different structures need to reference the 
+  same underlying data, and you want to be able to free the two instances separately,
+  and in either order
+*/
+_PUBLIC_ void *_talloc_reference_loc(const void *context, const void *ptr, const char *location)
+{
+	struct talloc_chunk *tc;
+	struct talloc_reference_handle *handle;
+	if (unlikely(ptr == NULL)) return NULL;
+
+	tc = talloc_chunk_from_ptr(ptr);
+	handle = (struct talloc_reference_handle *)_talloc_named_const(context,
+						   sizeof(struct talloc_reference_handle),
+						   TALLOC_MAGIC_REFERENCE);
+	if (unlikely(handle == NULL)) return NULL;
+
+	/* note that we hang the destructor off the handle, not the
+	   main context as that allows the caller to still setup their
+	   own destructor on the context if they want to */
+	talloc_set_destructor(handle, talloc_reference_destructor);
+	handle->ptr = discard_const_p(void, ptr);
+	handle->location = location;
+	_TLIST_ADD(tc->refs, handle);
+	return handle->ptr;
+}
+
+static void *_talloc_steal_internal(const void *new_ctx, const void *ptr);
+
+/* 
+   internal talloc_free call
+*/
+static inline int _talloc_free_internal(void *ptr, const char *location)
+{
+	struct talloc_chunk *tc;
+
+	if (unlikely(ptr == NULL)) {
+		return -1;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (unlikely(tc->refs)) {
+		int is_child;
+		/* check this is a reference from a child or grantchild
+		 * back to it's parent or grantparent
+		 *
+		 * in that case we need to remove the reference and
+		 * call another instance of talloc_free() on the current
+		 * pointer.
+		 */
+		is_child = talloc_is_parent(tc->refs, ptr);
+		_talloc_free_internal(tc->refs, location);
+		if (is_child) {
+			return _talloc_free_internal(ptr, location);
+		}
+		return -1;
+	}
+
+	if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
+		/* we have a free loop - stop looping */
+		return 0;
+	}
+
+	if (unlikely(tc->destructor)) {
+		talloc_destructor_t d = tc->destructor;
+		if (d == (talloc_destructor_t)-1) {
+			return -1;
+		}
+		tc->destructor = (talloc_destructor_t)-1;
+		if (d(ptr) == -1) {
+			tc->destructor = d;
+			return -1;
+		}
+		tc->destructor = NULL;
+	}
+
+	if (tc->parent) {
+		_TLIST_REMOVE(tc->parent->child, tc);
+		if (tc->parent->child) {
+			tc->parent->child->parent = tc->parent;
+		}
+	} else {
+		if (tc->prev) tc->prev->next = tc->next;
+		if (tc->next) tc->next->prev = tc->prev;
+	}
+
+	tc->flags |= TALLOC_FLAG_LOOP;
+
+	while (tc->child) {
+		/* we need to work out who will own an abandoned child
+		   if it cannot be freed. In priority order, the first
+		   choice is owner of any remaining reference to this
+		   pointer, the second choice is our parent, and the
+		   final choice is the null context. */
+		void *child = TC_PTR_FROM_CHUNK(tc->child);
+		const void *new_parent = null_context;
+		if (unlikely(tc->child->refs)) {
+			struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+			if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+		}
+		if (unlikely(_talloc_free_internal(child, location) == -1)) {
+			if (new_parent == null_context) {
+				struct talloc_chunk *p = talloc_parent_chunk(ptr);
+				if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+			}
+			_talloc_steal_internal(new_parent, child);
+		}
+	}
+
+	tc->flags |= TALLOC_FLAG_FREE;
+
+	/* we mark the freed memory with where we called the free
+	 * from. This means on a double free error we can report where
+	 * the first free came from
+	 */
+	tc->name = location;
+
+	if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
+		struct talloc_chunk *pool;
+		unsigned int *pool_object_count;
+
+		pool = (tc->flags & TALLOC_FLAG_POOL)
+			? tc : (struct talloc_chunk *)tc->pool;
+
+		pool_object_count = talloc_pool_objectcount(pool);
+
+		if (*pool_object_count == 0) {
+			talloc_abort("Pool object count zero!");
+			return 0;
+		}
+
+		*pool_object_count -= 1;
+
+		if (*pool_object_count == 0) {
+			free(pool);
+		}
+	}
+	else {
+		free(tc);
+	}
+	return 0;
+}
+
+/* 
+   move a lump of memory from one talloc context to another return the
+   ptr on success, or NULL if it could not be transferred.
+   passing NULL as ptr will always return NULL with no side effects.
+*/
+static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
+{
+	struct talloc_chunk *tc, *new_tc;
+
+	if (unlikely(!ptr)) {
+		return NULL;
+	}
+
+	if (unlikely(new_ctx == NULL)) {
+		new_ctx = null_context;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (unlikely(new_ctx == NULL)) {
+		if (tc->parent) {
+			_TLIST_REMOVE(tc->parent->child, tc);
+			if (tc->parent->child) {
+				tc->parent->child->parent = tc->parent;
+			}
+		} else {
+			if (tc->prev) tc->prev->next = tc->next;
+			if (tc->next) tc->next->prev = tc->prev;
+		}
+		
+		tc->parent = tc->next = tc->prev = NULL;
+		return discard_const_p(void, ptr);
+	}
+
+	new_tc = talloc_chunk_from_ptr(new_ctx);
+
+	if (unlikely(tc == new_tc || tc->parent == new_tc)) {
+		return discard_const_p(void, ptr);
+	}
+
+	if (tc->parent) {
+		_TLIST_REMOVE(tc->parent->child, tc);
+		if (tc->parent->child) {
+			tc->parent->child->parent = tc->parent;
+		}
+	} else {
+		if (tc->prev) tc->prev->next = tc->next;
+		if (tc->next) tc->next->prev = tc->prev;
+	}
+
+	tc->parent = new_tc;
+	if (new_tc->child) new_tc->child->parent = NULL;
+	_TLIST_ADD(new_tc->child, tc);
+
+	return discard_const_p(void, ptr);
+}
+
+/*
+   move a lump of memory from one talloc context to another return the
+   ptr on success, or NULL if it could not be transferred.
+   passing NULL as ptr will always return NULL with no side effects.
+*/
+_PUBLIC_ void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *location)
+{
+	struct talloc_chunk *tc;
+
+	if (unlikely(ptr == NULL)) {
+		return NULL;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) {
+		struct talloc_reference_handle *h;
+
+		talloc_log("WARNING: talloc_steal with references at %s\n",
+			   location);
+
+		for (h=tc->refs; h; h=h->next) {
+			talloc_log("\treference at %s\n",
+				   h->location);
+		}
+	}
+
+#if 0
+	/* this test is probably too expensive to have on in the
+	   normal build, but it useful for debugging */
+	if (talloc_is_parent(new_ctx, ptr)) {
+		talloc_log("WARNING: stealing into talloc child at %s\n", location);
+	}
+#endif
+
+	return _talloc_steal_internal(new_ctx, ptr);
+}
+
+/*
+   this is like a talloc_steal(), but you must supply the old
+   parent. This resolves the ambiguity in a talloc_steal() which is
+   called on a context that has more than one parent (via references)
+
+   The old parent can be either a reference or a parent
+*/
+_PUBLIC_ void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr)
+{
+	struct talloc_chunk *tc;
+	struct talloc_reference_handle *h;
+
+	if (unlikely(ptr == NULL)) {
+		return NULL;
+	}
+
+	if (old_parent == talloc_parent(ptr)) {
+		return _talloc_steal_internal(new_parent, ptr);
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+	for (h=tc->refs;h;h=h->next) {
+		if (talloc_parent(h) == old_parent) {
+			if (_talloc_steal_internal(new_parent, h) != h) {
+				return NULL;
+			}
+			return discard_const_p(void, ptr);
+		}
+	}
+
+	/* it wasn't a parent */
+	return NULL;
+}
+
+/*
+  remove a secondary reference to a pointer. This undo's what
+  talloc_reference() has done. The context and pointer arguments
+  must match those given to a talloc_reference()
+*/
+static inline int talloc_unreference(const void *context, const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	struct talloc_reference_handle *h;
+
+	if (unlikely(context == NULL)) {
+		context = null_context;
+	}
+
+	for (h=tc->refs;h;h=h->next) {
+		struct talloc_chunk *p = talloc_parent_chunk(h);
+		if (p == NULL) {
+			if (context == NULL) break;
+		} else if (TC_PTR_FROM_CHUNK(p) == context) {
+			break;
+		}
+	}
+	if (h == NULL) {
+		return -1;
+	}
+
+	return _talloc_free_internal(h, __location__);
+}
+
+/*
+  remove a specific parent context from a pointer. This is a more
+  controlled varient of talloc_free()
+*/
+_PUBLIC_ int talloc_unlink(const void *context, void *ptr)
+{
+	struct talloc_chunk *tc_p, *new_p;
+	void *new_parent;
+
+	if (ptr == NULL) {
+		return -1;
+	}
+
+	if (context == NULL) {
+		context = null_context;
+	}
+
+	if (talloc_unreference(context, ptr) == 0) {
+		return 0;
+	}
+
+	if (context == NULL) {
+		if (talloc_parent_chunk(ptr) != NULL) {
+			return -1;
+		}
+	} else {
+		if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
+			return -1;
+		}
+	}
+	
+	tc_p = talloc_chunk_from_ptr(ptr);
+
+	if (tc_p->refs == NULL) {
+		return _talloc_free_internal(ptr, __location__);
+	}
+
+	new_p = talloc_parent_chunk(tc_p->refs);
+	if (new_p) {
+		new_parent = TC_PTR_FROM_CHUNK(new_p);
+	} else {
+		new_parent = NULL;
+	}
+
+	if (talloc_unreference(new_parent, ptr) != 0) {
+		return -1;
+	}
+
+	_talloc_steal_internal(new_parent, ptr);
+
+	return 0;
+}
+
+/*
+  add a name to an existing pointer - va_list version
+*/
+static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	tc->name = talloc_vasprintf(ptr, fmt, ap);
+	if (likely(tc->name)) {
+		_talloc_set_name_const(tc->name, ".name");
+	}
+	return tc->name;
+}
+
+/*
+  add a name to an existing pointer
+*/
+_PUBLIC_ const char *talloc_set_name(const void *ptr, const char *fmt, ...)
+{
+	const char *name;
+	va_list ap;
+	va_start(ap, fmt);
+	name = talloc_set_name_v(ptr, fmt, ap);
+	va_end(ap);
+	return name;
+}
+
+
+/*
+  create a named talloc pointer. Any talloc pointer can be named, and
+  talloc_named() operates just like talloc() except that it allows you
+  to name the pointer.
+*/
+_PUBLIC_ void *talloc_named(const void *context, size_t size, const char *fmt, ...)
+{
+	va_list ap;
+	void *ptr;
+	const char *name;
+
+	ptr = __talloc(context, size);
+	if (unlikely(ptr == NULL)) return NULL;
+
+	va_start(ap, fmt);
+	name = talloc_set_name_v(ptr, fmt, ap);
+	va_end(ap);
+
+	if (unlikely(name == NULL)) {
+		_talloc_free_internal(ptr, __location__);
+		return NULL;
+	}
+
+	return ptr;
+}
+
+/*
+  return the name of a talloc ptr, or "UNNAMED"
+*/
+_PUBLIC_ const char *talloc_get_name(const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
+		return ".reference";
+	}
+	if (likely(tc->name)) {
+		return tc->name;
+	}
+	return "UNNAMED";
+}
+
+
+/*
+  check if a pointer has the given name. If it does, return the pointer,
+  otherwise return NULL
+*/
+_PUBLIC_ void *talloc_check_name(const void *ptr, const char *name)
+{
+	const char *pname;
+	if (unlikely(ptr == NULL)) return NULL;
+	pname = talloc_get_name(ptr);
+	if (likely(pname == name || strcmp(pname, name) == 0)) {
+		return discard_const_p(void, ptr);
+	}
+	return NULL;
+}
+
+static void talloc_abort_type_missmatch(const char *location,
+					const char *name,
+					const char *expected)
+{
+	const char *reason;
+
+	reason = talloc_asprintf(NULL,
+				 "%s: Type mismatch: name[%s] expected[%s]",
+				 location,
+				 name?name:"NULL",
+				 expected);
+	if (!reason) {
+		reason = "Type mismatch";
+	}
+
+	talloc_abort(reason);
+}
+
+_PUBLIC_ void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location)
+{
+	const char *pname;
+
+	if (unlikely(ptr == NULL)) {
+		talloc_abort_type_missmatch(location, NULL, name);
+		return NULL;
+	}
+
+	pname = talloc_get_name(ptr);
+	if (likely(pname == name || strcmp(pname, name) == 0)) {
+		return discard_const_p(void, ptr);
+	}
+
+	talloc_abort_type_missmatch(location, pname, name);
+	return NULL;
+}
+
+/*
+  this is for compatibility with older versions of talloc
+*/
+_PUBLIC_ void *talloc_init(const char *fmt, ...)
+{
+	va_list ap;
+	void *ptr;
+	const char *name;
+
+	/*
+	 * samba3 expects talloc_report_depth_cb(NULL, ...)
+	 * reports all talloc'ed memory, so we need to enable
+	 * null_tracking
+	 */
+	talloc_enable_null_tracking();
+
+	ptr = __talloc(NULL, 0);
+	if (unlikely(ptr == NULL)) return NULL;
+
+	va_start(ap, fmt);
+	name = talloc_set_name_v(ptr, fmt, ap);
+	va_end(ap);
+
+	if (unlikely(name == NULL)) {
+		_talloc_free_internal(ptr, __location__);
+		return NULL;
+	}
+
+	return ptr;
+}
+
+/*
+  this is a replacement for the Samba3 talloc_destroy_pool functionality. It
+  should probably not be used in new code. It's in here to keep the talloc
+  code consistent across Samba 3 and 4.
+*/
+_PUBLIC_ void talloc_free_children(void *ptr)
+{
+	struct talloc_chunk *tc;
+
+	if (unlikely(ptr == NULL)) {
+		return;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	while (tc->child) {
+		/* we need to work out who will own an abandoned child
+		   if it cannot be freed. In priority order, the first
+		   choice is owner of any remaining reference to this
+		   pointer, the second choice is our parent, and the
+		   final choice is the null context. */
+		void *child = TC_PTR_FROM_CHUNK(tc->child);
+		const void *new_parent = null_context;
+		if (unlikely(tc->child->refs)) {
+			struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+			if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+		}
+		if (unlikely(talloc_free(child) == -1)) {
+			if (new_parent == null_context) {
+				struct talloc_chunk *p = talloc_parent_chunk(ptr);
+				if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+			}
+			_talloc_steal_internal(new_parent, child);
+		}
+	}
+
+	if ((tc->flags & TALLOC_FLAG_POOL)
+	    && (*talloc_pool_objectcount(tc) == 1)) {
+		tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+		VALGRIND_MAKE_MEM_NOACCESS(
+			tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
+#endif
+	}
+}
+
+/* 
+   Allocate a bit of memory as a child of an existing pointer
+*/
+_PUBLIC_ void *_talloc(const void *context, size_t size)
+{
+	return __talloc(context, size);
+}
+
+/*
+  externally callable talloc_set_name_const()
+*/
+_PUBLIC_ void talloc_set_name_const(const void *ptr, const char *name)
+{
+	_talloc_set_name_const(ptr, name);
+}
+
+/*
+  create a named talloc pointer. Any talloc pointer can be named, and
+  talloc_named() operates just like talloc() except that it allows you
+  to name the pointer.
+*/
+_PUBLIC_ void *talloc_named_const(const void *context, size_t size, const char *name)
+{
+	return _talloc_named_const(context, size, name);
+}
+
+/* 
+   free a talloc pointer. This also frees all child pointers of this 
+   pointer recursively
+
+   return 0 if the memory is actually freed, otherwise -1. The memory
+   will not be freed if the ref_count is > 1 or the destructor (if
+   any) returns non-zero
+*/
+_PUBLIC_ int _talloc_free(void *ptr, const char *location)
+{
+	struct talloc_chunk *tc;
+
+	if (unlikely(ptr == NULL)) {
+		return -1;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (unlikely(tc->refs != NULL)) {
+		struct talloc_reference_handle *h;
+
+		if (talloc_parent(ptr) == null_context && tc->refs->next == NULL) {
+			/* in this case we do know which parent should
+			   get this pointer, as there is really only
+			   one parent */
+			return talloc_unlink(null_context, ptr);
+		}
+
+		talloc_log("ERROR: talloc_free with references at %s\n",
+			   location);
+
+		for (h=tc->refs; h; h=h->next) {
+			talloc_log("\treference at %s\n",
+				   h->location);
+		}
+		return -1;
+	}
+
+	return _talloc_free_internal(ptr, location);
+}
+
+
+
+/*
+  A talloc version of realloc. The context argument is only used if
+  ptr is NULL
+*/
+_PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
+{
+	struct talloc_chunk *tc;
+	void *new_ptr;
+	bool malloced = false;
+
+	/* size zero is equivalent to free() */
+	if (unlikely(size == 0)) {
+		talloc_unlink(context, ptr);
+		return NULL;
+	}
+
+	if (unlikely(size >= MAX_TALLOC_SIZE)) {
+		return NULL;
+	}
+
+	/* realloc(NULL) is equivalent to malloc() */
+	if (ptr == NULL) {
+		return _talloc_named_const(context, size, name);
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	/* don't allow realloc on referenced pointers */
+	if (unlikely(tc->refs)) {
+		return NULL;
+	}
+
+	/* don't let anybody try to realloc a talloc_pool */
+	if (unlikely(tc->flags & TALLOC_FLAG_POOL)) {
+		return NULL;
+	}
+
+	/* don't shrink if we have less than 1k to gain */
+	if ((size < tc->size) && ((tc->size - size) < 1024)) {
+		tc->size = size;
+		return ptr;
+	}
+
+	/* by resetting magic we catch users of the old memory */
+	tc->flags |= TALLOC_FLAG_FREE;
+
+#if ALWAYS_REALLOC
+	new_ptr = malloc(size + TC_HDR_SIZE);
+	if (new_ptr) {
+		memcpy(new_ptr, tc, MIN(tc->size, size) + TC_HDR_SIZE);
+		free(tc);
+	}
+#else
+	if (tc->flags & TALLOC_FLAG_POOLMEM) {
+
+		new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
+		*talloc_pool_objectcount((struct talloc_chunk *)
+					 (tc->pool)) -= 1;
+
+		if (new_ptr == NULL) {
+			new_ptr = malloc(TC_HDR_SIZE+size);
+			malloced = true;
+		}
+
+		if (new_ptr) {
+			memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
+		}
+	}
+	else {
+		new_ptr = realloc(tc, size + TC_HDR_SIZE);
+	}
+#endif
+	if (unlikely(!new_ptr)) {	
+		tc->flags &= ~TALLOC_FLAG_FREE; 
+		return NULL; 
+	}
+
+	tc = (struct talloc_chunk *)new_ptr;
+	tc->flags &= ~TALLOC_FLAG_FREE;
+	if (malloced) {
+		tc->flags &= ~TALLOC_FLAG_POOLMEM;
+	}
+	if (tc->parent) {
+		tc->parent->child = tc;
+	}
+	if (tc->child) {
+		tc->child->parent = tc;
+	}
+
+	if (tc->prev) {
+		tc->prev->next = tc;
+	}
+	if (tc->next) {
+		tc->next->prev = tc;
+	}
+
+	tc->size = size;
+	_talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
+
+	return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+  a wrapper around talloc_steal() for situations where you are moving a pointer
+  between two structures, and want the old pointer to be set to NULL
+*/
+_PUBLIC_ void *_talloc_move(const void *new_ctx, const void *_pptr)
+{
+	const void **pptr = discard_const_p(const void *,_pptr);
+	void *ret = talloc_steal(new_ctx, discard_const_p(void, *pptr));
+	(*pptr) = NULL;
+	return ret;
+}
+
+/*
+  return the total size of a talloc pool (subtree)
+*/
+_PUBLIC_ size_t talloc_total_size(const void *ptr)
+{
+	size_t total = 0;
+	struct talloc_chunk *c, *tc;
+
+	if (ptr == NULL) {
+		ptr = null_context;
+	}
+	if (ptr == NULL) {
+		return 0;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (tc->flags & TALLOC_FLAG_LOOP) {
+		return 0;
+	}
+
+	tc->flags |= TALLOC_FLAG_LOOP;
+
+	if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) {
+		total = tc->size;
+	}
+	for (c=tc->child;c;c=c->next) {
+		total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
+	}
+
+	tc->flags &= ~TALLOC_FLAG_LOOP;
+
+	return total;
+}
+
+/*
+  return the total number of blocks in a talloc pool (subtree)
+*/
+_PUBLIC_ size_t talloc_total_blocks(const void *ptr)
+{
+	size_t total = 0;
+	struct talloc_chunk *c, *tc;
+
+	if (ptr == NULL) {
+		ptr = null_context;
+	}
+	if (ptr == NULL) {
+		return 0;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (tc->flags & TALLOC_FLAG_LOOP) {
+		return 0;
+	}
+
+	tc->flags |= TALLOC_FLAG_LOOP;
+
+	total++;
+	for (c=tc->child;c;c=c->next) {
+		total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
+	}
+
+	tc->flags &= ~TALLOC_FLAG_LOOP;
+
+	return total;
+}
+
+/*
+  return the number of external references to a pointer
+*/
+_PUBLIC_ size_t talloc_reference_count(const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	struct talloc_reference_handle *h;
+	size_t ret = 0;
+
+	for (h=tc->refs;h;h=h->next) {
+		ret++;
+	}
+	return ret;
+}
+
+/*
+  report on memory usage by all children of a pointer, giving a full tree view
+*/
+_PUBLIC_ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+			    void (*callback)(const void *ptr,
+			  		     int depth, int max_depth,
+					     int is_ref,
+					     void *private_data),
+			    void *private_data)
+{
+	struct talloc_chunk *c, *tc;
+
+	if (ptr == NULL) {
+		ptr = null_context;
+	}
+	if (ptr == NULL) return;
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (tc->flags & TALLOC_FLAG_LOOP) {
+		return;
+	}
+
+	callback(ptr, depth, max_depth, 0, private_data);
+
+	if (max_depth >= 0 && depth >= max_depth) {
+		return;
+	}
+
+	tc->flags |= TALLOC_FLAG_LOOP;
+	for (c=tc->child;c;c=c->next) {
+		if (c->name == TALLOC_MAGIC_REFERENCE) {
+			struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
+			callback(h->ptr, depth + 1, max_depth, 1, private_data);
+		} else {
+			talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
+		}
+	}
+	tc->flags &= ~TALLOC_FLAG_LOOP;
+}
+
+static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
+{
+	const char *name = talloc_get_name(ptr);
+	FILE *f = (FILE *)_f;
+
+	if (is_ref) {
+		fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
+		return;
+	}
+
+	if (depth == 0) {
+		fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", 
+			(max_depth < 0 ? "full " :""), name,
+			(unsigned long)talloc_total_size(ptr),
+			(unsigned long)talloc_total_blocks(ptr));
+		return;
+	}
+
+	fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", 
+		depth*4, "",
+		name,
+		(unsigned long)talloc_total_size(ptr),
+		(unsigned long)talloc_total_blocks(ptr),
+		(int)talloc_reference_count(ptr), ptr);
+
+#if 0
+	fprintf(f, "content: ");
+	if (talloc_total_size(ptr)) {
+		int tot = talloc_total_size(ptr);
+		int i;
+
+		for (i = 0; i < tot; i++) {
+			if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
+				fprintf(f, "%c", ((char *)ptr)[i]);
+			} else {
+				fprintf(f, "~%02x", ((char *)ptr)[i]);
+			}
+		}
+	}
+	fprintf(f, "\n");
+#endif
+}
+
+/*
+  report on memory usage by all children of a pointer, giving a full tree view
+*/
+_PUBLIC_ void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
+{
+	if (f) {
+		talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
+		fflush(f);
+	}
+}
+
+/*
+  report on memory usage by all children of a pointer, giving a full tree view
+*/
+_PUBLIC_ void talloc_report_full(const void *ptr, FILE *f)
+{
+	talloc_report_depth_file(ptr, 0, -1, f);
+}
+
+/*
+  report on memory usage by all children of a pointer
+*/
+_PUBLIC_ void talloc_report(const void *ptr, FILE *f)
+{
+	talloc_report_depth_file(ptr, 0, 1, f);
+}
+
+/*
+  report on any memory hanging off the null context
+*/
+static void talloc_report_null(void)
+{
+	if (talloc_total_size(null_context) != 0) {
+		talloc_report(null_context, stderr);
+	}
+}
+
+/*
+  report on any memory hanging off the null context
+*/
+static void talloc_report_null_full(void)
+{
+	if (talloc_total_size(null_context) != 0) {
+		talloc_report_full(null_context, stderr);
+	}
+}
+
+/*
+  enable tracking of the NULL context
+*/
+_PUBLIC_ void talloc_enable_null_tracking(void)
+{
+	if (null_context == NULL) {
+		null_context = _talloc_named_const(NULL, 0, "null_context");
+		if (autofree_context != NULL) {
+			talloc_reparent(NULL, null_context, autofree_context);
+		}
+	}
+}
+
+/*
+  enable tracking of the NULL context, not moving the autofree context
+  into the NULL context. This is needed for the talloc testsuite
+*/
+_PUBLIC_ void talloc_enable_null_tracking_no_autofree(void)
+{
+	if (null_context == NULL) {
+		null_context = _talloc_named_const(NULL, 0, "null_context");
+	}
+}
+
+/*
+  disable tracking of the NULL context
+*/
+_PUBLIC_ void talloc_disable_null_tracking(void)
+{
+	if (null_context != NULL) {
+		/* we have to move any children onto the real NULL
+		   context */
+		struct talloc_chunk *tc, *tc2;
+		tc = talloc_chunk_from_ptr(null_context);
+		for (tc2 = tc->child; tc2; tc2=tc2->next) {
+			if (tc2->parent == tc) tc2->parent = NULL;
+			if (tc2->prev == tc) tc2->prev = NULL;
+		}
+		for (tc2 = tc->next; tc2; tc2=tc2->next) {
+			if (tc2->parent == tc) tc2->parent = NULL;
+			if (tc2->prev == tc) tc2->prev = NULL;
+		}
+		tc->child = NULL;
+		tc->next = NULL;
+	}
+	talloc_free(null_context);
+	null_context = NULL;
+}
+
+/*
+  enable leak reporting on exit
+*/
+_PUBLIC_ void talloc_enable_leak_report(void)
+{
+	talloc_enable_null_tracking();
+	atexit(talloc_report_null);
+}
+
+/*
+  enable full leak reporting on exit
+*/
+_PUBLIC_ void talloc_enable_leak_report_full(void)
+{
+	talloc_enable_null_tracking();
+	atexit(talloc_report_null_full);
+}
+
+/* 
+   talloc and zero memory. 
+*/
+_PUBLIC_ void *_talloc_zero(const void *ctx, size_t size, const char *name)
+{
+	void *p = _talloc_named_const(ctx, size, name);
+
+	if (p) {
+		memset(p, '\0', size);
+	}
+
+	return p;
+}
+
+/*
+  memdup with a talloc. 
+*/
+_PUBLIC_ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
+{
+	void *newp = _talloc_named_const(t, size, name);
+
+	if (likely(newp)) {
+		memcpy(newp, p, size);
+	}
+
+	return newp;
+}
+
+static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
+{
+	char *ret;
+
+	ret = (char *)__talloc(t, len + 1);
+	if (unlikely(!ret)) return NULL;
+
+	memcpy(ret, p, len);
+	ret[len] = 0;
+
+	_talloc_set_name_const(ret, ret);
+	return ret;
+}
+
+/*
+  strdup with a talloc
+*/
+_PUBLIC_ char *talloc_strdup(const void *t, const char *p)
+{
+	if (unlikely(!p)) return NULL;
+	return __talloc_strlendup(t, p, strlen(p));
+}
+
+/*
+  strndup with a talloc
+*/
+_PUBLIC_ char *talloc_strndup(const void *t, const char *p, size_t n)
+{
+	if (unlikely(!p)) return NULL;
+	return __talloc_strlendup(t, p, strnlen(p, n));
+}
+
+static inline char *__talloc_strlendup_append(char *s, size_t slen,
+					      const char *a, size_t alen)
+{
+	char *ret;
+
+	ret = talloc_realloc(NULL, s, char, slen + alen + 1);
+	if (unlikely(!ret)) return NULL;
+
+	/* append the string and the trailing \0 */
+	memcpy(&ret[slen], a, alen);
+	ret[slen+alen] = 0;
+
+	_talloc_set_name_const(ret, ret);
+	return ret;
+}
+
+/*
+ * Appends at the end of the string.
+ */
+_PUBLIC_ char *talloc_strdup_append(char *s, const char *a)
+{
+	if (unlikely(!s)) {
+		return talloc_strdup(NULL, a);
+	}
+
+	if (unlikely(!a)) {
+		return s;
+	}
+
+	return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
+}
+
+/*
+ * Appends at the end of the talloc'ed buffer,
+ * not the end of the string.
+ */
+_PUBLIC_ char *talloc_strdup_append_buffer(char *s, const char *a)
+{
+	size_t slen;
+
+	if (unlikely(!s)) {
+		return talloc_strdup(NULL, a);
+	}
+
+	if (unlikely(!a)) {
+		return s;
+	}
+
+	slen = talloc_get_size(s);
+	if (likely(slen > 0)) {
+		slen--;
+	}
+
+	return __talloc_strlendup_append(s, slen, a, strlen(a));
+}
+
+/*
+ * Appends at the end of the string.
+ */
+_PUBLIC_ char *talloc_strndup_append(char *s, const char *a, size_t n)
+{
+	if (unlikely(!s)) {
+		return talloc_strdup(NULL, a);
+	}
+
+	if (unlikely(!a)) {
+		return s;
+	}
+
+	return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
+}
+
+/*
+ * Appends at the end of the talloc'ed buffer,
+ * not the end of the string.
+ */
+_PUBLIC_ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
+{
+	size_t slen;
+
+	if (unlikely(!s)) {
+		return talloc_strdup(NULL, a);
+	}
+
+	if (unlikely(!a)) {
+		return s;
+	}
+
+	slen = talloc_get_size(s);
+	if (likely(slen > 0)) {
+		slen--;
+	}
+
+	return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
+}
+
+#ifndef HAVE_VA_COPY
+#ifdef HAVE___VA_COPY
+#define va_copy(dest, src) __va_copy(dest, src)
+#else
+#define va_copy(dest, src) (dest) = (src)
+#endif
+#endif
+
+_PUBLIC_ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
+{
+	int len;
+	char *ret;
+	va_list ap2;
+	char c;
+
+	/* this call looks strange, but it makes it work on older solaris boxes */
+	va_copy(ap2, ap);
+	len = vsnprintf(&c, 1, fmt, ap2);
+	va_end(ap2);
+	if (unlikely(len < 0)) {
+		return NULL;
+	}
+
+	ret = (char *)__talloc(t, len+1);
+	if (unlikely(!ret)) return NULL;
+
+	va_copy(ap2, ap);
+	vsnprintf(ret, len+1, fmt, ap2);
+	va_end(ap2);
+
+	_talloc_set_name_const(ret, ret);
+	return ret;
+}
+
+
+/*
+  Perform string formatting, and return a pointer to newly allocated
+  memory holding the result, inside a memory pool.
+ */
+_PUBLIC_ char *talloc_asprintf(const void *t, const char *fmt, ...)
+{
+	va_list ap;
+	char *ret;
+
+	va_start(ap, fmt);
+	ret = talloc_vasprintf(t, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+
+static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
+						 const char *fmt, va_list ap)
+						 PRINTF_ATTRIBUTE(3,0);
+
+static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
+						 const char *fmt, va_list ap)
+{
+	ssize_t alen;
+	va_list ap2;
+	char c;
+
+	va_copy(ap2, ap);
+	alen = vsnprintf(&c, 1, fmt, ap2);
+	va_end(ap2);
+
+	if (alen <= 0) {
+		/* Either the vsnprintf failed or the format resulted in
+		 * no characters being formatted. In the former case, we
+		 * ought to return NULL, in the latter we ought to return
+		 * the original string. Most current callers of this
+		 * function expect it to never return NULL.
+		 */
+		return s;
+	}
+
+	s = talloc_realloc(NULL, s, char, slen + alen + 1);
+	if (!s) return NULL;
+
+	va_copy(ap2, ap);
+	vsnprintf(s + slen, alen + 1, fmt, ap2);
+	va_end(ap2);
+
+	_talloc_set_name_const(s, s);
+	return s;
+}
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved.  Good for gradually
+ * accumulating output into a string buffer. Appends at the end
+ * of the string.
+ **/
+_PUBLIC_ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+{
+	if (unlikely(!s)) {
+		return talloc_vasprintf(NULL, fmt, ap);
+	}
+
+	return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
+}
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Always appends at the
+ * end of the talloc'ed buffer, not the end of the string.
+ **/
+_PUBLIC_ char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
+{
+	size_t slen;
+
+	if (unlikely(!s)) {
+		return talloc_vasprintf(NULL, fmt, ap);
+	}
+
+	slen = talloc_get_size(s);
+	if (likely(slen > 0)) {
+		slen--;
+	}
+
+	return __talloc_vaslenprintf_append(s, slen, fmt, ap);
+}
+
+/*
+  Realloc @p s to append the formatted result of @p fmt and return @p
+  s, which may have moved.  Good for gradually accumulating output
+  into a string buffer.
+ */
+_PUBLIC_ char *talloc_asprintf_append(char *s, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	s = talloc_vasprintf_append(s, fmt, ap);
+	va_end(ap);
+	return s;
+}
+
+/*
+  Realloc @p s to append the formatted result of @p fmt and return @p
+  s, which may have moved.  Good for gradually accumulating output
+  into a buffer.
+ */
+_PUBLIC_ char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	s = talloc_vasprintf_append_buffer(s, fmt, ap);
+	va_end(ap);
+	return s;
+}
+
+/*
+  alloc an array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+	if (count >= MAX_TALLOC_SIZE/el_size) {
+		return NULL;
+	}
+	return _talloc_named_const(ctx, el_size * count, name);
+}
+
+/*
+  alloc an zero array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+	if (count >= MAX_TALLOC_SIZE/el_size) {
+		return NULL;
+	}
+	return _talloc_zero(ctx, el_size * count, name);
+}
+
+/*
+  realloc an array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
+{
+	if (count >= MAX_TALLOC_SIZE/el_size) {
+		return NULL;
+	}
+	return _talloc_realloc(ctx, ptr, el_size * count, name);
+}
+
+/*
+  a function version of talloc_realloc(), so it can be passed as a function pointer
+  to libraries that want a realloc function (a realloc function encapsulates
+  all the basic capabilities of an allocation library, which is why this is useful)
+*/
+_PUBLIC_ void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
+{
+	return _talloc_realloc(context, ptr, size, NULL);
+}
+
+
+static int talloc_autofree_destructor(void *ptr)
+{
+	autofree_context = NULL;
+	return 0;
+}
+
+static void talloc_autofree(void)
+{
+	talloc_free(autofree_context);
+}
+
+/*
+  return a context which will be auto-freed on exit
+  this is useful for reducing the noise in leak reports
+*/
+_PUBLIC_ void *talloc_autofree_context(void)
+{
+	if (autofree_context == NULL) {
+		autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
+		talloc_set_destructor(autofree_context, talloc_autofree_destructor);
+		atexit(talloc_autofree);
+	}
+	return autofree_context;
+}
+
+_PUBLIC_ size_t talloc_get_size(const void *context)
+{
+	struct talloc_chunk *tc;
+
+	if (context == NULL) {
+		context = null_context;
+	}
+	if (context == NULL) {
+		return 0;
+	}
+
+	tc = talloc_chunk_from_ptr(context);
+
+	return tc->size;
+}
+
+/*
+  find a parent of this context that has the given name, if any
+*/
+_PUBLIC_ void *talloc_find_parent_byname(const void *context, const char *name)
+{
+	struct talloc_chunk *tc;
+
+	if (context == NULL) {
+		return NULL;
+	}
+
+	tc = talloc_chunk_from_ptr(context);
+	while (tc) {
+		if (tc->name && strcmp(tc->name, name) == 0) {
+			return TC_PTR_FROM_CHUNK(tc);
+		}
+		while (tc && tc->prev) tc = tc->prev;
+		if (tc) {
+			tc = tc->parent;
+		}
+	}
+	return NULL;
+}
+
+/*
+  show the parentage of a context
+*/
+_PUBLIC_ void talloc_show_parents(const void *context, FILE *file)
+{
+	struct talloc_chunk *tc;
+
+	if (context == NULL) {
+		fprintf(file, "talloc no parents for NULL\n");
+		return;
+	}
+
+	tc = talloc_chunk_from_ptr(context);
+	fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
+	while (tc) {
+		fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
+		while (tc && tc->prev) tc = tc->prev;
+		if (tc) {
+			tc = tc->parent;
+		}
+	}
+	fflush(file);
+}
+
+/*
+  return 1 if ptr is a parent of context
+*/
+static int _talloc_is_parent(const void *context, const void *ptr, int depth)
+{
+	struct talloc_chunk *tc;
+
+	if (context == NULL) {
+		return 0;
+	}
+
+	tc = talloc_chunk_from_ptr(context);
+	while (tc && depth > 0) {
+		if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
+		while (tc && tc->prev) tc = tc->prev;
+		if (tc) {
+			tc = tc->parent;
+			depth--;
+		}
+	}
+	return 0;
+}
+
+/*
+  return 1 if ptr is a parent of context
+*/
+_PUBLIC_ int talloc_is_parent(const void *context, const void *ptr)
+{
+	return _talloc_is_parent(context, ptr, TALLOC_MAX_DEPTH);
+}

Added: branches/ctdb/squeeze-backports/lib/talloc/talloc.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/talloc.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/talloc.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1695 @@
+#ifndef _TALLOC_H_
+#define _TALLOC_H_
+/* 
+   Unix SMB/CIFS implementation.
+   Samba temporary memory allocation functions
+
+   Copyright (C) Andrew Tridgell 2004-2005
+   Copyright (C) Stefan Metzmacher 2006
+   
+     ** NOTE! The following LGPL license applies to the talloc
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+/**
+ * @defgroup talloc The talloc API
+ *
+ * talloc is a hierarchical, reference counted memory pool system with
+ * destructors. It is the core memory allocator used in Samba.
+ *
+ * @{
+ */
+
+#define TALLOC_VERSION_MAJOR 2
+#define TALLOC_VERSION_MINOR 0
+
+int talloc_version_major(void);
+int talloc_version_minor(void);
+
+/**
+ * @brief Define a talloc parent type
+ *
+ * As talloc is a hierarchial memory allocator, every talloc chunk is a
+ * potential parent to other talloc chunks. So defining a separate type for a
+ * talloc chunk is not strictly necessary. TALLOC_CTX is defined nevertheless,
+ * as it provides an indicator for function arguments. You will frequently
+ * write code like
+ *
+ * @code
+ *      struct foo *foo_create(TALLOC_CTX *mem_ctx)
+ *      {
+ *              struct foo *result;
+ *              result = talloc(mem_ctx, struct foo);
+ *              if (result == NULL) return NULL;
+ *                      ... initialize foo ...
+ *              return result;
+ *      }
+ * @endcode
+ *
+ * In this type of allocating functions it is handy to have a general
+ * TALLOC_CTX type to indicate which parent to put allocated structures on.
+ */
+typedef void TALLOC_CTX;
+
+/*
+  this uses a little trick to allow __LINE__ to be stringified
+*/
+#ifndef __location__
+#define __TALLOC_STRING_LINE1__(s)    #s
+#define __TALLOC_STRING_LINE2__(s)   __TALLOC_STRING_LINE1__(s)
+#define __TALLOC_STRING_LINE3__  __TALLOC_STRING_LINE2__(__LINE__)
+#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
+#endif
+
+#ifndef TALLOC_DEPRECATED
+#define TALLOC_DEPRECATED 0
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns.  a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a new talloc context.
+ *
+ * The talloc() macro is the core of the talloc library. It takes a memory
+ * context and a type, and returns a pointer to a new area of memory of the
+ * given type.
+ *
+ * The returned pointer is itself a talloc context, so you can use it as the
+ * context argument to more calls to talloc if you wish.
+ *
+ * The returned pointer is a "child" of the supplied context. This means that if
+ * you talloc_free() the context then the new child disappears as well.
+ * Alternatively you can free just the child.
+ *
+ * @param[in]  ctx      A talloc context to create a new reference on or NULL to
+ *                      create a new top level context.
+ *
+ * @param[in]  type     The type of memory to allocate.
+ *
+ * @return              A type casted talloc context or NULL on error.
+ *
+ * @code
+ *      unsigned int *a, *b;
+ *
+ *      a = talloc(NULL, unsigned int);
+ *      b = talloc(a, unsigned int);
+ * @endcode
+ *
+ * @see talloc_zero
+ * @see talloc_array
+ * @see talloc_steal
+ * @see talloc_free
+ */
+void *talloc(const void *ctx, #type);
+#else
+#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+void *_talloc(const void *context, size_t size);
+#endif
+
+/**
+ * @brief Create a new top level talloc context.
+ *
+ * This function creates a zero length named talloc context as a top level
+ * context. It is equivalent to:
+ *
+ * @code
+ *      talloc_named(NULL, 0, fmt, ...);
+ * @endcode
+ * @param[in]  fmt      Format string for the name.
+ *
+ * @param[in]  ...      Additional printf-style arguments.
+ *
+ * @return              The allocated memory chunk, NULL on error.
+ *
+ * @see talloc_named()
+ */
+void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+
+#ifdef DOXYGEN
+/**
+ * @brief Free a chunk of talloc memory.
+ *
+ * The talloc_free() function frees a piece of talloc memory, and all its
+ * children. You can call talloc_free() on any pointer returned by
+ * talloc().
+ *
+ * The return value of talloc_free() indicates success or failure, with 0
+ * returned for success and -1 for failure. A possible failure condition
+ * is if the pointer had a destructor attached to it and the destructor
+ * returned -1. See talloc_set_destructor() for details on
+ * destructors. Likewise, if "ptr" is NULL, then the function will make
+ * no modifications and return -1.
+ *
+ * If this pointer has an additional parent when talloc_free() is called
+ * then the memory is not actually released, but instead the most
+ * recently established parent is destroyed. See talloc_reference() for
+ * details on establishing additional parents.
+ *
+ * For more control on which parent is removed, see talloc_unlink()
+ *
+ * talloc_free() operates recursively on its children.
+ *
+ * From the 2.0 version of talloc, as a special case, talloc_free() is
+ * refused on pointers that have more than one parent, as talloc would
+ * have no way of knowing which parent should be removed. To free a
+ * pointer that has more than one parent please use talloc_unlink().
+ *
+ * To help you find problems in your code caused by this behaviour, if
+ * you do try and free a pointer with more than one parent then the
+ * talloc logging function will be called to give output like this:
+ *
+ * @code
+ *   ERROR: talloc_free with references at some_dir/source/foo.c:123
+ *     reference at some_dir/source/other.c:325
+ *     reference at some_dir/source/third.c:121
+ * @endcode
+ *
+ * Please see the documentation for talloc_set_log_fn() and
+ * talloc_set_log_stderr() for more information on talloc logging
+ * functions.
+ *
+ * @param[in]  ptr      The chunk to be freed.
+ *
+ * @return              Returns 0 on success and -1 on error. A possible
+ *                      failure condition is if the pointer had a destructor
+ *                      attached to it and the destructor returned -1. Likewise,
+ *                      if "ptr" is NULL, then the function will make no
+ *                      modifications and returns -1.
+ *
+ * Example:
+ * @code
+ *      unsigned int *a, *b;
+ *      a = talloc(NULL, unsigned int);
+ *      b = talloc(a, unsigned int);
+ *
+ *      talloc_free(a); // Frees a and b
+ * @endcode
+ *
+ * @see talloc_set_destructor()
+ * @see talloc_unlink()
+ */
+int talloc_free(void *ptr);
+#else
+#define talloc_free(ctx) _talloc_free(ctx, __location__)
+int _talloc_free(void *ptr, const char *location);
+#endif
+
+/**
+ * @brief Free a talloc chunk's children.
+ *
+ * The function walks along the list of all children of a talloc context and
+ * talloc_free()s only the children, not the context itself.
+ *
+ * @param[in]  ptr      The chunk that you want to free the children of.
+ */
+void talloc_free_children(void *ptr);
+
+#ifdef DOXYGEN
+/**
+ * @brief Assign a destructor function to be called when a chunk is freed.
+ *
+ * The function talloc_set_destructor() sets the "destructor" for the pointer
+ * "ptr". A destructor is a function that is called when the memory used by a
+ * pointer is about to be released. The destructor receives the pointer as an
+ * argument, and should return 0 for success and -1 for failure.
+ *
+ * The destructor can do anything it wants to, including freeing other pieces
+ * of memory. A common use for destructors is to clean up operating system
+ * resources (such as open file descriptors) contained in the structure the
+ * destructor is placed on.
+ *
+ * You can only place one destructor on a pointer. If you need more than one
+ * destructor then you can create a zero-length child of the pointer and place
+ * an additional destructor on that.
+ *
+ * To remove a destructor call talloc_set_destructor() with NULL for the
+ * destructor.
+ *
+ * If your destructor attempts to talloc_free() the pointer that it is the
+ * destructor for then talloc_free() will return -1 and the free will be
+ * ignored. This would be a pointless operation anyway, as the destructor is
+ * only called when the memory is just about to go away.
+ *
+ * @param[in]  ptr      The talloc chunk to add a destructor to.
+ *
+ * @param[in]  destructor  The destructor function to be called. NULL to remove
+ *                         it.
+ *
+ * Example:
+ * @code
+ *      static int destroy_fd(int *fd) {
+ *              close(*fd);
+ *              return 0;
+ *      }
+ *
+ *      int *open_file(const char *filename) {
+ *              int *fd = talloc(NULL, int);
+ *              *fd = open(filename, O_RDONLY);
+ *              if (*fd < 0) {
+ *                      talloc_free(fd);
+ *                      return NULL;
+ *              }
+ *              // Whenever they free this, we close the file.
+ *              talloc_set_destructor(fd, destroy_fd);
+ *              return fd;
+ *      }
+ * @endcode
+ *
+ * @see talloc()
+ * @see talloc_free()
+ */
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+
+/**
+ * @brief Change a talloc chunk's parent.
+ *
+ * The talloc_steal() function changes the parent context of a talloc
+ * pointer. It is typically used when the context that the pointer is
+ * currently a child of is going to be freed and you wish to keep the
+ * memory for a longer time.
+ *
+ * To make the changed hierarchy less error-prone, you might consider to use
+ * talloc_move().
+ *
+ * If you try and call talloc_steal() on a pointer that has more than one
+ * parent then the result is ambiguous. Talloc will choose to remove the
+ * parent that is currently indicated by talloc_parent() and replace it with
+ * the chosen parent. You will also get a message like this via the talloc
+ * logging functions:
+ *
+ * @code
+ *   WARNING: talloc_steal with references at some_dir/source/foo.c:123
+ *     reference at some_dir/source/other.c:325
+ *     reference at some_dir/source/third.c:121
+ * @endcode
+ *
+ * To unambiguously change the parent of a pointer please see the function
+ * talloc_reparent(). See the talloc_set_log_fn() documentation for more
+ * information on talloc logging.
+ *
+ * @param[in]  new_ctx  The new parent context.
+ *
+ * @param[in]  ptr      The talloc chunk to move.
+ *
+ * @return              Returns the pointer that you pass it. It does not have
+ *                      any failure modes.
+ *
+ * @note It is possible to produce loops in the parent/child relationship
+ * if you are not careful with talloc_steal(). No guarantees are provided
+ * as to your sanity or the safety of your data if you do this.
+ */
+void *talloc_steal(const void *new_ctx, const void *ptr);
+#else /* DOXYGEN */
+/* try to make talloc_set_destructor() and talloc_steal() type safe,
+   if we have a recent gcc */
+#if (__GNUC__ >= 3)
+#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
+#define talloc_set_destructor(ptr, function)				      \
+	do {								      \
+		int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function);	      \
+		_talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \
+	} while(0)
+/* this extremely strange macro is to avoid some braindamaged warning
+   stupidity in gcc 4.1.x */
+#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal_loc((ctx),(ptr), __location__); __talloc_steal_ret; })
+#else /* __GNUC__ >= 3 */
+#define talloc_set_destructor(ptr, function) \
+	_talloc_set_destructor((ptr), (int (*)(void *))(function))
+#define _TALLOC_TYPEOF(ptr) void *
+#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal_loc((ctx),(ptr), __location__)
+#endif /* __GNUC__ >= 3 */
+void _talloc_set_destructor(const void *ptr, int (*_destructor)(void *));
+void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *location);
+#endif /* DOXYGEN */
+
+/**
+ * @brief Assign a name to a talloc chunk.
+ *
+ * Each talloc pointer has a "name". The name is used principally for
+ * debugging purposes, although it is also possible to set and get the name on
+ * a pointer in as a way of "marking" pointers in your code.
+ *
+ * The main use for names on pointer is for "talloc reports". See
+ * talloc_report() and talloc_report_full() for details. Also see
+ * talloc_enable_leak_report() and talloc_enable_leak_report_full().
+ *
+ * The talloc_set_name() function allocates memory as a child of the
+ * pointer. It is logically equivalent to:
+ *
+ * @code
+ *      talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));
+ * @endcode
+ *
+ * @param[in]  ptr      The talloc chunk to assign a name to.
+ *
+ * @param[in]  fmt      Format string for the name.
+ *
+ * @param[in]  ...      Add printf-style additional arguments.
+ *
+ * @return              The assigned name, NULL on error.
+ *
+ * @note Multiple calls to talloc_set_name() will allocate more memory without
+ * releasing the name. All of the memory is released when the ptr is freed
+ * using talloc_free().
+ */
+const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+#ifdef DOXYGEN
+/**
+ * @brief Change a talloc chunk's parent.
+ *
+ * This function has the same effect as talloc_steal(), and additionally sets
+ * the source pointer to NULL. You would use it like this:
+ *
+ * @code
+ *      struct foo *X = talloc(tmp_ctx, struct foo);
+ *      struct foo *Y;
+ *      Y = talloc_move(new_ctx, &X);
+ * @endcode
+ *
+ * @param[in]  new_ctx  The new parent context.
+ *
+ * @param[in]  ptr      Pointer to the talloc chunk to move.
+ *
+ * @return              The pointer of the talloc chunk it has been moved to,
+ *                      NULL on error.
+ */
+void *talloc_move(const void *new_ctx, const void *ptr);
+#else
+#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
+void *_talloc_move(const void *new_ctx, const void *pptr);
+#endif
+
+/**
+ * @brief Assign a name to a talloc chunk.
+ *
+ * The function is just like talloc_set_name(), but it takes a string constant,
+ * and is much faster. It is extensively used by the "auto naming" macros, such
+ * as talloc_p().
+ *
+ * This function does not allocate any memory. It just copies the supplied
+ * pointer into the internal representation of the talloc ptr. This means you
+ * must not pass a name pointer to memory that will disappear before the ptr
+ * is freed with talloc_free().
+ *
+ * @param[in]  ptr      The talloc chunk to assign a name to.
+ *
+ * @param[in]  name     Format string for the name.
+ */
+void talloc_set_name_const(const void *ptr, const char *name);
+
+/**
+ * @brief Create a named talloc chunk.
+ *
+ * The talloc_named() function creates a named talloc pointer. It is
+ * equivalent to:
+ *
+ * @code
+ *      ptr = talloc_size(context, size);
+ *      talloc_set_name(ptr, fmt, ....);
+ * @endcode
+ *
+ * @param[in]  context  The talloc context to hang the result off.
+ *
+ * @param[in]  size     Number of char's that you want to allocate.
+ *
+ * @param[in]  fmt      Format string for the name.
+ *
+ * @param[in]  ...      Additional printf-style arguments.
+ *
+ * @return              The allocated memory chunk, NULL on error.
+ *
+ * @see talloc_set_name()
+ */
+void *talloc_named(const void *context, size_t size,
+		   const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+/**
+ * @brief Basic routine to allocate a chunk of memory.
+ *
+ * This is equivalent to:
+ *
+ * @code
+ *      ptr = talloc_size(context, size);
+ *      talloc_set_name_const(ptr, name);
+ * @endcode
+ *
+ * @param[in]  context  The parent context.
+ *
+ * @param[in]  size     The number of char's that we want to allocate.
+ *
+ * @param[in]  name     The name the talloc block has.
+ *
+ * @return             The allocated memory chunk, NULL on error.
+ */
+void *talloc_named_const(const void *context, size_t size, const char *name);
+
+#ifdef DOXYGEN
+/**
+ * @brief Untyped allocation.
+ *
+ * The function should be used when you don't have a convenient type to pass to
+ * talloc(). Unlike talloc(), it is not type safe (as it returns a void *), so
+ * you are on your own for type checking.
+ *
+ * Best to use talloc() or talloc_array() instead.
+ *
+ * @param[in]  ctx     The talloc context to hang the result off.
+ *
+ * @param[in]  size    Number of char's that you want to allocate.
+ *
+ * @return             The allocated memory chunk, NULL on error.
+ *
+ * Example:
+ * @code
+ *      void *mem = talloc_size(NULL, 100);
+ * @endcode
+ */
+void *talloc_size(const void *ctx, size_t size);
+#else
+#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate into a typed pointer.
+ *
+ * The talloc_ptrtype() macro should be used when you have a pointer and want
+ * to allocate memory to point at with this pointer. When compiling with
+ * gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size() and
+ * talloc_get_name() will return the current location in the source file and
+ * not the type.
+ *
+ * @param[in]  ctx      The talloc context to hang the result off.
+ *
+ * @param[in]  type     The pointer you want to assign the result to.
+ *
+ * @return              The properly casted allocated memory chunk, NULL on
+ *                      error.
+ *
+ * Example:
+ * @code
+ *       unsigned int *a = talloc_ptrtype(NULL, a);
+ * @endcode
+ */
+void *talloc_ptrtype(const void *ctx, #type);
+#else
+#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a new 0-sized talloc chunk.
+ *
+ * This is a utility macro that creates a new memory context hanging off an
+ * existing context, automatically naming it "talloc_new: __location__" where
+ * __location__ is the source line it is called from. It is particularly
+ * useful for creating a new temporary working context.
+ *
+ * @param[in]  ctx      The talloc parent context.
+ *
+ * @return              A new talloc chunk, NULL on error.
+ */
+void *talloc_new(const void *ctx);
+#else
+#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a 0-initizialized structure.
+ *
+ * The macro is equivalent to:
+ *
+ * @code
+ *      ptr = talloc(ctx, type);
+ *      if (ptr) memset(ptr, 0, sizeof(type));
+ * @endcode
+ *
+ * @param[in]  ctx      The talloc context to hang the result off.
+ *
+ * @param[in]  type     The type that we want to allocate.
+ *
+ * @return              Pointer to a piece of memory, properly cast to 'type *',
+ *                      NULL on error.
+ *
+ * Example:
+ * @code
+ *      unsigned int *a, *b;
+ *      a = talloc_zero(NULL, unsigned int);
+ *      b = talloc_zero(a, unsigned int);
+ * @endcode
+ *
+ * @see talloc()
+ * @see talloc_zero_size()
+ * @see talloc_zero_array()
+ */
+void *talloc_zero(const void *ctx, #type);
+
+/**
+ * @brief Allocate untyped, 0-initialized memory.
+ *
+ * @param[in]  ctx      The talloc context to hang the result off.
+ *
+ * @param[in]  size     Number of char's that you want to allocate.
+ *
+ * @return              The allocated memory chunk.
+ */
+void *talloc_zero_size(const void *ctx, size_t size);
+#else
+#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
+void *_talloc_zero(const void *ctx, size_t size, const char *name);
+#endif
+
+/**
+ * @brief Return the name of a talloc chunk.
+ *
+ * @param[in]  ptr      The talloc chunk.
+ *
+ * @return              The current name for the given talloc pointer.
+ *
+ * @see talloc_set_name()
+ */
+const char *talloc_get_name(const void *ptr);
+
+/**
+ * @brief Verify that a talloc chunk carries a specified name.
+ *
+ * This function checks if a pointer has the specified name. If it does
+ * then the pointer is returned.
+ *
+ * @param[in]  ptr       The talloc chunk to check.
+ *
+ * @param[in]  name      The name to check against.
+ *
+ * @return               The pointer if the name matches, NULL if it doesn't.
+ */
+void *talloc_check_name(const void *ptr, const char *name);
+
+/**
+ * @brief Get the parent chunk of a pointer.
+ *
+ * @param[in]  ptr      The talloc pointer to inspect.
+ *
+ * @return              The talloc parent of ptr, NULL on error.
+ */
+void *talloc_parent(const void *ptr);
+
+/**
+ * @brief Get a talloc chunk's parent name.
+ *
+ * @param[in]  ptr      The talloc pointer to inspect.
+ *
+ * @return              The name of ptr's parent chunk.
+ */
+const char *talloc_parent_name(const void *ptr);
+
+/**
+ * @brief Get the total size of a talloc chunk including its children.
+ *
+ * The function returns the total size in bytes used by this pointer and all
+ * child pointers. Mostly useful for debugging.
+ *
+ * Passing NULL is allowed, but it will only give a meaningful result if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+ * been called.
+ *
+ * @param[in]  ptr      The talloc chunk.
+ *
+ * @return              The total size.
+ */
+size_t talloc_total_size(const void *ptr);
+
+/**
+ * @brief Get the number of talloc chunks hanging off a chunk.
+ *
+ * The talloc_total_blocks() function returns the total memory block
+ * count used by this pointer and all child pointers. Mostly useful for
+ * debugging.
+ *
+ * Passing NULL is allowed, but it will only give a meaningful result if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+ * been called.
+ *
+ * @param[in]  ptr      The talloc chunk.
+ *
+ * @return              The total size.
+ */
+size_t talloc_total_blocks(const void *ptr);
+
+#ifdef DOXYGEN
+/**
+ * @brief Duplicate a memory area into a talloc chunk.
+ *
+ * The function is equivalent to:
+ *
+ * @code
+ *      ptr = talloc_size(ctx, size);
+ *      if (ptr) memcpy(ptr, p, size);
+ * @endcode
+ *
+ * @param[in]  t        The talloc context to hang the result off.
+ *
+ * @param[in]  p        The memory chunk you want to duplicate.
+ *
+ * @param[in]  size     Number of char's that you want copy.
+ *
+ * @return              The allocated memory chunk.
+ *
+ * @see talloc_size()
+ */
+void *talloc_memdup(const void *t, const void *p, size_t size);
+#else
+#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Assign a type to a talloc chunk.
+ *
+ * This macro allows you to force the name of a pointer to be a particular type.
+ * This can be used in conjunction with talloc_get_type() to do type checking on
+ * void* pointers.
+ *
+ * It is equivalent to this:
+ *
+ * @code
+ *      talloc_set_name_const(ptr, #type)
+ * @endcode
+ *
+ * @param[in]  ptr      The talloc chunk to assign the type to.
+ *
+ * @param[in]  type     The type to assign.
+ */
+void talloc_set_type(const char *ptr, #type);
+
+/**
+ * @brief Get a typed pointer out of a talloc pointer.
+ *
+ * This macro allows you to do type checking on talloc pointers. It is
+ * particularly useful for void* private pointers. It is equivalent to
+ * this:
+ *
+ * @code
+ *      (type *)talloc_check_name(ptr, #type)
+ * @endcode
+ *
+ * @param[in]  ptr      The talloc pointer to check.
+ *
+ * @param[in]  type     The type to check against.
+ *
+ * @return              The properly casted pointer given by ptr, NULL on error.
+ */
+type *talloc_get_type(const void *ptr, #type);
+#else
+#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
+#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Safely turn a void pointer into a typed pointer.
+ *
+ * This macro is used together with talloc(mem_ctx, struct foo). If you had to
+ * assing the talloc chunk pointer to some void pointer variable,
+ * talloc_get_type_abort() is the recommended way to get the convert the void
+ * pointer back to a typed pointer.
+ *
+ * @param[in]  ptr      The void pointer to convert.
+ *
+ * @param[in]  type     The type that this chunk contains
+ *
+ * @return              The same value as ptr, type-checked and properly cast.
+ */
+void *talloc_get_type_abort(const void *ptr, #type);
+#else
+#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__)
+void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location);
+#endif
+
+/**
+ * @brief Find a parent context by name.
+ *
+ * Find a parent memory context of the current context that has the given
+ * name. This can be very useful in complex programs where it may be
+ * difficult to pass all information down to the level you need, but you
+ * know the structure you want is a parent of another context.
+ *
+ * @param[in]  ctx      The talloc chunk to start from.
+ *
+ * @param[in]  name     The name of the parent we look for.
+ *
+ * @return              The memory context we are looking for, NULL if not
+ *                      found.
+ */
+void *talloc_find_parent_byname(const void *ctx, const char *name);
+
+#ifdef DOXYGEN
+/**
+ * @brief Find a parent context by type.
+ *
+ * Find a parent memory context of the current context that has the given
+ * name. This can be very useful in complex programs where it may be
+ * difficult to pass all information down to the level you need, but you
+ * know the structure you want is a parent of another context.
+ *
+ * Like talloc_find_parent_byname() but takes a type, making it typesafe.
+ *
+ * @param[in]  ptr      The talloc chunk to start from.
+ *
+ * @param[in]  type     The type of the parent to look for.
+ *
+ * @return              The memory context we are looking for, NULL if not
+ *                      found.
+ */
+void *talloc_find_parent_bytype(const void *ptr, #type);
+#else
+#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
+#endif
+
+/**
+ * @brief Allocate a talloc pool.
+ *
+ * A talloc pool is a pure optimization for specific situations. In the
+ * release process for Samba 3.2 we found out that we had become considerably
+ * slower than Samba 3.0 was. Profiling showed that malloc(3) was a large CPU
+ * consumer in benchmarks. For Samba 3.2 we have internally converted many
+ * static buffers to dynamically allocated ones, so malloc(3) being beaten
+ * more was no surprise. But it made us slower.
+ *
+ * talloc_pool() is an optimization to call malloc(3) a lot less for the use
+ * pattern Samba has: The SMB protocol is mainly a request/response protocol
+ * where we have to allocate a certain amount of memory per request and free
+ * that after the SMB reply is sent to the client.
+ *
+ * talloc_pool() creates a talloc chunk that you can use as a talloc parent
+ * exactly as you would use any other ::TALLOC_CTX. The difference is that
+ * when you talloc a child of this pool, no malloc(3) is done. Instead, talloc
+ * just increments a pointer inside the talloc_pool. This also works
+ * recursively. If you use the child of the talloc pool as a parent for
+ * grand-children, their memory is also taken from the talloc pool.
+ *
+ * If you talloc_free() children of a talloc pool, the memory is not given
+ * back to the system. Instead, free(3) is only called if the talloc_pool()
+ * itself is released with talloc_free().
+ *
+ * The downside of a talloc pool is that if you talloc_move() a child of a
+ * talloc pool to a talloc parent outside the pool, the whole pool memory is
+ * not free(3)'ed until that moved chunk is also talloc_free()ed.
+ *
+ * @param[in]  context  The talloc context to hang the result off.
+ *
+ * @param[in]  size     Size of the talloc pool.
+ *
+ * @return              The allocated talloc pool, NULL on error.
+ */
+void *talloc_pool(const void *context, size_t size);
+
+/**
+ * @brief Free a talloc chunk and NULL out the pointer.
+ *
+ * TALLOC_FREE() frees a pointer and sets it to NULL. Use this if you want
+ * immediate feedback (i.e. crash) if you use a pointer after having free'ed
+ * it.
+ *
+ * @param[in]  ctx      The chunk to be freed.
+ */
+#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
+
+/* @} ******************************************************************/
+
+/**
+ * \defgroup talloc_ref The talloc reference function.
+ * @ingroup talloc
+ *
+ * This module contains the definitions around talloc references
+ *
+ * @{
+ */
+
+/**
+ * @brief Increase the reference count of a talloc chunk.
+ *
+ * The talloc_increase_ref_count(ptr) function is exactly equivalent to:
+ *
+ * @code
+ *      talloc_reference(NULL, ptr);
+ * @endcode
+ *
+ * You can use either syntax, depending on which you think is clearer in
+ * your code.
+ *
+ * @param[in]  ptr      The pointer to increase the reference count.
+ *
+ * @return              0 on success, -1 on error.
+ */
+int talloc_increase_ref_count(const void *ptr);
+
+/**
+ * @brief Get the number of references to a talloc chunk.
+ *
+ * @param[in]  ptr      The pointer to retrieve the reference count from.
+ *
+ * @return              The number of references.
+ */
+size_t talloc_reference_count(const void *ptr);
+
+#ifdef DOXYGEN
+/**
+ * @brief Create an additional talloc parent to a pointer.
+ *
+ * The talloc_reference() function makes "context" an additional parent of
+ * ptr. Each additional reference consumes around 48 bytes of memory on intel
+ * x86 platforms.
+ *
+ * If ptr is NULL, then the function is a no-op, and simply returns NULL.
+ *
+ * After creating a reference you can free it in one of the following ways:
+ *
+ * - you can talloc_free() any parent of the original pointer. That
+ *   will reduce the number of parents of this pointer by 1, and will
+ *   cause this pointer to be freed if it runs out of parents.
+ *
+ * - you can talloc_free() the pointer itself. That will destroy the
+ *   most recently established parent to the pointer and leave the
+ *   pointer as a child of its current parent.
+ *
+ * For more control on which parent to remove, see talloc_unlink()
+ * @param[in]  ctx      The additional parent.
+ *
+ * @param[in]  ptr      The pointer you want to create an additional parent for.
+ *
+ * @return              The original pointer 'ptr', NULL if talloc ran out of
+ *                      memory in creating the reference.
+ *
+ * Example:
+ * @code
+ *      unsigned int *a, *b, *c;
+ *      a = talloc(NULL, unsigned int);
+ *      b = talloc(NULL, unsigned int);
+ *      c = talloc(a, unsigned int);
+ *      // b also serves as a parent of c.
+ *      talloc_reference(b, c);
+ * @endcode
+ *
+ * @see talloc_unlink()
+ */
+void *talloc_reference(const void *ctx, const void *ptr);
+#else
+#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference_loc((ctx),(ptr), __location__)
+void *_talloc_reference_loc(const void *context, const void *ptr, const char *location);
+#endif
+
+/**
+ * @brief Remove a specific parent from a talloc chunk.
+ *
+ * The function removes a specific parent from ptr. The context passed must
+ * either be a context used in talloc_reference() with this pointer, or must be
+ * a direct parent of ptr.
+ *
+ * Usually you can just use talloc_free() instead of talloc_unlink(), but
+ * sometimes it is useful to have the additional control on which parent is
+ * removed.
+ *
+ * @param[in]  context  The talloc parent to remove.
+ *
+ * @param[in]  ptr      The talloc ptr you want to remove the parent from.
+ *
+ * @return              0 on success, -1 on error.
+ *
+ * @note If the parent has already been removed using talloc_free() then
+ * this function will fail and will return -1.  Likewise, if ptr is NULL,
+ * then the function will make no modifications and return -1.
+ *
+ * Example:
+ * @code
+ *      unsigned int *a, *b, *c;
+ *      a = talloc(NULL, unsigned int);
+ *      b = talloc(NULL, unsigned int);
+ *      c = talloc(a, unsigned int);
+ *      // b also serves as a parent of c.
+ *      talloc_reference(b, c);
+ *      talloc_unlink(b, c);
+ * @endcode
+ */
+int talloc_unlink(const void *context, void *ptr);
+
+/**
+ * @brief Provide a talloc context that is freed at program exit.
+ *
+ * This is a handy utility function that returns a talloc context
+ * which will be automatically freed on program exit. This can be used
+ * to reduce the noise in memory leak reports.
+ *
+ * @return              A talloc context, NULL on error.
+ */
+void *talloc_autofree_context(void);
+
+/**
+ * @brief Get the size of a talloc chunk.
+ *
+ * This function lets you know the amount of memory alloced so far by
+ * this context. It does NOT account for subcontext memory.
+ * This can be used to calculate the size of an array.
+ *
+ * @param[in]  ctx      The talloc chunk.
+ *
+ * @return              The size of the talloc chunk.
+ */
+size_t talloc_get_size(const void *ctx);
+
+/**
+ * @brief Show the parentage of a context.
+ *
+ * @param[in]  context            The talloc context to look at.
+ *
+ * @param[in]  file               The output to use, a file, stdout or stderr.
+ */
+void talloc_show_parents(const void *context, FILE *file);
+
+/**
+ * @brief Check if a context is parent of a talloc chunk.
+ *
+ * This checks if context is referenced in the talloc hierarchy above ptr.
+ *
+ * @param[in]  context  The assumed talloc context.
+ *
+ * @param[in]  ptr      The talloc chunk to check.
+ *
+ * @return              Return 1 if this is the case, 0 if not.
+ */
+int talloc_is_parent(const void *context, const void *ptr);
+
+/**
+ * @brief Change the parent context of a talloc pointer.
+ *
+ * The function changes the parent context of a talloc pointer. It is typically
+ * used when the context that the pointer is currently a child of is going to be
+ * freed and you wish to keep the memory for a longer time.
+ *
+ * The difference between talloc_reparent() and talloc_steal() is that
+ * talloc_reparent() can specify which parent you wish to change. This is
+ * useful when a pointer has multiple parents via references.
+ *
+ * @param[in]  old_parent
+ * @param[in]  new_parent
+ * @param[in]  ptr
+ *
+ * @return              Return the pointer you passed. It does not have any
+ *                      failure modes.
+ */
+void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr);
+
+/* @} ******************************************************************/
+
+/**
+ * @defgroup talloc_array The talloc array functions
+ * @ingroup talloc
+ *
+ * Talloc contains some handy helpers for handling Arrays conveniently
+ *
+ * @{
+ */
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate an array.
+ *
+ * The macro is equivalent to:
+ *
+ * @code
+ *      (type *)talloc_size(ctx, sizeof(type) * count);
+ * @endcode
+ *
+ * except that it provides integer overflow protection for the multiply,
+ * returning NULL if the multiply overflows.
+ *
+ * @param[in]  ctx      The talloc context to hang the result off.
+ *
+ * @param[in]  type     The type that we want to allocate.
+ *
+ * @param[in]  count    The number of 'type' elements you want to allocate.
+ *
+ * @return              The allocated result, properly cast to 'type *', NULL on
+ *                      error.
+ *
+ * Example:
+ * @code
+ *      unsigned int *a, *b;
+ *      a = talloc_zero(NULL, unsigned int);
+ *      b = talloc_array(a, unsigned int, 100);
+ * @endcode
+ *
+ * @see talloc()
+ * @see talloc_array_zero()
+ */
+void *talloc_array(const void *ctx, #type, unsigned count);
+#else
+#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate an array.
+ *
+ * @param[in]  ctx      The talloc context to hang the result off.
+ *
+ * @param[in]  size     The size of an array element.
+ *
+ * @param[in]  count    The number of elements you want to allocate.
+ *
+ * @return              The allocated result, NULL on error.
+ */
+void *talloc_array_size(const void *ctx, size_t size, unsigned count);
+#else
+#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate an array into a typed pointer.
+ *
+ * The macro should be used when you have a pointer to an array and want to
+ * allocate memory of an array to point at with this pointer. When compiling
+ * with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+ * and talloc_get_name() will return the current location in the source file
+ * and not the type.
+ *
+ * @param[in]  ctx      The talloc context to hang the result off.
+ *
+ * @param[in]  ptr      The pointer you want to assign the result to.
+ *
+ * @param[in]  count    The number of elements you want to allocate.
+ *
+ * @return              The allocated memory chunk, properly casted. NULL on
+ *                      error.
+ */
+void *talloc_array_ptrtype(const void *ctx, const void *ptr, unsigned count);
+#else
+#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Get the number of elements in a talloc'ed array.
+ *
+ * A talloc chunk carries its own size, so for talloc'ed arrays it is not
+ * necessary to store the number of elements explicitly.
+ *
+ * @param[in]  ctx      The allocated array.
+ *
+ * @return              The number of elements in ctx.
+ */
+size_t talloc_array_length(const void *ctx);
+#else
+#define talloc_array_length(ctx) (talloc_get_size(ctx)/sizeof(*ctx))
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a zero-initialized array
+ *
+ * @param[in]  ctx      The talloc context to hang the result off.
+ *
+ * @param[in]  type     The type that we want to allocate.
+ *
+ * @param[in]  count    The number of "type" elements you want to allocate.
+ *
+ * @return              The allocated result casted to "type *", NULL on error.
+ *
+ * The talloc_zero_array() macro is equivalent to:
+ *
+ * @code
+ *     ptr = talloc_array(ctx, type, count);
+ *     if (ptr) memset(ptr, sizeof(type) * count);
+ * @endcode
+ */
+void *talloc_zero_array(const void *ctx, #type, unsigned count);
+#else
+#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+void *_talloc_zero_array(const void *ctx,
+			 size_t el_size,
+			 unsigned count,
+			 const char *name);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Change the size of a talloc array.
+ *
+ * The macro changes the size of a talloc pointer. The 'count' argument is the
+ * number of elements of type 'type' that you want the resulting pointer to
+ * hold.
+ *
+ * talloc_realloc() has the following equivalences:
+ *
+ * @code
+ *      talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
+ *      talloc_realloc(ctx, NULL, type, N) ==> talloc_array(ctx, type, N);
+ *      talloc_realloc(ctx, ptr, type, 0)  ==> talloc_free(ptr);
+ * @endcode
+ *
+ * The "context" argument is only used if "ptr" is NULL, otherwise it is
+ * ignored.
+ *
+ * @param[in]  ctx      The parent context used if ptr is NULL.
+ *
+ * @param[in]  ptr      The chunk to be resized.
+ *
+ * @param[in]  type     The type of the array element inside ptr.
+ *
+ * @param[in]  count    The intended number of array elements.
+ *
+ * @return              The new array, NULL on error. The call will fail either
+ *                      due to a lack of memory, or because the pointer has more
+ *                      than one parent (see talloc_reference()).
+ */
+void *talloc_realloc(const void *ctx, void *ptr, #type, size_t count);
+#else
+#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Untyped realloc to change the size of a talloc array.
+ *
+ * The macro is useful when the type is not known so the typesafe
+ * talloc_realloc() cannot be used.
+ *
+ * @param[in]  ctx      The parent context used if 'ptr' is NULL.
+ *
+ * @param[in]  ptr      The chunk to be resized.
+ *
+ * @param[in]  size     The new chunk size.
+ *
+ * @return              The new array, NULL on error.
+ */
+void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);
+#else
+#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
+#endif
+
+/**
+ * @brief Provide a function version of talloc_realloc_size.
+ *
+ * This is a non-macro version of talloc_realloc(), which is useful as
+ * libraries sometimes want a ralloc function pointer. A realloc()
+ * implementation encapsulates the functionality of malloc(), free() and
+ * realloc() in one call, which is why it is useful to be able to pass around
+ * a single function pointer.
+ *
+ * @param[in]  context  The parent context used if ptr is NULL.
+ *
+ * @param[in]  ptr      The chunk to be resized.
+ *
+ * @param[in]  size     The new chunk size.
+ *
+ * @return              The new chunk, NULL on error.
+ */
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
+
+/* @} ******************************************************************/
+
+/**
+ * @defgroup talloc_string The talloc string functions.
+ * @ingroup talloc
+ *
+ * talloc string allocation and manipulation functions.
+ * @{
+ */
+
+/**
+ * @brief Duplicate a string into a talloc chunk.
+ *
+ * This function is equivalent to:
+ *
+ * @code
+ *      ptr = talloc_size(ctx, strlen(p)+1);
+ *      if (ptr) memcpy(ptr, p, strlen(p)+1);
+ * @endcode
+ *
+ * This functions sets the name of the new pointer to the passed
+ * string. This is equivalent to:
+ *
+ * @code
+ *      talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in]  t        The talloc context to hang the result off.
+ *
+ * @param[in]  p        The string you want to duplicate.
+ *
+ * @return              The duplicated string, NULL on error.
+ */
+char *talloc_strdup(const void *t, const char *p);
+
+/**
+ * @brief Append a string to given string and duplicate the result.
+ *
+ * @param[in]  s        The destination to append to.
+ *
+ * @param[in]  a        The string you want to append.
+ *
+ * @return              The duplicated string, NULL on error.
+ *
+ * @see talloc_strdup()
+ */
+char *talloc_strdup_append(char *s, const char *a);
+
+/**
+ * @brief Append a string to a given buffer and duplicate the result.
+ *
+ * @param[in]  s        The destination buffer to append to.
+ *
+ * @param[in]  a        The string you want to append.
+ *
+ * @return              The duplicated string, NULL on error.
+ *
+ * @see talloc_strdup()
+ */
+char *talloc_strdup_append_buffer(char *s, const char *a);
+
+/**
+ * @brief Duplicate a length-limited string into a talloc chunk.
+ *
+ * This function is the talloc equivalent of the C library function strndup(3).
+ *
+ * This functions sets the name of the new pointer to the passed string. This is
+ * equivalent to:
+ *
+ * @code
+ *      talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in]  t        The talloc context to hang the result off.
+ *
+ * @param[in]  p        The string you want to duplicate.
+ *
+ * @param[in]  n        The maximum string length to duplicate.
+ *
+ * @return              The duplicated string, NULL on error.
+ */
+char *talloc_strndup(const void *t, const char *p, size_t n);
+
+/**
+ * @brief Append at most n characters of a string to given string and duplicate
+ *        the result.
+ *
+ * @param[in]  s        The destination string to append to.
+ *
+ * @param[in]  a        The source string you want to append.
+ *
+ * @param[in]  n        The number of characters you want to append from the
+ *                      string.
+ *
+ * @return              The duplicated string, NULL on error.
+ *
+ * @see talloc_strndup()
+ */
+char *talloc_strndup_append(char *s, const char *a, size_t n);
+
+/**
+ * @brief Append at most n characters of a string to given buffer and duplicate
+ *        the result.
+ *
+ * @param[in]  s        The destination buffer to append to.
+ *
+ * @param[in]  a        The source string you want to append.
+ *
+ * @param[in]  n        The number of characters you want to append from the
+ *                      string.
+ *
+ * @return              The duplicated string, NULL on error.
+ *
+ * @see talloc_strndup()
+ */
+char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
+
+/**
+ * @brief Format a string given a va_list.
+ *
+ * This function is the talloc equivalent of the C library function
+ * vasprintf(3).
+ *
+ * This functions sets the name of the new pointer to the new string. This is
+ * equivalent to:
+ *
+ * @code
+ *      talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in]  t        The talloc context to hang the result off.
+ *
+ * @param[in]  fmt      The format string.
+ *
+ * @param[in]  ap       The parameters used to fill fmt.
+ *
+ * @return              The formatted string, NULL on error.
+ */
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * @brief Format a string given a va_list and append it to the given destination
+ *        string.
+ *
+ * @param[in]  s        The destination string to append to.
+ *
+ * @param[in]  fmt      The format string.
+ *
+ * @param[in]  ap       The parameters used to fill fmt.
+ *
+ * @return              The formatted string, NULL on error.
+ *
+ * @see talloc_vasprintf()
+ */
+char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * @brief Format a string given a va_list and append it to the given destination
+ *        buffer.
+ *
+ * @param[in]  s        The destination buffer to append to.
+ *
+ * @param[in]  fmt      The format string.
+ *
+ * @param[in]  ap       The parameters used to fill fmt.
+ *
+ * @return              The formatted string, NULL on error.
+ *
+ * @see talloc_vasprintf()
+ */
+char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * @brief Format a string.
+ *
+ * This function is the talloc equivalent of the C library function asprintf(3).
+ *
+ * This functions sets the name of the new pointer to the new string. This is
+ * equivalent to:
+ *
+ * @code
+ *      talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in]  t        The talloc context to hang the result off.
+ *
+ * @param[in]  fmt      The format string.
+ *
+ * @param[in]  ...      The parameters used to fill fmt.
+ *
+ * @return              The formatted string, NULL on error.
+ */
+char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * @brief Append a formatted string to another string.
+ *
+ * This function appends the given formatted string to the given string. Use
+ * this varient when the string in the current talloc buffer may have been
+ * truncated in length.
+ *
+ * This functions sets the name of the new pointer to the new
+ * string. This is equivalent to:
+ *
+ * @code
+ *      talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in]  s        The string to append to.
+ *
+ * @param[in]  fmt      The format string.
+ *
+ * @param[in]  ...      The parameters used to fill fmt.
+ *
+ * @return              The formatted string, NULL on error.
+ */
+char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * @brief Append a formatted string to another string.
+ *
+ * @param[in]  s        The string to append to
+ *
+ * @param[in]  fmt      The format string.
+ *
+ * @param[in]  ...      The parameters used to fill fmt.
+ *
+ * @return              The formatted string, NULL on error.
+ */
+char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/* @} ******************************************************************/
+
+/**
+ * @defgroup talloc_debug The talloc debugging support functions
+ * @ingroup talloc
+ *
+ * To aid memory debugging, talloc contains routines to inspect the currently
+ * allocated memory hierarchy.
+ *
+ * @{
+ */
+
+/**
+ * @brief Walk a complete talloc hierarchy.
+ *
+ * This provides a more flexible reports than talloc_report(). It
+ * will recursively call the callback for the entire tree of memory
+ * referenced by the pointer. References in the tree are passed with
+ * is_ref = 1 and the pointer that is referenced.
+ *
+ * You can pass NULL for the pointer, in which case a report is
+ * printed for the top level memory context, but only if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ * has been called.
+ *
+ * The recursion is stopped when depth >= max_depth.
+ * max_depth = -1 means only stop at leaf nodes.
+ *
+ * @param[in]  ptr      The talloc chunk.
+ *
+ * @param[in]  depth    Internal parameter to control recursion. Call with 0.
+ *
+ * @param[in]  max_depth  Maximum recursion level.
+ *
+ * @param[in]  callback  Function to be called on every chunk.
+ *
+ * @param[in]  private_data  Private pointer passed to callback.
+ */
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+			    void (*callback)(const void *ptr,
+					     int depth, int max_depth,
+					     int is_ref,
+					     void *private_data),
+			    void *private_data);
+
+/**
+ * @brief Print a talloc hierarchy.
+ *
+ * This provides a more flexible reports than talloc_report(). It
+ * will let you specify the depth and max_depth.
+ *
+ * @param[in]  ptr      The talloc chunk.
+ *
+ * @param[in]  depth    Internal parameter to control recursion. Call with 0.
+ *
+ * @param[in]  max_depth  Maximum recursion level.
+ *
+ * @param[in]  f        The file handle to print to.
+ */
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
+
+/**
+ * @brief Print a summary report of all memory used by ptr.
+ *
+ * This provides a more detailed report than talloc_report(). It will
+ * recursively print the ensire tree of memory referenced by the
+ * pointer. References in the tree are shown by giving the name of the
+ * pointer that is referenced.
+ *
+ * You can pass NULL for the pointer, in which case a report is printed
+ * for the top level memory context, but only if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+ * been called.
+ *
+ * @param[in]  ptr      The talloc chunk.
+ *
+ * @param[in]  f        The file handle to print to.
+ *
+ * Example:
+ * @code
+ *      unsigned int *a, *b;
+ *      a = talloc(NULL, unsigned int);
+ *      b = talloc(a, unsigned int);
+ *      fprintf(stderr, "Dumping memory tree for a:\n");
+ *      talloc_report_full(a, stderr);
+ * @endcode
+ *
+ * @see talloc_report()
+ */
+void talloc_report_full(const void *ptr, FILE *f);
+
+/**
+ * @brief Print a summary report of all memory used by ptr.
+ *
+ * This function prints a summary report of all memory used by ptr. One line of
+ * report is printed for each immediate child of ptr, showing the total memory
+ * and number of blocks used by that child.
+ *
+ * You can pass NULL for the pointer, in which case a report is printed
+ * for the top level memory context, but only if talloc_enable_leak_report()
+ * or talloc_enable_leak_report_full() has been called.
+ *
+ * @param[in]  ptr      The talloc chunk.
+ *
+ * @param[in]  f        The file handle to print to.
+ *
+ * Example:
+ * @code
+ *      unsigned int *a, *b;
+ *      a = talloc(NULL, unsigned int);
+ *      b = talloc(a, unsigned int);
+ *      fprintf(stderr, "Summary of memory tree for a:\n");
+ *      talloc_report(a, stderr);
+ * @endcode
+ *
+ * @see talloc_report_full()
+ */
+void talloc_report(const void *ptr, FILE *f);
+
+/**
+ * @brief Enable tracking the use of NULL memory contexts.
+ *
+ * This enables tracking of the NULL memory context without enabling leak
+ * reporting on exit. Useful for when you want to do your own leak
+ * reporting call via talloc_report_null_full();
+ */
+void talloc_enable_null_tracking(void);
+
+/**
+ * @brief Enable tracking the use of NULL memory contexts.
+ *
+ * This enables tracking of the NULL memory context without enabling leak
+ * reporting on exit. Useful for when you want to do your own leak
+ * reporting call via talloc_report_null_full();
+ */
+void talloc_enable_null_tracking_no_autofree(void);
+
+/**
+ * @brief Disable tracking of the NULL memory context.
+ *
+ * This disables tracking of the NULL memory context.
+ */
+void talloc_disable_null_tracking(void);
+
+/**
+ * @brief Enable leak report when a program exits.
+ *
+ * This enables calling of talloc_report(NULL, stderr) when the program
+ * exits. In Samba4 this is enabled by using the --leak-report command
+ * line option.
+ *
+ * For it to be useful, this function must be called before any other
+ * talloc function as it establishes a "null context" that acts as the
+ * top of the tree. If you don't call this function first then passing
+ * NULL to talloc_report() or talloc_report_full() won't give you the
+ * full tree printout.
+ *
+ * Here is a typical talloc report:
+ *
+ * @code
+ * talloc report on 'null_context' (total 267 bytes in 15 blocks)
+ *      libcli/auth/spnego_parse.c:55  contains     31 bytes in   2 blocks
+ *      libcli/auth/spnego_parse.c:55  contains     31 bytes in   2 blocks
+ *      iconv(UTF8,CP850)              contains     42 bytes in   2 blocks
+ *      libcli/auth/spnego_parse.c:55  contains     31 bytes in   2 blocks
+ *      iconv(CP850,UTF8)              contains     42 bytes in   2 blocks
+ *      iconv(UTF8,UTF-16LE)           contains     45 bytes in   2 blocks
+ *      iconv(UTF-16LE,UTF8)           contains     45 bytes in   2 blocks
+ * @endcode
+ */
+void talloc_enable_leak_report(void);
+
+/**
+ * @brief Enable full leak report when a program exits.
+ *
+ * This enables calling of talloc_report_full(NULL, stderr) when the
+ * program exits. In Samba4 this is enabled by using the
+ * --leak-report-full command line option.
+ *
+ * For it to be useful, this function must be called before any other
+ * talloc function as it establishes a "null context" that acts as the
+ * top of the tree. If you don't call this function first then passing
+ * NULL to talloc_report() or talloc_report_full() won't give you the
+ * full tree printout.
+ *
+ * Here is a typical full report:
+ *
+ * @code
+ * full talloc report on 'root' (total 18 bytes in 8 blocks)
+ *      p1                             contains     18 bytes in   7 blocks (ref 0)
+ *      r1                             contains     13 bytes in   2 blocks (ref 0)
+ *      reference to: p2
+ *      p2                             contains      1 bytes in   1 blocks (ref 1)
+ *      x3                             contains      1 bytes in   1 blocks (ref 0)
+ *      x2                             contains      1 bytes in   1 blocks (ref 0)
+ *      x1                             contains      1 bytes in   1 blocks (ref 0)
+ * @endcode
+ */
+void talloc_enable_leak_report_full(void);
+
+/* @} ******************************************************************/
+
+void talloc_set_abort_fn(void (*abort_fn)(const char *reason));
+void talloc_set_log_fn(void (*log_fn)(const char *message));
+void talloc_set_log_stderr(void);
+
+#if TALLOC_DEPRECATED
+#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
+#define talloc_p(ctx, type) talloc(ctx, type)
+#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
+#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
+#endif
+
+#ifndef TALLOC_MAX_DEPTH
+#define TALLOC_MAX_DEPTH 10000
+#endif
+
+#endif

Added: branches/ctdb/squeeze-backports/lib/talloc/talloc.pc
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/talloc.pc	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/talloc.pc	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+prefix=/home/tridge/samba/samba4/prefix
+exec_prefix=/home/tridge/samba/samba4/prefix
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: talloc
+Description: A hierarchical pool based memory system with destructors
+Requires.private: 
+Version: 0.0.1
+Libs: -L${libdir} -ltalloc
+Libs.private: -lreplace 
+Cflags: -I${includedir}  -DHAVE_IMMEDIATE_STRUCTURES=1

Added: branches/ctdb/squeeze-backports/lib/talloc/talloc.pc.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/talloc.pc.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/talloc.pc.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: talloc 
+Description: A hierarchical pool based memory system with destructors
+Version: @TALLOC_VERSION@
+Libs: -L${libdir} -ltalloc
+Cflags: -I${includedir} 
+URL: http://talloc.samba.org/

Added: branches/ctdb/squeeze-backports/lib/talloc/talloc_guide.txt
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/talloc_guide.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/talloc_guide.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,758 @@
+Using talloc in Samba4
+======================
+
+.. contents::
+
+Andrew Tridgell
+August 2009
+
+The most current version of this document is available at
+   http://samba.org/ftp/unpacked/talloc/talloc_guide.txt
+
+If you are used to the "old" talloc from Samba3 before 3.0.20 then please read
+this carefully, as talloc has changed a lot. With 3.0.20 (or 3.0.14?) the
+Samba4 talloc has been ported back to Samba3, so this guide applies to both.
+
+The new talloc is a hierarchical, reference counted memory pool system
+with destructors. Quite a mouthful really, but not too bad once you
+get used to it.
+
+Perhaps the biggest change from Samba3 is that there is no distinction
+between a "talloc context" and a "talloc pointer". Any pointer
+returned from talloc() is itself a valid talloc context. This means
+you can do this::
+
+  struct foo *X = talloc(mem_ctx, struct foo);
+  X->name = talloc_strdup(X, "foo");
+
+and the pointer X->name would be a "child" of the talloc context "X"
+which is itself a child of mem_ctx. So if you do talloc_free(mem_ctx)
+then it is all destroyed, whereas if you do talloc_free(X) then just X
+and X->name are destroyed, and if you do talloc_free(X->name) then
+just the name element of X is destroyed.
+
+If you think about this, then what this effectively gives you is an
+n-ary tree, where you can free any part of the tree with
+talloc_free().
+
+If you find this confusing, then I suggest you run the testsuite to
+watch talloc in action. You may also like to add your own tests to
+testsuite.c to clarify how some particular situation is handled.
+
+
+Performance
+-----------
+
+All the additional features of talloc() over malloc() do come at a
+price. We have a simple performance test in Samba4 that measures
+talloc() versus malloc() performance, and it seems that talloc() is
+about 4% slower than malloc() on my x86 Debian Linux box. For Samba,
+the great reduction in code complexity that we get by using talloc
+makes this worthwhile, especially as the total overhead of
+talloc/malloc in Samba is already quite small.
+
+
+talloc API
+----------
+
+The following is a complete guide to the talloc API. Read it all at
+least twice.
+
+Multi-threading
+---------------
+
+talloc itself does not deal with threads. It is thread-safe (assuming  
+the underlying "malloc" is), as long as each thread uses different  
+memory contexts.
+If two threads uses the same context then they need to synchronize in  
+order to be safe. In particular:
+- when using talloc_enable_leak_report(), giving directly NULL as a  
+parent context implicitly refers to a hidden "null context" global  
+variable, so this should not be used in a multi-threaded environment  
+without proper synchronization ;
+- the context returned by talloc_autofree_context() is also global so  
+shouldn't be used by several threads simultaneously without  
+synchronization.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc(const void *context, type);
+
+The talloc() macro is the core of the talloc library. It takes a
+memory context and a type, and returns a pointer to a new area of
+memory of the given type.
+
+The returned pointer is itself a talloc context, so you can use it as
+the context argument to more calls to talloc if you wish.
+
+The returned pointer is a "child" of the supplied context. This means
+that if you talloc_free() the context then the new child disappears as
+well. Alternatively you can free just the child.
+
+The context argument to talloc() can be NULL, in which case a new top
+level context is created. 
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_size(const void *context, size_t size);
+
+The function talloc_size() should be used when you don't have a
+convenient type to pass to talloc(). Unlike talloc(), it is not type
+safe (as it returns a void *), so you are on your own for type checking.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);
+
+The talloc_ptrtype() macro should be used when you have a pointer and
+want to allocate memory to point at with this pointer. When compiling
+with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+and talloc_get_name() will return the current location in the source file.
+and not the type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_free(void *ptr);
+
+The talloc_free() function frees a piece of talloc memory, and all its
+children. You can call talloc_free() on any pointer returned by
+talloc().
+
+The return value of talloc_free() indicates success or failure, with 0
+returned for success and -1 for failure. A possible failure condition
+is if the pointer had a destructor attached to it and the destructor
+returned -1. See talloc_set_destructor() for details on
+destructors. Likewise, if "ptr" is NULL, then the function will make
+no modifications and returns -1.
+
+If this pointer has an additional parent when talloc_free() is called
+then the memory is not actually released, but instead the most
+recently established parent is destroyed. See talloc_reference() for
+details on establishing additional parents.
+
+For more control on which parent is removed, see talloc_unlink()
+
+talloc_free() operates recursively on its children.
+
+From the 2.0 version of talloc, as a special case, talloc_free() is
+refused on pointers that have more than one parent, as talloc would
+have no way of knowing which parent should be removed. To free a
+pointer that has more than one parent please use talloc_unlink().
+
+To help you find problems in your code caused by this behaviour, if
+you do try and free a pointer with more than one parent then the
+talloc logging function will be called to give output like this:
+
+  ERROR: talloc_free with references at some_dir/source/foo.c:123
+	reference at some_dir/source/other.c:325
+	reference at some_dir/source/third.c:121
+
+Please see the documentation for talloc_set_log_fn() and
+talloc_set_log_stderr() for more information on talloc logging
+functions.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_free_children(void *ptr);
+
+The talloc_free_children() walks along the list of all children of a
+talloc context and talloc_free()s only the children, not the context
+itself.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_reference(const void *context, const void *ptr);
+
+The talloc_reference() function makes "context" an additional parent
+of "ptr".
+
+The return value of talloc_reference() is always the original pointer
+"ptr", unless talloc ran out of memory in creating the reference in
+which case it will return NULL (each additional reference consumes
+around 48 bytes of memory on intel x86 platforms).
+
+If "ptr" is NULL, then the function is a no-op, and simply returns NULL.
+
+After creating a reference you can free it in one of the following
+ways:
+
+  - you can talloc_free() any parent of the original pointer. That
+    will reduce the number of parents of this pointer by 1, and will
+    cause this pointer to be freed if it runs out of parents.
+
+  - you can talloc_free() the pointer itself. That will destroy the
+    most recently established parent to the pointer and leave the
+    pointer as a child of its current parent.
+
+For more control on which parent to remove, see talloc_unlink()
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_unlink(const void *context, const void *ptr);
+
+The talloc_unlink() function removes a specific parent from ptr. The
+context passed must either be a context used in talloc_reference()
+with this pointer, or must be a direct parent of ptr. 
+
+Note that if the parent has already been removed using talloc_free()
+then this function will fail and will return -1.  Likewise, if "ptr"
+is NULL, then the function will make no modifications and return -1.
+
+Usually you can just use talloc_free() instead of talloc_unlink(), but
+sometimes it is useful to have the additional control on which parent
+is removed.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+
+The function talloc_set_destructor() sets the "destructor" for the
+pointer "ptr". A destructor is a function that is called when the
+memory used by a pointer is about to be released. The destructor
+receives the pointer as an argument, and should return 0 for success
+and -1 for failure.
+
+The destructor can do anything it wants to, including freeing other
+pieces of memory. A common use for destructors is to clean up
+operating system resources (such as open file descriptors) contained
+in the structure the destructor is placed on.
+
+You can only place one destructor on a pointer. If you need more than
+one destructor then you can create a zero-length child of the pointer
+and place an additional destructor on that.
+
+To remove a destructor call talloc_set_destructor() with NULL for the
+destructor.
+
+If your destructor attempts to talloc_free() the pointer that it is
+the destructor for then talloc_free() will return -1 and the free will
+be ignored. This would be a pointless operation anyway, as the
+destructor is only called when the memory is just about to go away.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_increase_ref_count(const void *ptr);
+
+The talloc_increase_ref_count(ptr) function is exactly equivalent to:
+
+  talloc_reference(NULL, ptr);
+
+You can use either syntax, depending on which you think is clearer in
+your code.
+
+It returns 0 on success and -1 on failure.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_reference_count(const void *ptr);
+
+Return the number of references to the pointer.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_name(const void *ptr, const char *fmt, ...);
+
+Each talloc pointer has a "name". The name is used principally for
+debugging purposes, although it is also possible to set and get the
+name on a pointer in as a way of "marking" pointers in your code.
+
+The main use for names on pointer is for "talloc reports". See
+talloc_report() and talloc_report_full() for details. Also see
+talloc_enable_leak_report() and talloc_enable_leak_report_full().
+
+The talloc_set_name() function allocates memory as a child of the
+pointer. It is logically equivalent to:
+  talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));
+
+Note that multiple calls to talloc_set_name() will allocate more
+memory without releasing the name. All of the memory is released when
+the ptr is freed using talloc_free().
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_name_const(const void *ptr, const char *name);
+
+The function talloc_set_name_const() is just like talloc_set_name(),
+but it takes a string constant, and is much faster. It is extensively
+used by the "auto naming" macros, such as talloc_p().
+
+This function does not allocate any memory. It just copies the
+supplied pointer into the internal representation of the talloc
+ptr. This means you must not pass a name pointer to memory that will
+disappear before the ptr is freed with talloc_free().
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_named(const void *context, size_t size, const char *fmt, ...);
+
+The talloc_named() function creates a named talloc pointer. It is
+equivalent to:
+
+   ptr = talloc_size(context, size);
+   talloc_set_name(ptr, fmt, ....);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_named_const(const void *context, size_t size, const char *name);
+
+This is equivalent to::
+
+   ptr = talloc_size(context, size);
+   talloc_set_name_const(ptr, name);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+const char *talloc_get_name(const void *ptr);
+
+This returns the current name for the given talloc pointer. See
+talloc_set_name() for details.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_init(const char *fmt, ...);
+
+This function creates a zero length named talloc context as a top
+level context. It is equivalent to::
+
+  talloc_named(NULL, 0, fmt, ...);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_new(void *ctx);
+
+This is a utility macro that creates a new memory context hanging
+off an exiting context, automatically naming it "talloc_new: __location__"
+where __location__ is the source line it is called from. It is
+particularly useful for creating a new temporary working context.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_realloc(const void *context, void *ptr, type, count);
+
+The talloc_realloc() macro changes the size of a talloc
+pointer. The "count" argument is the number of elements of type "type"
+that you want the resulting pointer to hold. 
+
+talloc_realloc() has the following equivalences::
+
+  talloc_realloc(context, NULL, type, 1) ==> talloc(context, type);
+  talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N);
+  talloc_realloc(context, ptr, type, 0)  ==> talloc_free(ptr);
+
+The "context" argument is only used if "ptr" is NULL, otherwise it is
+ignored.
+
+talloc_realloc() returns the new pointer, or NULL on failure. The call
+will fail either due to a lack of memory, or because the pointer has
+more than one parent (see talloc_reference()).
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_realloc_size(const void *context, void *ptr, size_t size);
+
+the talloc_realloc_size() function is useful when the type is not 
+known so the typesafe talloc_realloc() cannot be used.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_steal(const void *new_ctx, const void *ptr);
+
+The talloc_steal() function changes the parent context of a talloc
+pointer. It is typically used when the context that the pointer is
+currently a child of is going to be freed and you wish to keep the
+memory for a longer time. 
+
+The talloc_steal() function returns the pointer that you pass it. It
+does not have any failure modes.
+
+NOTE: It is possible to produce loops in the parent/child relationship
+if you are not careful with talloc_steal(). No guarantees are provided
+as to your sanity or the safety of your data if you do this.
+
+talloc_steal (new_ctx, NULL) will return NULL with no sideeffects.
+
+Note that if you try and call talloc_steal() on a pointer that has
+more than one parent then the result is ambiguous. Talloc will choose
+to remove the parent that is currently indicated by talloc_parent()
+and replace it with the chosen parent. You will also get a message
+like this via the talloc logging functions:
+
+  WARNING: talloc_steal with references at some_dir/source/foo.c:123
+	reference at some_dir/source/other.c:325
+	reference at some_dir/source/third.c:121
+
+To unambiguously change the parent of a pointer please see the
+function talloc_reparent(). See the talloc_set_log_fn() documentation
+for more information on talloc logging.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr);
+
+The talloc_reparent() function changes the parent context of a talloc
+pointer. It is typically used when the context that the pointer is
+currently a child of is going to be freed and you wish to keep the
+memory for a longer time.
+
+The talloc_reparent() function returns the pointer that you pass it. It
+does not have any failure modes.
+
+The difference between talloc_reparent() and talloc_steal() is that
+talloc_reparent() can specify which parent you wish to change. This is
+useful when a pointer has multiple parents via references.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_parent(const void *ptr);
+
+The talloc_parent() function returns the current talloc parent. This
+is usually the pointer under which this memory was originally created,
+but it may have changed due to a talloc_steal() or talloc_reparent()
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_total_size(const void *ptr);
+
+The talloc_total_size() function returns the total size in bytes used
+by this pointer and all child pointers. Mostly useful for debugging.
+
+Passing NULL is allowed, but it will only give a meaningful result if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_total_blocks(const void *ptr);
+
+The talloc_total_blocks() function returns the total memory block
+count used by this pointer and all child pointers. Mostly useful for
+debugging.
+
+Passing NULL is allowed, but it will only give a meaningful result if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+			    void (*callback)(const void *ptr,
+			    		     int depth, int max_depth,
+					     int is_ref,
+					     void *priv),
+			    void *priv);
+
+This provides a more flexible reports than talloc_report(). It
+will recursively call the callback for the entire tree of memory
+referenced by the pointer. References in the tree are passed with
+is_ref = 1 and the pointer that is referenced.
+
+You can pass NULL for the pointer, in which case a report is
+printed for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full()
+has been called.
+
+The recursion is stopped when depth >= max_depth.
+max_depth = -1 means only stop at leaf nodes.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
+
+This provides a more flexible reports than talloc_report(). It
+will let you specify the depth and max_depth.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report(const void *ptr, FILE *f);
+
+The talloc_report() function prints a summary report of all memory
+used by ptr. One line of report is printed for each immediate child of
+ptr, showing the total memory and number of blocks used by that child.
+
+You can pass NULL for the pointer, in which case a report is printed
+for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_full(const void *ptr, FILE *f);
+
+This provides a more detailed report than talloc_report(). It will
+recursively print the ensire tree of memory referenced by the
+pointer. References in the tree are shown by giving the name of the
+pointer that is referenced.
+
+You can pass NULL for the pointer, in which case a report is printed
+for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_leak_report(void);
+
+This enables calling of talloc_report(NULL, stderr) when the program
+exits. In Samba4 this is enabled by using the --leak-report command
+line option.
+
+For it to be useful, this function must be called before any other
+talloc function as it establishes a "null context" that acts as the
+top of the tree. If you don't call this function first then passing
+NULL to talloc_report() or talloc_report_full() won't give you the
+full tree printout.
+
+Here is a typical talloc report:
+
+talloc report on 'null_context' (total 267 bytes in 15 blocks)
+        libcli/auth/spnego_parse.c:55  contains     31 bytes in   2 blocks
+        libcli/auth/spnego_parse.c:55  contains     31 bytes in   2 blocks
+        iconv(UTF8,CP850)              contains     42 bytes in   2 blocks
+        libcli/auth/spnego_parse.c:55  contains     31 bytes in   2 blocks
+        iconv(CP850,UTF8)              contains     42 bytes in   2 blocks
+        iconv(UTF8,UTF-16LE)           contains     45 bytes in   2 blocks
+        iconv(UTF-16LE,UTF8)           contains     45 bytes in   2 blocks
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_leak_report_full(void);
+
+This enables calling of talloc_report_full(NULL, stderr) when the
+program exits. In Samba4 this is enabled by using the
+--leak-report-full command line option.
+
+For it to be useful, this function must be called before any other
+talloc function as it establishes a "null context" that acts as the
+top of the tree. If you don't call this function first then passing
+NULL to talloc_report() or talloc_report_full() won't give you the
+full tree printout.
+
+Here is a typical full report:
+
+full talloc report on 'root' (total 18 bytes in 8 blocks)
+    p1                             contains     18 bytes in   7 blocks (ref 0)
+        r1                             contains     13 bytes in   2 blocks (ref 0)
+            reference to: p2
+        p2                             contains      1 bytes in   1 blocks (ref 1)
+        x3                             contains      1 bytes in   1 blocks (ref 0)
+        x2                             contains      1 bytes in   1 blocks (ref 0)
+        x1                             contains      1 bytes in   1 blocks (ref 0)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_null_tracking(void);
+
+This enables tracking of the NULL memory context without enabling leak
+reporting on exit. Useful for when you want to do your own leak
+reporting call via talloc_report_null_full();
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_disable_null_tracking(void);
+
+This disables tracking of the NULL memory context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_zero(const void *ctx, type);
+
+The talloc_zero() macro is equivalent to::
+
+  ptr = talloc(ctx, type);
+  if (ptr) memset(ptr, 0, sizeof(type));
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_zero_size(const void *ctx, size_t size)
+
+The talloc_zero_size() function is useful when you don't have a known type
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_memdup(const void *ctx, const void *p, size_t size);
+
+The talloc_memdup() function is equivalent to::
+
+  ptr = talloc_size(ctx, size);
+  if (ptr) memcpy(ptr, p, size);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_strdup(const void *ctx, const char *p);
+
+The talloc_strdup() function is equivalent to::
+
+  ptr = talloc_size(ctx, strlen(p)+1);
+  if (ptr) memcpy(ptr, p, strlen(p)+1);
+
+This functions sets the name of the new pointer to the passed
+string. This is equivalent to::
+
+   talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_strndup(const void *t, const char *p, size_t n);
+
+The talloc_strndup() function is the talloc equivalent of the C
+library function strndup()
+
+This functions sets the name of the new pointer to the passed
+string. This is equivalent to:
+   talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_append_string(const void *t, char *orig, const char *append);
+
+The talloc_append_string() function appends the given formatted
+string to the given string.
+
+This function sets the name of the new pointer to the new
+string. This is equivalent to::
+
+   talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap);
+
+The talloc_vasprintf() function is the talloc equivalent of the C
+library function vasprintf()
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to::
+
+   talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf(const void *t, const char *fmt, ...);
+
+The talloc_asprintf() function is the talloc equivalent of the C
+library function asprintf()
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to::
+
+   talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf_append(char *s, const char *fmt, ...);
+
+The talloc_asprintf_append() function appends the given formatted
+string to the given string.
+Use this varient when the string in the current talloc buffer may
+have been truncated in length.
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to::
+
+   talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...);
+
+The talloc_asprintf_append() function appends the given formatted 
+string to the end of the currently allocated talloc buffer.
+Use this varient when the string in the current talloc buffer has
+not been changed.
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to::
+
+   talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+((type *)talloc_array(const void *ctx, type, unsigned int count);
+
+The talloc_array() macro is equivalent to::
+
+  (type *)talloc_size(ctx, sizeof(type) * count);
+
+except that it provides integer overflow protection for the multiply,
+returning NULL if the multiply overflows.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_array_size(const void *ctx, size_t size, unsigned int count);
+
+The talloc_array_size() function is useful when the type is not
+known. It operates in the same way as talloc_array(), but takes a size
+instead of a type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, unsigned int count);
+
+The talloc_ptrtype() macro should be used when you have a pointer to an array
+and want to allocate memory of an array to point at with this pointer. When compiling
+with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+and talloc_get_name() will return the current location in the source file.
+and not the type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size);
+
+This is a non-macro version of talloc_realloc(), which is useful 
+as libraries sometimes want a ralloc function pointer. A realloc()
+implementation encapsulates the functionality of malloc(), free() and
+realloc() in one call, which is why it is useful to be able to pass
+around a single function pointer.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_autofree_context(void);
+
+This is a handy utility function that returns a talloc context
+which will be automatically freed on program exit. This can be used
+to reduce the noise in memory leak reports.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_check_name(const void *ptr, const char *name);
+
+This function checks if a pointer has the specified name. If it does
+then the pointer is returned. It it doesn't then NULL is returned.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_get_type(const void *ptr, type);
+
+This macro allows you to do type checking on talloc pointers. It is
+particularly useful for void* private pointers. It is equivalent to
+this::
+
+   (type *)talloc_check_name(ptr, #type)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+talloc_set_type(const void *ptr, type);
+
+This macro allows you to force the name of a pointer to be a
+particular type. This can be used in conjunction with
+talloc_get_type() to do type checking on void* pointers.
+
+It is equivalent to this::
+
+   talloc_set_name_const(ptr, #type)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+talloc_get_size(const void *ctx);
+
+This function lets you know the amount of memory alloced so far by
+this context. It does NOT account for subcontext memory.
+This can be used to calculate the size of an array.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_find_parent_byname(const void *ctx, const char *name);
+
+Find a parent memory context of the current context that has the given
+name. This can be very useful in complex programs where it may be
+difficult to pass all information down to the level you need, but you
+know the structure you want is a parent of another context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_find_parent_bytype(ctx, type);
+
+Like talloc_find_parent_byname() but takes a type, making it typesafe.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_log_fn(void (*log_fn)(const char *message));
+
+This function sets a logging function that talloc will use for
+warnings and errors. By default talloc will not print any warnings or
+errors.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_log_stderr(void)
+
+This sets the talloc log function to write log messages to stderr

Added: branches/ctdb/squeeze-backports/lib/talloc/testsuite.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/testsuite.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/testsuite.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1232 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   local testing of talloc routines.
+
+   Copyright (C) Andrew Tridgell 2004
+   
+     ** NOTE! The following LGPL license applies to the talloc
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#include <talloc.h>
+
+static struct timeval timeval_current(void)
+{
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return tv;
+}
+
+static double timeval_elapsed(struct timeval *tv)
+{
+	struct timeval tv2 = timeval_current();
+	return (tv2.tv_sec - tv->tv_sec) + 
+	       (tv2.tv_usec - tv->tv_usec)*1.0e-6;
+}
+
+#define torture_assert(test, expr, str) if (!(expr)) { \
+	printf("failure: %s [\n%s: Expression %s failed: %s\n]\n", \
+		test, __location__, #expr, str); \
+	return false; \
+}
+
+#define torture_assert_str_equal(test, arg1, arg2, desc) \
+	if (arg1 == NULL && arg2 == NULL) {				\
+	} else if (strcmp(arg1, arg2)) {			\
+		printf("failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
+		   test, __location__, arg1, arg2, desc); \
+		return false; \
+	}
+
+#if _SAMBA_BUILD_==3
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef strdup
+#undef strdup
+#endif
+#endif
+
+#define CHECK_SIZE(test, ptr, tsize) do { \
+	if (talloc_total_size(ptr) != (tsize)) { \
+		printf("failed: %s [\n%s: wrong '%s' tree size: got %u  expected %u\n]\n", \
+		       test, __location__, #ptr, \
+		       (unsigned)talloc_total_size(ptr), \
+		       (unsigned)tsize); \
+		talloc_report_full(ptr, stdout); \
+		return false; \
+	} \
+} while (0)
+
+#define CHECK_BLOCKS(test, ptr, tblocks) do { \
+	if (talloc_total_blocks(ptr) != (tblocks)) { \
+		printf("failed: %s [\n%s: wrong '%s' tree blocks: got %u  expected %u\n]\n", \
+		       test, __location__, #ptr, \
+		       (unsigned)talloc_total_blocks(ptr), \
+		       (unsigned)tblocks); \
+		talloc_report_full(ptr, stdout); \
+		return false; \
+	} \
+} while (0)
+
+#define CHECK_PARENT(test, ptr, parent) do { \
+	if (talloc_parent(ptr) != (parent)) { \
+		printf("failed: %s [\n%s: '%s' has wrong parent: got %p  expected %p\n]\n", \
+		       test, __location__, #ptr, \
+		       talloc_parent(ptr), \
+		       (parent)); \
+		talloc_report_full(ptr, stdout); \
+		talloc_report_full(parent, stdout); \
+		talloc_report_full(NULL, stdout); \
+		return false; \
+	} \
+} while (0)
+
+static unsigned int test_abort_count;
+
+static void test_abort_fn(const char *reason)
+{
+	printf("# test_abort_fn(%s)\n", reason);
+	test_abort_count++;
+}
+
+static void test_abort_start(void)
+{
+	test_abort_count = 0;
+	talloc_set_abort_fn(test_abort_fn);
+}
+
+static void test_abort_stop(void)
+{
+	test_abort_count = 0;
+	talloc_set_abort_fn(NULL);
+}
+
+static void test_log_stdout(const char *message)
+{
+	fprintf(stdout, "%s", message);
+}
+
+/*
+  test references 
+*/
+static bool test_ref1(void)
+{
+	void *root, *p1, *p2, *ref, *r1;
+
+	printf("test: ref1\n# SINGLE REFERENCE FREE\n");
+
+	root = talloc_named_const(NULL, 0, "root");
+	p1 = talloc_named_const(root, 1, "p1");
+	p2 = talloc_named_const(p1, 1, "p2");
+	talloc_named_const(p1, 1, "x1");
+	talloc_named_const(p1, 2, "x2");
+	talloc_named_const(p1, 3, "x3");
+
+	r1 = talloc_named_const(root, 1, "r1");	
+	ref = talloc_reference(r1, p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref1", p1, 5);
+	CHECK_BLOCKS("ref1", p2, 1);
+	CHECK_BLOCKS("ref1", r1, 2);
+
+	fprintf(stderr, "Freeing p2\n");
+	talloc_unlink(r1, p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref1", p1, 5);
+	CHECK_BLOCKS("ref1", p2, 1);
+	CHECK_BLOCKS("ref1", r1, 1);
+
+	fprintf(stderr, "Freeing p1\n");
+	talloc_free(p1);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref1", r1, 1);
+
+	fprintf(stderr, "Freeing r1\n");
+	talloc_free(r1);
+	talloc_report_full(NULL, stderr);
+
+	fprintf(stderr, "Testing NULL\n");
+	if (talloc_reference(root, NULL)) {
+		return false;
+	}
+
+	CHECK_BLOCKS("ref1", root, 1);
+
+	CHECK_SIZE("ref1", root, 0);
+
+	talloc_free(root);
+	printf("success: ref1\n");
+	return true;
+}
+
+/*
+  test references 
+*/
+static bool test_ref2(void)
+{
+	void *root, *p1, *p2, *ref, *r1;
+
+	printf("test: ref2\n# DOUBLE REFERENCE FREE\n");
+	root = talloc_named_const(NULL, 0, "root");
+	p1 = talloc_named_const(root, 1, "p1");
+	talloc_named_const(p1, 1, "x1");
+	talloc_named_const(p1, 1, "x2");
+	talloc_named_const(p1, 1, "x3");
+	p2 = talloc_named_const(p1, 1, "p2");
+
+	r1 = talloc_named_const(root, 1, "r1");	
+	ref = talloc_reference(r1, p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref2", p1, 5);
+	CHECK_BLOCKS("ref2", p2, 1);
+	CHECK_BLOCKS("ref2", r1, 2);
+
+	fprintf(stderr, "Freeing ref\n");
+	talloc_unlink(r1, ref);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref2", p1, 5);
+	CHECK_BLOCKS("ref2", p2, 1);
+	CHECK_BLOCKS("ref2", r1, 1);
+
+	fprintf(stderr, "Freeing p2\n");
+	talloc_free(p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref2", p1, 4);
+	CHECK_BLOCKS("ref2", r1, 1);
+
+	fprintf(stderr, "Freeing p1\n");
+	talloc_free(p1);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref2", r1, 1);
+
+	fprintf(stderr, "Freeing r1\n");
+	talloc_free(r1);
+	talloc_report_full(root, stderr);
+
+	CHECK_SIZE("ref2", root, 0);
+
+	talloc_free(root);
+	printf("success: ref2\n");
+	return true;
+}
+
+/*
+  test references 
+*/
+static bool test_ref3(void)
+{
+	void *root, *p1, *p2, *ref, *r1;
+
+	printf("test: ref3\n# PARENT REFERENCE FREE\n");
+
+	root = talloc_named_const(NULL, 0, "root");
+	p1 = talloc_named_const(root, 1, "p1");
+	p2 = talloc_named_const(root, 1, "p2");
+	r1 = talloc_named_const(p1, 1, "r1");
+	ref = talloc_reference(p2, r1);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref3", p1, 2);
+	CHECK_BLOCKS("ref3", p2, 2);
+	CHECK_BLOCKS("ref3", r1, 1);
+
+	fprintf(stderr, "Freeing p1\n");
+	talloc_free(p1);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref3", p2, 2);
+	CHECK_BLOCKS("ref3", r1, 1);
+
+	fprintf(stderr, "Freeing p2\n");
+	talloc_free(p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_SIZE("ref3", root, 0);
+
+	talloc_free(root);
+
+	printf("success: ref3\n");
+	return true;
+}
+
+/*
+  test references 
+*/
+static bool test_ref4(void)
+{
+	void *root, *p1, *p2, *ref, *r1;
+
+	printf("test: ref4\n# REFERRER REFERENCE FREE\n");
+
+	root = talloc_named_const(NULL, 0, "root");
+	p1 = talloc_named_const(root, 1, "p1");
+	talloc_named_const(p1, 1, "x1");
+	talloc_named_const(p1, 1, "x2");
+	talloc_named_const(p1, 1, "x3");
+	p2 = talloc_named_const(p1, 1, "p2");
+
+	r1 = talloc_named_const(root, 1, "r1");	
+	ref = talloc_reference(r1, p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref4", p1, 5);
+	CHECK_BLOCKS("ref4", p2, 1);
+	CHECK_BLOCKS("ref4", r1, 2);
+
+	fprintf(stderr, "Freeing r1\n");
+	talloc_free(r1);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref4", p1, 5);
+	CHECK_BLOCKS("ref4", p2, 1);
+
+	fprintf(stderr, "Freeing p2\n");
+	talloc_free(p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("ref4", p1, 4);
+
+	fprintf(stderr, "Freeing p1\n");
+	talloc_free(p1);
+	talloc_report_full(root, stderr);
+
+	CHECK_SIZE("ref4", root, 0);
+
+	talloc_free(root);
+
+	printf("success: ref4\n");
+	return true;
+}
+
+
+/*
+  test references 
+*/
+static bool test_unlink1(void)
+{
+	void *root, *p1, *p2, *ref, *r1;
+
+	printf("test: unlink\n# UNLINK\n");
+
+	root = talloc_named_const(NULL, 0, "root");
+	p1 = talloc_named_const(root, 1, "p1");
+	talloc_named_const(p1, 1, "x1");
+	talloc_named_const(p1, 1, "x2");
+	talloc_named_const(p1, 1, "x3");
+	p2 = talloc_named_const(p1, 1, "p2");
+
+	r1 = talloc_named_const(p1, 1, "r1");	
+	ref = talloc_reference(r1, p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("unlink", p1, 7);
+	CHECK_BLOCKS("unlink", p2, 1);
+	CHECK_BLOCKS("unlink", r1, 2);
+
+	fprintf(stderr, "Unreferencing r1\n");
+	talloc_unlink(r1, p2);
+	talloc_report_full(root, stderr);
+
+	CHECK_BLOCKS("unlink", p1, 6);
+	CHECK_BLOCKS("unlink", p2, 1);
+	CHECK_BLOCKS("unlink", r1, 1);
+
+	fprintf(stderr, "Freeing p1\n");
+	talloc_free(p1);
+	talloc_report_full(root, stderr);
+
+	CHECK_SIZE("unlink", root, 0);
+
+	talloc_free(root);
+
+	printf("success: unlink\n");
+	return true;
+}
+
+static int fail_destructor(void *ptr)
+{
+	return -1;
+}
+
+/*
+  miscellaneous tests to try to get a higher test coverage percentage
+*/
+static bool test_misc(void)
+{
+	void *root, *p1;
+	char *p2;
+	double *d;
+	const char *name;
+
+	printf("test: misc\n# MISCELLANEOUS\n");
+
+	root = talloc_new(NULL);
+
+	p1 = talloc_size(root, 0x7fffffff);
+	torture_assert("misc", !p1, "failed: large talloc allowed\n");
+
+	p1 = talloc_strdup(root, "foo");
+	talloc_increase_ref_count(p1);
+	talloc_increase_ref_count(p1);
+	talloc_increase_ref_count(p1);
+	CHECK_BLOCKS("misc", p1, 1);
+	CHECK_BLOCKS("misc", root, 2);
+	talloc_unlink(NULL, p1);
+	CHECK_BLOCKS("misc", p1, 1);
+	CHECK_BLOCKS("misc", root, 2);
+	talloc_unlink(NULL, p1);
+	CHECK_BLOCKS("misc", p1, 1);
+	CHECK_BLOCKS("misc", root, 2);
+	p2 = talloc_strdup(p1, "foo");
+	torture_assert("misc", talloc_unlink(root, p2) == -1,
+				   "failed: talloc_unlink() of non-reference context should return -1\n");
+	torture_assert("misc", talloc_unlink(p1, p2) == 0,
+		"failed: talloc_unlink() of parent should succeed\n");
+	talloc_unlink(NULL, p1);
+	CHECK_BLOCKS("misc", p1, 1);
+	CHECK_BLOCKS("misc", root, 2);
+
+	name = talloc_set_name(p1, "my name is %s", "foo");
+	torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
+		"failed: wrong name after talloc_set_name(my name is foo)");
+	CHECK_BLOCKS("misc", p1, 2);
+	CHECK_BLOCKS("misc", root, 3);
+
+	talloc_set_name_const(p1, NULL);
+	torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
+		"failed: wrong name after talloc_set_name(NULL)");
+	CHECK_BLOCKS("misc", p1, 2);
+	CHECK_BLOCKS("misc", root, 3);
+
+	torture_assert("misc", talloc_free(NULL) == -1, 
+				   "talloc_free(NULL) should give -1\n");
+
+	talloc_set_destructor(p1, fail_destructor);
+	torture_assert("misc", talloc_free(p1) == -1, 
+		"Failed destructor should cause talloc_free to fail\n");
+	talloc_set_destructor(p1, NULL);
+
+	talloc_report(root, stderr);
+
+
+	p2 = (char *)talloc_zero_size(p1, 20);
+	torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
+	talloc_free(p2);
+
+	torture_assert("misc", talloc_strdup(root, NULL) == NULL,
+		"failed: strdup on NULL should give NULL\n");
+
+	p2 = talloc_strndup(p1, "foo", 2);
+	torture_assert("misc", strcmp("fo", p2) == 0, 
+				   "strndup doesn't work\n");
+	p2 = talloc_asprintf_append_buffer(p2, "o%c", 'd');
+	torture_assert("misc", strcmp("food", p2) == 0, 
+				   "talloc_asprintf_append_buffer doesn't work\n");
+	CHECK_BLOCKS("misc", p2, 1);
+	CHECK_BLOCKS("misc", p1, 3);
+
+	p2 = talloc_asprintf_append_buffer(NULL, "hello %s", "world");
+	torture_assert("misc", strcmp("hello world", p2) == 0,
+		"talloc_asprintf_append_buffer doesn't work\n");
+	CHECK_BLOCKS("misc", p2, 1);
+	CHECK_BLOCKS("misc", p1, 3);
+	talloc_free(p2);
+
+	d = talloc_array(p1, double, 0x20000000);
+	torture_assert("misc", !d, "failed: integer overflow not detected\n");
+
+	d = talloc_realloc(p1, d, double, 0x20000000);
+	torture_assert("misc", !d, "failed: integer overflow not detected\n");
+
+	talloc_free(p1);
+	CHECK_BLOCKS("misc", root, 1);
+
+	p1 = talloc_named(root, 100, "%d bytes", 100);
+	CHECK_BLOCKS("misc", p1, 2);
+	CHECK_BLOCKS("misc", root, 3);
+	talloc_unlink(root, p1);
+
+	p1 = talloc_init("%d bytes", 200);
+	p2 = talloc_asprintf(p1, "my test '%s'", "string");
+	torture_assert_str_equal("misc", p2, "my test 'string'",
+		"failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
+	CHECK_BLOCKS("misc", p1, 3);
+	CHECK_SIZE("misc", p2, 17);
+	CHECK_BLOCKS("misc", root, 1);
+	talloc_unlink(NULL, p1);
+
+	p1 = talloc_named_const(root, 10, "p1");
+	p2 = (char *)talloc_named_const(root, 20, "p2");
+	(void)talloc_reference(p1, p2);
+	talloc_report_full(root, stderr);
+	talloc_unlink(root, p2);
+	talloc_report_full(root, stderr);
+	CHECK_BLOCKS("misc", p2, 1);
+	CHECK_BLOCKS("misc", p1, 2);
+	CHECK_BLOCKS("misc", root, 3);
+	talloc_unlink(p1, p2);
+	talloc_unlink(root, p1);
+
+	p1 = talloc_named_const(root, 10, "p1");
+	p2 = (char *)talloc_named_const(root, 20, "p2");
+	(void)talloc_reference(NULL, p2);
+	talloc_report_full(root, stderr);
+	talloc_unlink(root, p2);
+	talloc_report_full(root, stderr);
+	CHECK_BLOCKS("misc", p2, 1);
+	CHECK_BLOCKS("misc", p1, 1);
+	CHECK_BLOCKS("misc", root, 2);
+	talloc_unlink(NULL, p2);
+	talloc_unlink(root, p1);
+
+	/* Test that talloc_unlink is a no-op */
+
+	torture_assert("misc", talloc_unlink(root, NULL) == -1,
+		"failed: talloc_unlink(root, NULL) == -1\n");
+
+	talloc_report(root, stderr);
+	talloc_report(NULL, stderr);
+
+	CHECK_SIZE("misc", root, 0);
+
+	talloc_free(root);
+
+	CHECK_SIZE("misc", NULL, 0);
+
+	talloc_enable_null_tracking_no_autofree();
+	talloc_enable_leak_report();
+	talloc_enable_leak_report_full();
+
+	printf("success: misc\n");
+
+	return true;
+}
+
+
+/*
+  test realloc
+*/
+static bool test_realloc(void)
+{
+	void *root, *p1, *p2;
+
+	printf("test: realloc\n# REALLOC\n");
+
+	root = talloc_new(NULL);
+
+	p1 = talloc_size(root, 10);
+	CHECK_SIZE("realloc", p1, 10);
+
+	p1 = talloc_realloc_size(NULL, p1, 20);
+	CHECK_SIZE("realloc", p1, 20);
+
+	talloc_new(p1);
+
+	p2 = talloc_realloc_size(p1, NULL, 30);
+
+	talloc_new(p1);
+
+	p2 = talloc_realloc_size(p1, p2, 40);
+
+	CHECK_SIZE("realloc", p2, 40);
+	CHECK_SIZE("realloc", root, 60);
+	CHECK_BLOCKS("realloc", p1, 4);
+
+	p1 = talloc_realloc_size(NULL, p1, 20);
+	CHECK_SIZE("realloc", p1, 60);
+
+	talloc_increase_ref_count(p2);
+	torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
+		"failed: talloc_realloc() on a referenced pointer should fail\n");
+	CHECK_BLOCKS("realloc", p1, 4);
+
+	talloc_realloc_size(NULL, p2, 0);
+	talloc_realloc_size(NULL, p2, 0);
+	CHECK_BLOCKS("realloc", p1, 4);
+	talloc_realloc_size(p1, p2, 0);
+	CHECK_BLOCKS("realloc", p1, 3);
+
+	torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
+		"failed: oversize talloc should fail\n");
+
+	talloc_realloc_size(NULL, p1, 0);
+	CHECK_BLOCKS("realloc", root, 4);
+	talloc_realloc_size(root, p1, 0);
+	CHECK_BLOCKS("realloc", root, 1);
+
+	CHECK_SIZE("realloc", root, 0);
+
+	talloc_free(root);
+
+	printf("success: realloc\n");
+
+	return true;
+}
+
+/*
+  test realloc with a child
+*/
+static bool test_realloc_child(void)
+{
+	void *root;
+	struct el2 {
+		const char *name;
+	} *el2;	
+	struct el1 {
+		int count;
+		struct el2 **list, **list2, **list3;
+	} *el1;
+
+	printf("test: REALLOC WITH CHILD\n");
+
+	root = talloc_new(NULL);
+
+	el1 = talloc(root, struct el1);
+	el1->list = talloc(el1, struct el2 *);
+	el1->list[0] = talloc(el1->list, struct el2);
+	el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
+
+	el1->list2 = talloc(el1, struct el2 *);
+	el1->list2[0] = talloc(el1->list2, struct el2);
+	el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
+
+	el1->list3 = talloc(el1, struct el2 *);
+	el1->list3[0] = talloc(el1->list3, struct el2);
+	el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
+	
+	el2 = talloc(el1->list, struct el2);
+	el2 = talloc(el1->list2, struct el2);
+	el2 = talloc(el1->list3, struct el2);
+
+	el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
+	el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
+	el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
+
+	talloc_free(root);
+
+	printf("success: REALLOC WITH CHILD\n");
+	return true;
+}
+
+/*
+  test type checking
+*/
+static bool test_type(void)
+{
+	void *root;
+	struct el1 {
+		int count;
+	};
+	struct el2 {
+		int count;
+	};
+	struct el1 *el1;
+
+	printf("test: type\n# talloc type checking\n");
+
+	root = talloc_new(NULL);
+
+	el1 = talloc(root, struct el1);
+
+	el1->count = 1;
+
+	torture_assert("type", talloc_get_type(el1, struct el1) == el1,
+		"type check failed on el1\n");
+	torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
+		"type check failed on el1 with el2\n");
+	talloc_set_type(el1, struct el2);
+	torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
+		"type set failed on el1 with el2\n");
+
+	talloc_free(root);
+
+	printf("success: type\n");
+	return true;
+}
+
+/*
+  test steal
+*/
+static bool test_steal(void)
+{
+	void *root, *p1, *p2;
+
+	printf("test: steal\n# STEAL\n");
+
+	root = talloc_new(NULL);
+
+	p1 = talloc_array(root, char, 10);
+	CHECK_SIZE("steal", p1, 10);
+
+	p2 = talloc_realloc(root, NULL, char, 20);
+	CHECK_SIZE("steal", p1, 10);
+	CHECK_SIZE("steal", root, 30);
+
+	torture_assert("steal", talloc_steal(p1, NULL) == NULL,
+		"failed: stealing NULL should give NULL\n");
+
+	torture_assert("steal", talloc_steal(p1, p1) == p1,
+		"failed: stealing to ourselves is a nop\n");
+	CHECK_BLOCKS("steal", root, 3);
+	CHECK_SIZE("steal", root, 30);
+
+	talloc_steal(NULL, p1);
+	talloc_steal(NULL, p2);
+	CHECK_BLOCKS("steal", root, 1);
+	CHECK_SIZE("steal", root, 0);
+
+	talloc_free(p1);
+	talloc_steal(root, p2);
+	CHECK_BLOCKS("steal", root, 2);
+	CHECK_SIZE("steal", root, 20);
+	
+	talloc_free(p2);
+
+	CHECK_BLOCKS("steal", root, 1);
+	CHECK_SIZE("steal", root, 0);
+
+	talloc_free(root);
+
+	p1 = talloc_size(NULL, 3);
+	talloc_report_full(NULL, stderr);
+	CHECK_SIZE("steal", NULL, 3);
+	talloc_free(p1);
+
+	printf("success: steal\n");
+	return true;
+}
+
+/*
+  test move
+*/
+static bool test_move(void)
+{
+	void *root;
+	struct t_move {
+		char *p;
+		int *x;
+	} *t1, *t2;
+
+	printf("test: move\n# MOVE\n");
+
+	root = talloc_new(NULL);
+
+	t1 = talloc(root, struct t_move);
+	t2 = talloc(root, struct t_move);
+	t1->p = talloc_strdup(t1, "foo");
+	t1->x = talloc(t1, int);
+	*t1->x = 42;
+
+	t2->p = talloc_move(t2, &t1->p);
+	t2->x = talloc_move(t2, &t1->x);
+	torture_assert("move", t1->p == NULL && t1->x == NULL &&
+	    strcmp(t2->p, "foo") == 0 && *t2->x == 42,
+		"talloc move failed");
+
+	talloc_free(root);
+
+	printf("success: move\n");
+
+	return true;
+}
+
+/*
+  test talloc_realloc_fn
+*/
+static bool test_realloc_fn(void)
+{
+	void *root, *p1;
+
+	printf("test: realloc_fn\n# talloc_realloc_fn\n");
+
+	root = talloc_new(NULL);
+
+	p1 = talloc_realloc_fn(root, NULL, 10);
+	CHECK_BLOCKS("realloc_fn", root, 2);
+	CHECK_SIZE("realloc_fn", root, 10);
+	p1 = talloc_realloc_fn(root, p1, 20);
+	CHECK_BLOCKS("realloc_fn", root, 2);
+	CHECK_SIZE("realloc_fn", root, 20);
+	p1 = talloc_realloc_fn(root, p1, 0);
+	CHECK_BLOCKS("realloc_fn", root, 1);
+	CHECK_SIZE("realloc_fn", root, 0);
+
+	talloc_free(root);
+
+	printf("success: realloc_fn\n");
+	return true;
+}
+
+
+static bool test_unref_reparent(void)
+{
+	void *root, *p1, *p2, *c1;
+
+	printf("test: unref_reparent\n# UNREFERENCE AFTER PARENT FREED\n");
+
+	root = talloc_named_const(NULL, 0, "root");
+	p1 = talloc_named_const(root, 1, "orig parent");
+	p2 = talloc_named_const(root, 1, "parent by reference");
+
+	c1 = talloc_named_const(p1, 1, "child");
+	talloc_reference(p2, c1);
+
+	CHECK_PARENT("unref_reparent", c1, p1);
+
+	talloc_free(p1);
+
+	CHECK_PARENT("unref_reparent", c1, p2);
+
+	talloc_unlink(p2, c1);
+
+	CHECK_SIZE("unref_reparent", root, 1);
+
+	talloc_free(p2);
+	talloc_free(root);
+
+	printf("success: unref_reparent\n");
+	return true;
+}
+
+/*
+  measure the speed of talloc versus malloc
+*/
+static bool test_speed(void)
+{
+	void *ctx = talloc_new(NULL);
+	unsigned count;
+	const int loop = 1000;
+	int i;
+	struct timeval tv;
+
+	printf("test: speed\n# TALLOC VS MALLOC SPEED\n");
+
+	tv = timeval_current();
+	count = 0;
+	do {
+		void *p1, *p2, *p3;
+		for (i=0;i<loop;i++) {
+			p1 = talloc_size(ctx, loop % 100);
+			p2 = talloc_strdup(p1, "foo bar");
+			p3 = talloc_size(p1, 300);
+			talloc_free(p1);
+		}
+		count += 3 * loop;
+	} while (timeval_elapsed(&tv) < 5.0);
+
+	fprintf(stderr, "talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+
+	talloc_free(ctx);
+
+	ctx = talloc_pool(NULL, 1024);
+
+	tv = timeval_current();
+	count = 0;
+	do {
+		void *p1, *p2, *p3;
+		for (i=0;i<loop;i++) {
+			p1 = talloc_size(ctx, loop % 100);
+			p2 = talloc_strdup(p1, "foo bar");
+			p3 = talloc_size(p1, 300);
+			talloc_free_children(ctx);
+		}
+		count += 3 * loop;
+	} while (timeval_elapsed(&tv) < 5.0);
+
+	talloc_free(ctx);
+
+	fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+
+	tv = timeval_current();
+	count = 0;
+	do {
+		void *p1, *p2, *p3;
+		for (i=0;i<loop;i++) {
+			p1 = malloc(loop % 100);
+			p2 = strdup("foo bar");
+			p3 = malloc(300);
+			free(p1);
+			free(p2);
+			free(p3);
+		}
+		count += 3 * loop;
+	} while (timeval_elapsed(&tv) < 5.0);
+	fprintf(stderr, "malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+
+	printf("success: speed\n");
+
+	return true;
+}
+
+static bool test_lifeless(void)
+{
+	void *top = talloc_new(NULL);
+	char *parent, *child; 
+	void *child_owner = talloc_new(NULL);
+
+	printf("test: lifeless\n# TALLOC_UNLINK LOOP\n");
+
+	parent = talloc_strdup(top, "parent");
+	child = talloc_strdup(parent, "child");  
+	(void)talloc_reference(child, parent);
+	(void)talloc_reference(child_owner, child); 
+	talloc_report_full(top, stderr);
+	talloc_unlink(top, parent);
+	talloc_unlink(top, child);
+	talloc_report_full(top, stderr);
+	talloc_free(top);
+	talloc_free(child_owner);
+	talloc_free(child);
+
+	printf("success: lifeless\n");
+	return true;
+}
+
+static int loop_destructor_count;
+
+static int test_loop_destructor(char *ptr)
+{
+	loop_destructor_count++;
+	return 0;
+}
+
+static bool test_loop(void)
+{
+	void *top = talloc_new(NULL);
+	char *parent;
+	struct req1 {
+		char *req2, *req3;
+	} *req1;
+
+	printf("test: loop\n# TALLOC LOOP DESTRUCTION\n");
+
+	parent = talloc_strdup(top, "parent");
+	req1 = talloc(parent, struct req1);
+	req1->req2 = talloc_strdup(req1, "req2");  
+	talloc_set_destructor(req1->req2, test_loop_destructor);
+	req1->req3 = talloc_strdup(req1, "req3");
+	(void)talloc_reference(req1->req3, req1);
+	talloc_report_full(top, stderr);
+	talloc_free(parent);
+	talloc_report_full(top, stderr);
+	talloc_report_full(NULL, stderr);
+	talloc_free(top);
+
+	torture_assert("loop", loop_destructor_count == 1, 
+				   "FAILED TO FIRE LOOP DESTRUCTOR\n");
+	loop_destructor_count = 0;
+
+	printf("success: loop\n");
+	return true;
+}
+
+static int fail_destructor_str(char *ptr)
+{
+	return -1;
+}
+
+static bool test_free_parent_deny_child(void)
+{
+	void *top = talloc_new(NULL);
+	char *level1;
+	char *level2;
+	char *level3;
+
+	printf("test: free_parent_deny_child\n# TALLOC FREE PARENT DENY CHILD\n");
+
+	level1 = talloc_strdup(top, "level1");
+	level2 = talloc_strdup(level1, "level2");
+	level3 = talloc_strdup(level2, "level3");
+
+	talloc_set_destructor(level3, fail_destructor_str);
+	talloc_free(level1);
+	talloc_set_destructor(level3, NULL);
+
+	CHECK_PARENT("free_parent_deny_child", level3, top);
+
+	talloc_free(top);
+
+	printf("success: free_parent_deny_child\n");
+	return true;
+}
+
+static bool test_talloc_ptrtype(void)
+{
+	void *top = talloc_new(NULL);
+	struct struct1 {
+		int foo;
+		int bar;
+	} *s1, *s2, **s3, ***s4;
+	const char *location1;
+	const char *location2;
+	const char *location3;
+	const char *location4;
+
+	printf("test: ptrtype\n# TALLOC PTRTYPE\n");
+
+	s1 = talloc_ptrtype(top, s1);location1 = __location__;
+
+	if (talloc_get_size(s1) != sizeof(struct struct1)) {
+		printf("failure: ptrtype [\n"
+		  "talloc_ptrtype() allocated the wrong size %lu (should be %lu)\n"
+		  "]\n", (unsigned long)talloc_get_size(s1),
+		           (unsigned long)sizeof(struct struct1));
+		return false;
+	}
+
+	if (strcmp(location1, talloc_get_name(s1)) != 0) {
+		printf("failure: ptrtype [\n"
+		  "talloc_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
+			talloc_get_name(s1), location1);
+		return false;
+	}
+
+	s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
+
+	if (talloc_get_size(s2) != (sizeof(struct struct1) * 10)) {
+		printf("failure: ptrtype [\n"
+			   "talloc_array_ptrtype() allocated the wrong size "
+		       "%lu (should be %lu)\n]\n",
+			(unsigned long)talloc_get_size(s2),
+		    (unsigned long)(sizeof(struct struct1)*10));
+		return false;
+	}
+
+	if (strcmp(location2, talloc_get_name(s2)) != 0) {
+		printf("failure: ptrtype [\n"
+		"talloc_array_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
+			talloc_get_name(s2), location2);
+		return false;
+	}
+
+	s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
+
+	if (talloc_get_size(s3) != (sizeof(struct struct1 *) * 10)) {
+		printf("failure: ptrtype [\n"
+			   "talloc_array_ptrtype() allocated the wrong size "
+		       "%lu (should be %lu)\n]\n",
+			   (unsigned long)talloc_get_size(s3),
+		       (unsigned long)(sizeof(struct struct1 *)*10));
+		return false;
+	}
+
+	torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
+		"talloc_array_ptrtype() sets the wrong name");
+
+	s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
+
+	if (talloc_get_size(s4) != (sizeof(struct struct1 **) * 10)) {
+		printf("failure: ptrtype [\n"
+		      "talloc_array_ptrtype() allocated the wrong size "
+		       "%lu (should be %lu)\n]\n",
+			   (unsigned long)talloc_get_size(s4),
+		       (unsigned long)(sizeof(struct struct1 **)*10));
+		return false;
+	}
+
+	torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
+		"talloc_array_ptrtype() sets the wrong name");
+
+	talloc_free(top);
+
+	printf("success: ptrtype\n");
+	return true;
+}
+
+static int _test_talloc_free_in_destructor(void **ptr)
+{
+	talloc_free(*ptr);
+	return 0;
+}
+
+static bool test_talloc_free_in_destructor(void)
+{
+	void *level0;
+	void *level1;
+	void *level2;
+	void *level3;
+	void *level4;
+	void **level5;
+
+	printf("test: free_in_destructor\n# TALLOC FREE IN DESTRUCTOR\n");
+
+	level0 = talloc_new(NULL);
+	level1 = talloc_new(level0);
+	level2 = talloc_new(level1);
+	level3 = talloc_new(level2);
+	level4 = talloc_new(level3);
+	level5 = talloc(level4, void *);
+
+	*level5 = level3;
+	(void)talloc_reference(level0, level3);
+	(void)talloc_reference(level3, level3);
+	(void)talloc_reference(level5, level3);
+
+	talloc_set_destructor(level5, _test_talloc_free_in_destructor);
+
+	talloc_free(level1);
+
+	talloc_free(level0);
+
+	printf("success: free_in_destructor\n");
+	return true;
+}
+
+static bool test_autofree(void)
+{
+#if _SAMBA_BUILD_ < 4
+	/* autofree test would kill smbtorture */
+	void *p;
+	printf("test: autofree\n# TALLOC AUTOFREE CONTEXT\n");
+
+	p = talloc_autofree_context();
+	talloc_free(p);
+
+	p = talloc_autofree_context();
+	talloc_free(p);
+
+	printf("success: autofree\n");
+#endif
+	return true;
+}
+
+static bool test_pool(void)
+{
+	void *pool;
+	void *p1, *p2, *p3, *p4;
+
+	pool = talloc_pool(NULL, 1024);
+
+	p1 = talloc_size(pool, 80);
+	p2 = talloc_size(pool, 20);
+	p3 = talloc_size(p1, 50);
+	p4 = talloc_size(p3, 1000);
+
+	talloc_free(pool);
+
+	return true;
+}
+
+
+static bool test_free_ref_null_context(void)
+{
+	void *p1, *p2, *p3;
+	int ret;
+
+	talloc_disable_null_tracking();
+	p1 = talloc_new(NULL);
+	p2 = talloc_new(NULL);
+
+	p3 = talloc_reference(p2, p1);
+	torture_assert("reference", p3 == p1, "failed: reference on null");
+
+	ret = talloc_free(p1);
+	torture_assert("ref free with null parent", ret == 0, "failed: free with null parent");
+	talloc_free(p2);
+
+	talloc_enable_null_tracking_no_autofree();
+	p1 = talloc_new(NULL);
+	p2 = talloc_new(NULL);
+
+	p3 = talloc_reference(p2, p1);
+	torture_assert("reference", p3 == p1, "failed: reference on null");
+
+	ret = talloc_free(p1);
+	torture_assert("ref free with null tracked parent", ret == 0, "failed: free with null parent");
+	talloc_free(p2);
+
+	return true;
+}
+
+static void test_reset(void)
+{
+	talloc_set_log_fn(test_log_stdout);
+	test_abort_stop();
+	talloc_disable_null_tracking();
+	talloc_enable_null_tracking_no_autofree();
+}
+
+struct torture_context;
+bool torture_local_talloc(struct torture_context *tctx)
+{
+	bool ret = true;
+
+	setlinebuf(stdout);
+
+	test_reset();
+	ret &= test_ref1();
+	test_reset();
+	ret &= test_ref2();
+	test_reset();
+	ret &= test_ref3();
+	test_reset();
+	ret &= test_ref4();
+	test_reset();
+	ret &= test_unlink1(); 
+	test_reset();
+	ret &= test_misc();
+	test_reset();
+	ret &= test_realloc();
+	test_reset();
+	ret &= test_realloc_child(); 
+	test_reset();
+	ret &= test_steal(); 
+	test_reset();
+	ret &= test_move(); 
+	test_reset();
+	ret &= test_unref_reparent();
+	test_reset();
+	ret &= test_realloc_fn(); 
+	test_reset();
+	ret &= test_type();
+	test_reset();
+	ret &= test_lifeless(); 
+	test_reset();
+	ret &= test_loop();
+	test_reset();
+	ret &= test_free_parent_deny_child(); 
+	test_reset();
+	ret &= test_talloc_ptrtype();
+	test_reset();
+	ret &= test_talloc_free_in_destructor();
+	test_reset();
+	ret &= test_pool();
+	test_reset();
+	ret &= test_free_ref_null_context();
+
+	if (ret) {
+		test_reset();
+		ret &= test_speed();
+	}
+	test_reset();
+	ret &= test_autofree();
+
+	test_reset();
+
+	return ret;
+}

Added: branches/ctdb/squeeze-backports/lib/talloc/testsuite_main.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/testsuite_main.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/testsuite_main.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,37 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   local testing of talloc routines.
+
+   Copyright (C) Andrew Tridgell 2004
+
+     ** NOTE! The following LGPL license applies to the talloc
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+struct torture_context;
+bool torture_local_talloc(struct torture_context *tctx);
+
+int main(void)
+{
+	bool ret = torture_local_talloc(NULL);
+	if (!ret)
+		return -1;
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/lib/talloc/web/index.html
===================================================================
--- branches/ctdb/squeeze-backports/lib/talloc/web/index.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/talloc/web/index.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>talloc</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
+
+<h1>talloc</h1>
+
+talloc is a hierarchical pool based memory allocator with
+destructors. It is the core memory allocator used in Samba, and has
+made a huge difference in many aspects of Samba4 development.<p>
+
+To get started with talloc, I would recommend you read the <a
+href="http://samba.org/ftp/unpacked/talloc/talloc_guide.txt">talloc guide</a>.
+
+<h2>Download</h2>
+You can download the latest releases of talloc from the <a
+href="http://samba.org/ftp/talloc">talloc directory</a> on the samba public
+source archive.
+
+<h2>Discussion and bug reports</h2>
+
+talloc does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+<h2>Development</h2>
+
+You can download the latest code either via git or rsync.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the master branch and cd into the lib/talloc directory.<br>
+<br>
+To fetch via rsync use this command:
+
+<pre>
+  rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/talloc .
+</pre>
+
+<hr>
+<tiny>
+<a href="http://samba.org/~tridge/">Andrew Tridgell</a><br>
+talloc AT tridgell.net
+</tiny>
+
+</BODY>
+</HTML>

Added: branches/ctdb/squeeze-backports/lib/tdb/ABI/tdb-1.2.6.sigs
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/ABI/tdb-1.2.6.sigs	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/ABI/tdb-1.2.6.sigs	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,61 @@
+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_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_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_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_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_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+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 *)

Added: branches/ctdb/squeeze-backports/lib/tdb/Makefile.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/Makefile.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/Makefile.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,74 @@
+#!gmake
+#
+# Makefile for tdb directory
+#
+
+CC = @CC@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+includedir = @includedir@
+libdir = @libdir@
+VPATH = @srcdir@:@libreplacedir@
+srcdir = @srcdir@
+builddir = @builddir@
+sharedbuilddir = @sharedbuilddir@
+INSTALLCMD = @INSTALL@
+CPPFLAGS = @CPPFLAGS@ -I$(srcdir)/include -Iinclude 
+CFLAGS = $(CPPFLAGS) @CFLAGS@
+LDFLAGS = @LDFLAGS@
+EXEEXT = @EXEEXT@
+SHLD = @SHLD@
+SHLD_FLAGS = @SHLD_FLAGS@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PICFLAG = @PICFLAG@
+SHLIBEXT = @SHLIBEXT@
+PYTHON = @PYTHON@
+PYTHON_CONFIG = @PYTHON_CONFIG@
+PYTHON_BUILD_TARGET = @PYTHON_BUILD_TARGET@
+PYTHON_INSTALL_TARGET = @PYTHON_INSTALL_TARGET@
+PYTHON_CHECK_TARGET = @PYTHON_CHECK_TARGET@
+LIB_PATH_VAR = @LIB_PATH_VAR@
+tdbdir = @tdbdir@
+
+TDB_OBJ = @TDB_OBJ@ @LIBREPLACEOBJ@
+
+SONAMEFLAG = @SONAMEFLAG@
+VERSIONSCRIPT = @VERSIONSCRIPT@
+EXPORTSFILE = @EXPORTSFILE@
+
+default: all
+
+include $(tdbdir)/tdb.mk
+include $(tdbdir)/rules.mk
+
+all:: showflags dirs $(PROGS) $(TDB_SOLIB) libtdb.a $(PYTHON_BUILD_TARGET)
+
+install:: all
+$(TDB_SOLIB): $(TDB_OBJ)
+	$(SHLD) $(SHLD_FLAGS) -o $@ $(TDB_OBJ) $(VERSIONSCRIPT) $(EXPORTSFILE) $(SONAMEFLAG)$(TDB_SONAME)
+
+shared-build: all
+	${INSTALLCMD} -d $(sharedbuilddir)/lib
+	${INSTALLCMD} -m 644 libtdb.a $(sharedbuilddir)/lib
+	${INSTALLCMD} -m 755 $(TDB_SOLIB) $(sharedbuilddir)/lib
+	ln -sf $(TDB_SOLIB) $(sharedbuilddir)/lib/$(TDB_SONAME)
+	ln -sf $(TDB_SOLIB) $(sharedbuilddir)/lib/libtdb.so
+	${INSTALLCMD} -d $(sharedbuilddir)/include
+	${INSTALLCMD} -m 644 $(srcdir)/include/tdb.h $(sharedbuilddir)/include
+
+check: test
+
+test:: $(PYTHON_CHECK_TARGET)
+installcheck:: test install
+
+clean::
+	rm -f *.o *.a */*.o
+	rm -fr abi
+
+distclean:: clean
+	rm -f config.log config.status include/config.h config.cache
+	rm -f Makefile
+
+realdistclean:: distclean
+	rm -f configure include/config.h.in

Added: branches/ctdb/squeeze-backports/lib/tdb/aclocal.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/aclocal.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/aclocal.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+m4_include(libreplace.m4)

Added: branches/ctdb/squeeze-backports/lib/tdb/autogen.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/autogen.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/autogen.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace"
+autoconf $IPATHS || exit 1
+autoheader $IPATHS || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0
+


Property changes on: branches/ctdb/squeeze-backports/lib/tdb/autogen.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tdb/build_macros.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/build_macros.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/build_macros.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+AC_DEFUN(BUILD_WITH_SHARED_BUILD_DIR,
+  [ AC_ARG_WITH([shared-build-dir],
+                [AC_HELP_STRING([--with-shared-build-dir=DIR],
+                                [temporary build directory where libraries are installed [$srcdir/sharedbuild]])])
+
+    sharedbuilddir="$srcdir/sharedbuild"
+    if test x"$with_shared_build_dir" != x; then
+        sharedbuilddir=$with_shared_build_dir
+        CFLAGS="$CFLAGS -I$with_shared_build_dir/include"
+        LDFLAGS="$LDFLAGS -L$with_shared_build_dir/lib"
+    fi
+    AC_SUBST(sharedbuilddir)
+  ])
+

Added: branches/ctdb/squeeze-backports/lib/tdb/common/check.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/check.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/check.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,472 @@
+ /*
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Rusty Russell		   2009
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "tdb_private.h"
+
+/* Since we opened it, these shouldn't fail unless it's recent corruption. */
+static bool tdb_check_header(struct tdb_context *tdb, tdb_off_t *recovery)
+{
+	struct tdb_header hdr;
+	uint32_t h1, h2;
+
+	if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), 0) == -1)
+		return false;
+	if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0)
+		goto corrupt;
+
+	CONVERT(hdr);
+	if (hdr.version != TDB_VERSION)
+		goto corrupt;
+
+	if (hdr.rwlocks != 0 && hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC)
+		goto corrupt;
+
+	tdb_header_hash(tdb, &h1, &h2);
+	if (hdr.magic1_hash && hdr.magic2_hash &&
+	    (hdr.magic1_hash != h1 || hdr.magic2_hash != h2))
+		goto corrupt;
+
+	if (hdr.hash_size == 0)
+		goto corrupt;
+
+	if (hdr.hash_size != tdb->header.hash_size)
+		goto corrupt;
+
+	if (hdr.recovery_start != 0 &&
+	    hdr.recovery_start < TDB_DATA_START(tdb->header.hash_size))
+		goto corrupt;
+
+	*recovery = hdr.recovery_start;
+	return true;
+
+corrupt:
+	tdb->ecode = TDB_ERR_CORRUPT;
+	TDB_LOG((tdb, TDB_DEBUG_ERROR, "Header is corrupt\n"));
+	return false;
+}
+
+/* Generic record header check. */
+static bool tdb_check_record(struct tdb_context *tdb,
+			     tdb_off_t off,
+			     const struct tdb_record *rec)
+{
+	tdb_off_t tailer;
+
+	/* Check rec->next: 0 or points to record offset, aligned. */
+	if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->header.hash_size)){
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Record offset %d too small next %d\n",
+			 off, rec->next));
+		goto corrupt;
+	}
+	if (rec->next + sizeof(*rec) < rec->next) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Record offset %d too large next %d\n",
+			 off, rec->next));
+		goto corrupt;
+	}
+	if ((rec->next % TDB_ALIGNMENT) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Record offset %d misaligned next %d\n",
+			 off, rec->next));
+		goto corrupt;
+	}
+	if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0))
+		goto corrupt;
+
+	/* Check rec_len: similar to rec->next, implies next record. */
+	if ((rec->rec_len % TDB_ALIGNMENT) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Record offset %d misaligned length %d\n",
+			 off, rec->rec_len));
+		goto corrupt;
+	}
+	/* Must fit tailer. */
+	if (rec->rec_len < sizeof(tailer)) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Record offset %d too short length %d\n",
+			 off, rec->rec_len));
+		goto corrupt;
+	}
+	/* OOB allows "right at the end" access, so this works for last rec. */
+	if (tdb->methods->tdb_oob(tdb, off+sizeof(*rec)+rec->rec_len, 0))
+		goto corrupt;
+
+	/* Check tailer. */
+	if (tdb_ofs_read(tdb, off+sizeof(*rec)+rec->rec_len-sizeof(tailer),
+			 &tailer) == -1)
+		goto corrupt;
+	if (tailer != sizeof(*rec) + rec->rec_len) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Record offset %d invalid tailer\n", off));
+		goto corrupt;
+	}
+
+	return true;
+
+corrupt:
+	tdb->ecode = TDB_ERR_CORRUPT;
+	return false;
+}
+
+/* Grab some bytes: may copy if can't use mmap.
+   Caller has already done bounds check. */
+static TDB_DATA get_bytes(struct tdb_context *tdb,
+			  tdb_off_t off, tdb_len_t len)
+{
+	TDB_DATA d;
+
+	d.dsize = len;
+
+	if (tdb->transaction == NULL && tdb->map_ptr != NULL)
+		d.dptr = (unsigned char *)tdb->map_ptr + off;
+	else
+		d.dptr = tdb_alloc_read(tdb, off, d.dsize);
+	return d;
+}
+
+/* Frees data if we're not able to simply use mmap. */
+static void put_bytes(struct tdb_context *tdb, TDB_DATA d)
+{
+	if (tdb->transaction == NULL && tdb->map_ptr != NULL)
+		return;
+	free(d.dptr);
+}
+
+/* We use the excellent Jenkins lookup3 hash; this is based on hash_word2.
+ * See: http://burtleburtle.net/bob/c/lookup3.c
+ */
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+static void hash(uint32_t key, uint32_t *pc, uint32_t *pb)
+{
+	uint32_t a,b,c;
+
+	/* Set up the internal state */
+	a = b = c = 0xdeadbeef + *pc;
+	c += *pb;
+	a += key;
+	c ^= b; c -= rot(b,14);
+	a ^= c; a -= rot(c,11);
+	b ^= a; b -= rot(a,25);
+	c ^= b; c -= rot(b,16);
+	a ^= c; a -= rot(c,4);
+	b ^= a; b -= rot(a,14);
+	c ^= b; c -= rot(b,24);
+	*pc=c; *pb=b;
+}
+
+/*
+  We want to check that all free records are in the free list
+  (only once), and all free list entries are free records.  Similarly
+  for each hash chain of used records.
+
+  Doing that naively (without walking hash chains, since we want to be
+  linear) means keeping a list of records which have been seen in each
+  hash chain, and another of records pointed to (ie. next pointers
+  from records and the initial hash chain heads).  These two lists
+  should be equal.  This will take 8 bytes per record, and require
+  sorting at the end.
+
+  So instead, we record each offset in a bitmap such a way that
+  recording it twice will cancel out.  Since each offset should appear
+  exactly twice, the bitmap should be zero at the end.
+
+  The approach was inspired by Bloom Filters (see Wikipedia).  For
+  each value, we flip K bits in a bitmap of size N.  The number of
+  distinct arrangements is:
+
+	N! / (K! * (N-K)!)
+
+  Of course, not all arrangements are actually distinct, but testing
+  shows this formula to be close enough.
+
+  So, if K == 8 and N == 256, the probability of two things flipping the same
+  bits is 1 in 409,663,695,276,000.
+
+  Given that ldb uses a hash size of 10000, using 32 bytes per hash chain
+  (320k) seems reasonable.
+*/
+#define NUM_HASHES 8
+#define BITMAP_BITS 256
+
+static void bit_flip(unsigned char bits[], unsigned int idx)
+{
+	bits[idx / CHAR_BIT] ^= (1 << (idx % CHAR_BIT));
+}
+
+/* We record offsets in a bitmap for the particular chain it should be in.  */
+static void record_offset(unsigned char bits[], tdb_off_t off)
+{
+	uint32_t h1 = off, h2 = 0;
+	unsigned int i;
+
+	/* We get two good hash values out of jhash2, so we use both.  Then
+	 * we keep going to produce further hash values. */
+	for (i = 0; i < NUM_HASHES / 2; i++) {
+		hash(off, &h1, &h2);
+		bit_flip(bits, h1 % BITMAP_BITS);
+		bit_flip(bits, h2 % BITMAP_BITS);
+		h2++;
+	}
+}
+
+/* Check that an in-use record is valid. */
+static bool tdb_check_used_record(struct tdb_context *tdb,
+				  tdb_off_t off,
+				  const struct tdb_record *rec,
+				  unsigned char **hashes,
+				  int (*check)(TDB_DATA, TDB_DATA, void *),
+				  void *private_data)
+{
+	TDB_DATA key, data;
+
+	if (!tdb_check_record(tdb, off, rec))
+		return false;
+
+	/* key + data + tailer must fit in record */
+	if (rec->key_len + rec->data_len + sizeof(tdb_off_t) > rec->rec_len) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Record offset %d too short for contents\n", off));
+		return false;
+	}
+
+	key = get_bytes(tdb, off + sizeof(*rec), rec->key_len);
+	if (!key.dptr)
+		return false;
+
+	if (tdb->hash_fn(&key) != rec->full_hash) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Record offset %d has incorrect hash\n", off));
+		goto fail_put_key;
+	}
+
+	/* Mark this offset as a known value for this hash bucket. */
+	record_offset(hashes[BUCKET(rec->full_hash)+1], off);
+	/* And similarly if the next pointer is valid. */
+	if (rec->next)
+		record_offset(hashes[BUCKET(rec->full_hash)+1], rec->next);
+
+	/* If they supply a check function and this record isn't dead,
+	   get data and feed it. */
+	if (check && rec->magic != TDB_DEAD_MAGIC) {
+		data = get_bytes(tdb, off + sizeof(*rec) + rec->key_len,
+				 rec->data_len);
+		if (!data.dptr)
+			goto fail_put_key;
+
+		if (check(key, data, private_data) == -1)
+			goto fail_put_data;
+		put_bytes(tdb, data);
+	}
+
+	put_bytes(tdb, key);
+	return true;
+
+fail_put_data:
+	put_bytes(tdb, data);
+fail_put_key:
+	put_bytes(tdb, key);
+	return false;
+}
+
+/* Check that an unused record is valid. */
+static bool tdb_check_free_record(struct tdb_context *tdb,
+				  tdb_off_t off,
+				  const struct tdb_record *rec,
+				  unsigned char **hashes)
+{
+	if (!tdb_check_record(tdb, off, rec))
+		return false;
+
+	/* Mark this offset as a known value for the free list. */
+	record_offset(hashes[0], off);
+	/* And similarly if the next pointer is valid. */
+	if (rec->next)
+		record_offset(hashes[0], rec->next);
+	return true;
+}
+
+/* Slow, but should be very rare. */
+static size_t dead_space(struct tdb_context *tdb, tdb_off_t off)
+{
+	size_t len;
+
+	for (len = 0; off + len < tdb->map_size; len++) {
+		char c;
+		if (tdb->methods->tdb_read(tdb, off, &c, 1, 0))
+			return 0;
+		if (c != 0 && c != 0x42)
+			break;
+	}
+	return len;
+}
+
+int tdb_check(struct tdb_context *tdb,
+	      int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
+	      void *private_data)
+{
+	unsigned int h;
+	unsigned char **hashes;
+	tdb_off_t off, recovery_start;
+	struct tdb_record rec;
+	bool found_recovery = false;
+	tdb_len_t dead;
+	bool locked;
+
+	/* Read-only databases use no locking at all: it's best-effort.
+	 * We may have a write lock already, so skip that case too. */
+	if (tdb->read_only || tdb->allrecord_lock.count != 0) {
+		locked = false;
+	} else {
+		if (tdb_lockall_read(tdb) == -1)
+			return -1;
+		locked = true;
+	}
+
+	/* Make sure we know true size of the underlying file. */
+	tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+
+	/* Header must be OK: also gets us the recovery ptr, if any. */
+	if (!tdb_check_header(tdb, &recovery_start))
+		goto unlock;
+
+	/* We should have the whole header, too. */
+	if (tdb->map_size < TDB_DATA_START(tdb->header.hash_size)) {
+		tdb->ecode = TDB_ERR_CORRUPT;
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n"));
+		goto unlock;
+	}
+
+	/* One big malloc: pointers then bit arrays. */
+	hashes = (unsigned char **)calloc(
+			1, sizeof(hashes[0]) * (1+tdb->header.hash_size)
+			+ BITMAP_BITS / CHAR_BIT * (1+tdb->header.hash_size));
+	if (!hashes) {
+		tdb->ecode = TDB_ERR_OOM;
+		goto unlock;
+	}
+
+	/* Initialize pointers */
+	hashes[0] = (unsigned char *)(&hashes[1+tdb->header.hash_size]);
+	for (h = 1; h < 1+tdb->header.hash_size; h++)
+		hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT;
+
+	/* Freelist and hash headers are all in a row: read them. */
+	for (h = 0; h < 1+tdb->header.hash_size; h++) {
+		if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t),
+				 &off) == -1)
+			goto free;
+		if (off)
+			record_offset(hashes[h], off);
+	}
+
+	/* For each record, read it in and check it's ok. */
+	for (off = TDB_DATA_START(tdb->header.hash_size);
+	     off < tdb->map_size;
+	     off += sizeof(rec) + rec.rec_len) {
+		if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
+					   DOCONV()) == -1)
+			goto free;
+		switch (rec.magic) {
+		case TDB_MAGIC:
+		case TDB_DEAD_MAGIC:
+			if (!tdb_check_used_record(tdb, off, &rec, hashes,
+						   check, private_data))
+				goto free;
+			break;
+		case TDB_FREE_MAGIC:
+			if (!tdb_check_free_record(tdb, off, &rec, hashes))
+				goto free;
+			break;
+		/* If we crash after ftruncate, we can get zeroes or fill. */
+		case TDB_RECOVERY_INVALID_MAGIC:
+		case 0x42424242:
+			if (recovery_start == off) {
+				found_recovery = true;
+				break;
+			}
+			dead = dead_space(tdb, off);
+			if (dead < sizeof(rec))
+				goto corrupt;
+
+			TDB_LOG((tdb, TDB_DEBUG_ERROR,
+				 "Dead space at %d-%d (of %u)\n",
+				 off, off + dead, tdb->map_size));
+			rec.rec_len = dead - sizeof(rec);
+			break;
+		case TDB_RECOVERY_MAGIC:
+			if (recovery_start != off) {
+				TDB_LOG((tdb, TDB_DEBUG_ERROR,
+					 "Unexpected recovery record at offset %d\n",
+					 off));
+				goto free;
+			}
+			found_recovery = true;
+			break;
+		default: ;
+		corrupt:
+			tdb->ecode = TDB_ERR_CORRUPT;
+			TDB_LOG((tdb, TDB_DEBUG_ERROR,
+				 "Bad magic 0x%x at offset %d\n",
+				 rec.magic, off));
+			goto free;
+		}
+	}
+
+	/* Now, hashes should all be empty: each record exists and is referred
+	 * to by one other. */
+	for (h = 0; h < 1+tdb->header.hash_size; h++) {
+		unsigned int i;
+		for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) {
+			if (hashes[h][i] != 0) {
+				tdb->ecode = TDB_ERR_CORRUPT;
+				TDB_LOG((tdb, TDB_DEBUG_ERROR,
+					 "Hashes do not match records\n"));
+				goto free;
+			}
+		}
+	}
+
+	/* We must have found recovery area if there was one. */
+	if (recovery_start != 0 && !found_recovery) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "Expected a recovery area at %u\n",
+			 recovery_start));
+		goto free;
+	}
+
+	free(hashes);
+	if (locked) {
+		tdb_unlockall_read(tdb);
+	}
+	return 0;
+
+free:
+	free(hashes);
+unlock:
+	if (locked) {
+		tdb_unlockall_read(tdb);
+	}
+	return -1;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/common/dump.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/dump.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/dump.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,137 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              1999-2005
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000-2003
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+static tdb_off_t tdb_dump_record(struct tdb_context *tdb, int hash,
+				 tdb_off_t offset)
+{
+	struct tdb_record rec;
+	tdb_off_t tailer_ofs, tailer;
+
+	if (tdb->methods->tdb_read(tdb, offset, (char *)&rec, 
+				   sizeof(rec), DOCONV()) == -1) {
+		printf("ERROR: failed to read record at %u\n", offset);
+		return 0;
+	}
+
+	printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%d "
+	       "key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
+	       hash, offset, rec.next, rec.rec_len, rec.key_len, rec.data_len,
+	       rec.full_hash, rec.magic);
+
+	tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off_t);
+
+	if (tdb_ofs_read(tdb, tailer_ofs, &tailer) == -1) {
+		printf("ERROR: failed to read tailer at %u\n", tailer_ofs);
+		return rec.next;
+	}
+
+	if (tailer != rec.rec_len + sizeof(rec)) {
+		printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n",
+				(unsigned int)tailer, (unsigned int)(rec.rec_len + sizeof(rec)));
+	}
+	return rec.next;
+}
+
+static int tdb_dump_chain(struct tdb_context *tdb, int i)
+{
+	tdb_off_t rec_ptr, top;
+
+	top = TDB_HASH_TOP(i);
+
+	if (tdb_lock(tdb, i, F_WRLCK) != 0)
+		return -1;
+
+	if (tdb_ofs_read(tdb, top, &rec_ptr) == -1)
+		return tdb_unlock(tdb, i, F_WRLCK);
+
+	if (rec_ptr)
+		printf("hash=%d\n", i);
+
+	while (rec_ptr) {
+		rec_ptr = tdb_dump_record(tdb, i, rec_ptr);
+	}
+
+	return tdb_unlock(tdb, i, F_WRLCK);
+}
+
+void tdb_dump_all(struct tdb_context *tdb)
+{
+	int i;
+	for (i=0;i<tdb->header.hash_size;i++) {
+		tdb_dump_chain(tdb, i);
+	}
+	printf("freelist:\n");
+	tdb_dump_chain(tdb, -1);
+}
+
+int tdb_printfreelist(struct tdb_context *tdb)
+{
+	int ret;
+	long total_free = 0;
+	tdb_off_t offset, rec_ptr;
+	struct tdb_record rec;
+
+	if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0)
+		return ret;
+
+	offset = FREELIST_TOP;
+
+	/* read in the freelist top */
+	if (tdb_ofs_read(tdb, offset, &rec_ptr) == -1) {
+		tdb_unlock(tdb, -1, F_WRLCK);
+		return 0;
+	}
+
+	printf("freelist top=[0x%08x]\n", rec_ptr );
+	while (rec_ptr) {
+		if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec, 
+					   sizeof(rec), DOCONV()) == -1) {
+			tdb_unlock(tdb, -1, F_WRLCK);
+			return -1;
+		}
+
+		if (rec.magic != TDB_FREE_MAGIC) {
+			printf("bad magic 0x%08x in free list\n", rec.magic);
+			tdb_unlock(tdb, -1, F_WRLCK);
+			return -1;
+		}
+
+		printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)] (end = 0x%08x)\n", 
+		       rec_ptr, rec.rec_len, rec.rec_len, rec_ptr + rec.rec_len);
+		total_free += rec.rec_len;
+
+		/* move to the next record */
+		rec_ptr = rec.next;
+	}
+	printf("total rec_len = [0x%08x (%d)]\n", (int)total_free, 
+               (int)total_free);
+
+	return tdb_unlock(tdb, -1, F_WRLCK);
+}
+

Added: branches/ctdb/squeeze-backports/lib/tdb/common/error.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/error.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/error.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,57 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              1999-2005
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000-2003
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+enum TDB_ERROR tdb_error(struct tdb_context *tdb)
+{
+	return tdb->ecode;
+}
+
+static struct tdb_errname {
+	enum TDB_ERROR ecode; const char *estring;
+} emap[] = { {TDB_SUCCESS, "Success"},
+	     {TDB_ERR_CORRUPT, "Corrupt database"},
+	     {TDB_ERR_IO, "IO Error"},
+	     {TDB_ERR_LOCK, "Locking error"},
+	     {TDB_ERR_OOM, "Out of memory"},
+	     {TDB_ERR_EXISTS, "Record exists"},
+	     {TDB_ERR_NOLOCK, "Lock exists on other keys"},
+	     {TDB_ERR_EINVAL, "Invalid parameter"},
+	     {TDB_ERR_NOEXIST, "Record does not exist"},
+	     {TDB_ERR_RDONLY, "write not permitted"} };
+
+/* Error string for the last tdb error */
+const char *tdb_errorstr(struct tdb_context *tdb)
+{
+	uint32_t i;
+	for (i = 0; i < sizeof(emap) / sizeof(struct tdb_errname); i++)
+		if (tdb->ecode == emap[i].ecode)
+			return emap[i].estring;
+	return "Invalid error code";
+}
+

Added: branches/ctdb/squeeze-backports/lib/tdb/common/freelist.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/freelist.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/freelist.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,386 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              1999-2005
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000-2003
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* 'right' merges can involve O(n^2) cost when combined with a
+   traverse, so they are disabled until we find a way to do them in 
+   O(1) time
+*/
+#define USE_RIGHT_MERGES 0
+
+/* read a freelist record and check for simple errors */
+int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct tdb_record *rec)
+{
+	if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
+		return -1;
+
+	if (rec->magic == TDB_MAGIC) {
+		/* this happens when a app is showdown while deleting a record - we should
+		   not completely fail when this happens */
+		TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n", 
+			 rec->magic, off));
+		rec->magic = TDB_FREE_MAGIC;
+		if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
+			return -1;
+	}
+
+	if (rec->magic != TDB_FREE_MAGIC) {
+		/* Ensure ecode is set for log fn. */
+		tdb->ecode = TDB_ERR_CORRUPT;
+		TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n", 
+			   rec->magic, off));
+		return -1;
+	}
+	if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0)
+		return -1;
+	return 0;
+}
+
+
+#if USE_RIGHT_MERGES
+/* Remove an element from the freelist.  Must have alloc lock. */
+static int remove_from_freelist(struct tdb_context *tdb, tdb_off_t off, tdb_off_t next)
+{
+	tdb_off_t last_ptr, i;
+
+	/* read in the freelist top */
+	last_ptr = FREELIST_TOP;
+	while (tdb_ofs_read(tdb, last_ptr, &i) != -1 && i != 0) {
+		if (i == off) {
+			/* We've found it! */
+			return tdb_ofs_write(tdb, last_ptr, &next);
+		}
+		/* Follow chain (next offset is at start of record) */
+		last_ptr = i;
+	}
+	tdb->ecode = TDB_ERR_CORRUPT;
+	TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off));
+	return -1;
+}
+#endif
+
+
+/* update a record tailer (must hold allocation lock) */
+static int update_tailer(struct tdb_context *tdb, tdb_off_t offset,
+			 const struct tdb_record *rec)
+{
+	tdb_off_t totalsize;
+
+	/* Offset of tailer from record header */
+	totalsize = sizeof(*rec) + rec->rec_len;
+	return tdb_ofs_write(tdb, offset + totalsize - sizeof(tdb_off_t),
+			 &totalsize);
+}
+
+/* Add an element into the freelist. Merge adjacent records if
+   necessary. */
+int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
+{
+	/* Allocation and tailer lock */
+	if (tdb_lock(tdb, -1, F_WRLCK) != 0)
+		return -1;
+
+	/* set an initial tailer, so if we fail we don't leave a bogus record */
+	if (update_tailer(tdb, offset, rec) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed!\n"));
+		goto fail;
+	}
+
+#if USE_RIGHT_MERGES
+	/* Look right first (I'm an Australian, dammit) */
+	if (offset + sizeof(*rec) + rec->rec_len + sizeof(*rec) <= tdb->map_size) {
+		tdb_off_t right = offset + sizeof(*rec) + rec->rec_len;
+		struct tdb_record r;
+
+		if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right read failed at %u\n", right));
+			goto left;
+		}
+
+		/* If it's free, expand to include it. */
+		if (r.magic == TDB_FREE_MAGIC) {
+			if (remove_from_freelist(tdb, right, r.next) == -1) {
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right free failed at %u\n", right));
+				goto left;
+			}
+			rec->rec_len += sizeof(r) + r.rec_len;
+			if (update_tailer(tdb, offset, rec) == -1) {
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
+				goto fail;
+			}
+		}
+	}
+left:
+#endif
+
+	/* Look left */
+	if (offset - sizeof(tdb_off_t) > TDB_DATA_START(tdb->header.hash_size)) {
+		tdb_off_t left = offset - sizeof(tdb_off_t);
+		struct tdb_record l;
+		tdb_off_t leftsize;
+
+		/* Read in tailer and jump back to header */
+		if (tdb_ofs_read(tdb, left, &leftsize) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left));
+			goto update;
+		}
+
+		/* it could be uninitialised data */
+		if (leftsize == 0 || leftsize == TDB_PAD_U32) {
+			goto update;
+		}
+
+		left = offset - leftsize;
+
+		if (leftsize > offset ||
+		    left < TDB_DATA_START(tdb->header.hash_size)) {
+			goto update;
+		}
+
+		/* Now read in the left record */
+		if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
+			goto update;
+		}
+
+		/* If it's free, expand to include it. */
+		if (l.magic == TDB_FREE_MAGIC) {
+			/* we now merge the new record into the left record, rather than the other 
+			   way around. This makes the operation O(1) instead of O(n). This change
+			   prevents traverse from being O(n^2) after a lot of deletes */
+			l.rec_len += sizeof(*rec) + rec->rec_len;
+			if (tdb_rec_write(tdb, left, &l) == -1) {
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_left failed at %u\n", left));
+				goto fail;
+			}
+			if (update_tailer(tdb, left, &l) == -1) {
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
+				goto fail;
+			}
+			tdb_unlock(tdb, -1, F_WRLCK);
+			return 0;
+		}
+	}
+
+update:
+
+	/* Now, prepend to free list */
+	rec->magic = TDB_FREE_MAGIC;
+
+	if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
+	    tdb_rec_write(tdb, offset, rec) == -1 ||
+	    tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%d\n", offset));
+		goto fail;
+	}
+
+	/* And we're done. */
+	tdb_unlock(tdb, -1, F_WRLCK);
+	return 0;
+
+ fail:
+	tdb_unlock(tdb, -1, F_WRLCK);
+	return -1;
+}
+
+
+
+/* 
+   the core of tdb_allocate - called when we have decided which
+   free list entry to use
+
+   Note that we try to allocate by grabbing data from the end of an existing record,
+   not the beginning. This is so the left merge in a free is more likely to be
+   able to free up the record without fragmentation
+ */
+static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb, 
+				  tdb_len_t length, tdb_off_t rec_ptr,
+				  struct tdb_record *rec, tdb_off_t last_ptr)
+{
+#define MIN_REC_SIZE (sizeof(struct tdb_record) + sizeof(tdb_off_t) + 8)
+
+	if (rec->rec_len < length + MIN_REC_SIZE) {
+		/* we have to grab the whole record */
+
+		/* unlink it from the previous record */
+		if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) {
+			return 0;
+		}
+
+		/* mark it not free */
+		rec->magic = TDB_MAGIC;
+		if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+			return 0;
+		}
+		return rec_ptr;
+	}
+
+	/* we're going to just shorten the existing record */
+	rec->rec_len -= (length + sizeof(*rec));
+	if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+		return 0;
+	}
+	if (update_tailer(tdb, rec_ptr, rec) == -1) {
+		return 0;
+	}
+
+	/* and setup the new record */
+	rec_ptr += sizeof(*rec) + rec->rec_len;	
+
+	memset(rec, '\0', sizeof(*rec));
+	rec->rec_len = length;
+	rec->magic = TDB_MAGIC;
+
+	if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+		return 0;
+	}
+
+	if (update_tailer(tdb, rec_ptr, rec) == -1) {
+		return 0;
+	}
+
+	return rec_ptr;
+}
+
+/* allocate some space from the free list. The offset returned points
+   to a unconnected tdb_record within the database with room for at
+   least length bytes of total data
+
+   0 is returned if the space could not be allocated
+ */
+tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec)
+{
+	tdb_off_t rec_ptr, last_ptr, newrec_ptr;
+	struct {
+		tdb_off_t rec_ptr, last_ptr;
+		tdb_len_t rec_len;
+	} bestfit;
+	float multiplier = 1.0;
+
+	if (tdb_lock(tdb, -1, F_WRLCK) == -1)
+		return 0;
+
+	/* over-allocate to reduce fragmentation */
+	length *= 1.25;
+
+	/* Extra bytes required for tailer */
+	length += sizeof(tdb_off_t);
+	length = TDB_ALIGN(length, TDB_ALIGNMENT);
+
+ again:
+	last_ptr = FREELIST_TOP;
+
+	/* read in the freelist top */
+	if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
+		goto fail;
+
+	bestfit.rec_ptr = 0;
+	bestfit.last_ptr = 0;
+	bestfit.rec_len = 0;
+
+	/* 
+	   this is a best fit allocation strategy. Originally we used
+	   a first fit strategy, but it suffered from massive fragmentation
+	   issues when faced with a slowly increasing record size.
+	 */
+	while (rec_ptr) {
+		if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
+			goto fail;
+		}
+
+		if (rec->rec_len >= length) {
+			if (bestfit.rec_ptr == 0 ||
+			    rec->rec_len < bestfit.rec_len) {
+				bestfit.rec_len = rec->rec_len;
+				bestfit.rec_ptr = rec_ptr;
+				bestfit.last_ptr = last_ptr;
+			}
+		}
+
+		/* move to the next record */
+		last_ptr = rec_ptr;
+		rec_ptr = rec->next;
+
+		/* if we've found a record that is big enough, then
+		   stop searching if its also not too big. The
+		   definition of 'too big' changes as we scan
+		   through */
+		if (bestfit.rec_len > 0 &&
+		    bestfit.rec_len < length * multiplier) {
+			break;
+		}
+
+		/* this multiplier means we only extremely rarely
+		   search more than 50 or so records. At 50 records we
+		   accept records up to 11 times larger than what we
+		   want */
+		multiplier *= 1.05;
+	}
+
+	if (bestfit.rec_ptr != 0) {
+		if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
+			goto fail;
+		}
+
+		newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, 
+					      rec, bestfit.last_ptr);
+		tdb_unlock(tdb, -1, F_WRLCK);
+		return newrec_ptr;
+	}
+
+	/* we didn't find enough space. See if we can expand the
+	   database and if we can then try again */
+	if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
+		goto again;
+ fail:
+	tdb_unlock(tdb, -1, F_WRLCK);
+	return 0;
+}
+
+
+
+/* 
+   return the size of the freelist - used to decide if we should repack 
+*/
+int tdb_freelist_size(struct tdb_context *tdb)
+{
+	tdb_off_t ptr;
+	int count=0;
+
+	if (tdb_lock(tdb, -1, F_RDLCK) == -1) {
+		return -1;
+	}
+
+	ptr = FREELIST_TOP;
+	while (tdb_ofs_read(tdb, ptr, &ptr) == 0 && ptr != 0) {
+		count++;
+	}
+
+	tdb_unlock(tdb, -1, F_RDLCK);
+	return count;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/common/freelistcheck.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/freelistcheck.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/freelistcheck.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,109 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Jeremy Allison                    2006
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* Check the freelist is good and contains no loops.
+   Very memory intensive - only do this as a consistency
+   checker. Heh heh - uses an in memory tdb as the storage
+   for the "seen" record list. For some reason this strikes
+   me as extremely clever as I don't have to write another tree
+   data structure implementation :-).
+ */
+
+static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr)
+{
+	TDB_DATA key, data;
+
+	memset(&data, '\0', sizeof(data));
+	key.dptr = (unsigned char *)&rec_ptr;
+	key.dsize = sizeof(rec_ptr);
+	return tdb_store(mem_tdb, key, data, TDB_INSERT);
+}
+
+int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
+{
+	struct tdb_context *mem_tdb = NULL;
+	struct tdb_record rec;
+	tdb_off_t rec_ptr, last_ptr;
+	int ret = -1;
+
+	*pnum_entries = 0;
+
+	mem_tdb = tdb_open("flval", tdb->header.hash_size,
+				TDB_INTERNAL, O_RDWR, 0600);
+	if (!mem_tdb) {
+		return -1;
+	}
+
+	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+		tdb_close(mem_tdb);
+		return 0;
+	}
+
+	last_ptr = FREELIST_TOP;
+
+	/* Store the FREELIST_TOP record. */
+	if (seen_insert(mem_tdb, last_ptr) == -1) {
+		tdb->ecode = TDB_ERR_CORRUPT;
+		ret = -1;
+		goto fail;
+	}
+
+	/* read in the freelist top */
+	if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) {
+		goto fail;
+	}
+
+	while (rec_ptr) {
+
+		/* If we can't store this record (we've seen it
+		   before) then the free list has a loop and must
+		   be corrupt. */
+
+		if (seen_insert(mem_tdb, rec_ptr)) {
+			tdb->ecode = TDB_ERR_CORRUPT;
+			ret = -1;
+			goto fail;
+		}
+
+		if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) {
+			goto fail;
+		}
+
+		/* move to the next record */
+		last_ptr = rec_ptr;
+		rec_ptr = rec.next;
+		*pnum_entries += 1;
+	}
+
+	ret = 0;
+
+  fail:
+
+	tdb_close(mem_tdb);
+	tdb_unlock(tdb, -1, F_WRLCK);
+	return ret;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/common/hash.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/hash.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/hash.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,380 @@
+ /*
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Rusty Russell		   2010
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "tdb_private.h"
+
+/* This is based on the hash algorithm from gdbm */
+unsigned int tdb_old_hash(TDB_DATA *key)
+{
+	uint32_t value;	/* Used to compute the hash value.  */
+	uint32_t   i;	/* Used to cycle through random values. */
+
+	/* Set the initial value from the key size. */
+	for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
+		value = (value + (key->dptr[i] << (i*5 % 24)));
+
+	return (1103515243 * value + 12345);
+}
+
+#ifndef WORDS_BIGENDIAN
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#endif
+
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions.  Routines to test the hash are included
+if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+the public domain.  It has no warranty.
+
+You probably want to use hashlittle().  hashlittle() and hashbig()
+hash byte arrays.  hashlittle() is is faster than hashbig() on
+little-endian machines.  Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+  a = i1;  b = i2;  c = i3;
+  mix(a,b,c);
+  a += i4; b += i5; c += i6;
+  mix(a,b,c);
+  a += i7;
+  final(a,b,c);
+then use c as the hash value.  If you have a variable length array of
+4-byte integers to hash, use hash_word().  If you have a byte array (like
+a character string), use hashlittle().  If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big?  I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers.  This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+*/
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or
+  all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+    4  6  8 16 19  4
+    9 15  3 18 27 15
+   14  9  3  7 17  3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta.  I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche.  There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a.  The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism.  Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism.  I did what I could.  Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+  a -= c;  a ^= rot(c, 4);  c += b; \
+  b -= a;  b ^= rot(a, 6);  a += c; \
+  c -= b;  c ^= rot(b, 8);  b += a; \
+  a -= c;  a ^= rot(c,16);  c += b; \
+  b -= a;  b ^= rot(a,19);  a += c; \
+  c -= b;  c ^= rot(b, 4);  b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different.  This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or
+  all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+  4  8 15 26 3 22 24
+ 10  8 15 26 3 22 24
+ 11  8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+  c ^= b; c -= rot(b,14); \
+  a ^= c; a -= rot(c,11); \
+  b ^= a; b -= rot(a,25); \
+  c ^= b; c -= rot(b,16); \
+  a ^= c; a -= rot(c,4);  \
+  b ^= a; b -= rot(a,14); \
+  c ^= b; c -= rot(b,24); \
+}
+
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+  k       : the key (the unaligned variable-length array of bytes)
+  length  : the length of the key, counting by bytes
+  val2    : IN: can be any 4-byte value OUT: second 32 bit hash.
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Two keys differing by one or two bits will have
+totally different hash values.  Note that the return value is better
+mixed than val2, so use that first.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006.  bob_jenkins at burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial.  It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+static uint32_t hashlittle( const void *key, size_t length )
+{
+  uint32_t a,b,c;                                          /* internal state */
+  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length);
+
+  u.ptr = key;
+  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+#ifdef VALGRIND
+    const uint8_t  *k8;
+#endif
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /*
+     * "k[2]&0xffffff" actually reads beyond the end of the string, but
+     * then masks off the part it's not allowed to read.  Because the
+     * string is aligned, the masked-off tail is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticably faster for short strings (like English words).
+     */
+#ifndef VALGRIND
+
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff; break;
+    case 2 : a+=k[0]&0xffff; break;
+    case 1 : a+=k[0]&0xff; break;
+    case 0 : return c;              /* zero length strings require no mixing */
+    }
+
+#else /* make valgrind happy */
+
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
+    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
+    case 9 : c+=k8[8];                   /* fall through */
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
+    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
+    case 5 : b+=k8[4];                   /* fall through */
+    case 4 : a+=k[0]; break;
+    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
+    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
+    case 1 : a+=k8[0]; break;
+    case 0 : return c;
+    }
+
+#endif /* !valgrind */
+
+  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
+    const uint8_t  *k8;
+
+    /*--------------- all but last block: aligned reads and different mixing */
+    while (length > 12)
+    {
+      a += k[0] + (((uint32_t)k[1])<<16);
+      b += k[2] + (((uint32_t)k[3])<<16);
+      c += k[4] + (((uint32_t)k[5])<<16);
+      mix(a,b,c);
+      length -= 12;
+      k += 6;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
+    case 10: c+=k[4];
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 9 : c+=k8[8];                      /* fall through */
+    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
+    case 6 : b+=k[2];
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 5 : b+=k8[4];                      /* fall through */
+    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
+    case 2 : a+=k[0];
+             break;
+    case 1 : a+=k8[0];
+             break;
+    case 0 : return c;                     /* zero length requires no mixing */
+    }
+
+  } else {                        /* need to read the key one byte at a time */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      a += ((uint32_t)k[1])<<8;
+      a += ((uint32_t)k[2])<<16;
+      a += ((uint32_t)k[3])<<24;
+      b += k[4];
+      b += ((uint32_t)k[5])<<8;
+      b += ((uint32_t)k[6])<<16;
+      b += ((uint32_t)k[7])<<24;
+      c += k[8];
+      c += ((uint32_t)k[9])<<8;
+      c += ((uint32_t)k[10])<<16;
+      c += ((uint32_t)k[11])<<24;
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=((uint32_t)k[11])<<24;
+    case 11: c+=((uint32_t)k[10])<<16;
+    case 10: c+=((uint32_t)k[9])<<8;
+    case 9 : c+=k[8];
+    case 8 : b+=((uint32_t)k[7])<<24;
+    case 7 : b+=((uint32_t)k[6])<<16;
+    case 6 : b+=((uint32_t)k[5])<<8;
+    case 5 : b+=k[4];
+    case 4 : a+=((uint32_t)k[3])<<24;
+    case 3 : a+=((uint32_t)k[2])<<16;
+    case 2 : a+=((uint32_t)k[1])<<8;
+    case 1 : a+=k[0];
+             break;
+    case 0 : return c;
+    }
+  }
+
+  final(a,b,c);
+  return c;
+}
+
+unsigned int tdb_jenkins_hash(TDB_DATA *key)
+{
+	return hashlittle(key->dptr, key->dsize);
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/common/io.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/io.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/io.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,472 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              1999-2005
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000-2003
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "tdb_private.h"
+
+/* check for an out of bounds access - if it is out of bounds then
+   see if the database has been expanded by someone else and expand
+   if necessary 
+   note that "len" is the minimum length needed for the db
+*/
+static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
+{
+	struct stat st;
+	if (len <= tdb->map_size)
+		return 0;
+	if (tdb->flags & TDB_INTERNAL) {
+		if (!probe) {
+			/* Ensure ecode is set for log fn. */
+			tdb->ecode = TDB_ERR_IO;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond internal malloc size %d\n",
+				 (int)len, (int)tdb->map_size));
+		}
+		return -1;
+	}
+
+	if (fstat(tdb->fd, &st) == -1) {
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+	if (st.st_size < (size_t)len) {
+		if (!probe) {
+			/* Ensure ecode is set for log fn. */
+			tdb->ecode = TDB_ERR_IO;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond eof at %d\n",
+				 (int)len, (int)st.st_size));
+		}
+		return -1;
+	}
+
+	/* Unmap, update size, remap */
+	if (tdb_munmap(tdb) == -1) {
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+	tdb->map_size = st.st_size;
+	tdb_mmap(tdb);
+	return 0;
+}
+
+/* write a lump of data at a specified offset */
+static int tdb_write(struct tdb_context *tdb, tdb_off_t off, 
+		     const void *buf, tdb_len_t len)
+{
+	if (len == 0) {
+		return 0;
+	}
+
+	if (tdb->read_only || tdb->traverse_read) {
+		tdb->ecode = TDB_ERR_RDONLY;
+		return -1;
+	}
+
+	if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0)
+		return -1;
+
+	if (tdb->map_ptr) {
+		memcpy(off + (char *)tdb->map_ptr, buf, len);
+	} else {
+		ssize_t written = pwrite(tdb->fd, buf, len, off);
+		if ((written != (ssize_t)len) && (written != -1)) {
+			/* try once more */
+			tdb->ecode = TDB_ERR_IO;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only "
+				 "%d of %d bytes at %d, trying once more\n",
+				 (int)written, len, off));
+			written = pwrite(tdb->fd, (const char *)buf+written,
+					 len-written,
+					 off+written);
+		}
+		if (written == -1) {
+			/* Ensure ecode is set for log fn. */
+			tdb->ecode = TDB_ERR_IO;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d "
+				 "len=%d (%s)\n", off, len, strerror(errno)));
+			return -1;
+		} else if (written != (ssize_t)len) {
+			tdb->ecode = TDB_ERR_IO;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to "
+				 "write %d bytes at %d in two attempts\n",
+				 len, off));
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/* Endian conversion: we only ever deal with 4 byte quantities */
+void *tdb_convert(void *buf, uint32_t size)
+{
+	uint32_t i, *p = (uint32_t *)buf;
+	for (i = 0; i < size / 4; i++)
+		p[i] = TDB_BYTEREV(p[i]);
+	return buf;
+}
+
+
+/* read a lump of data at a specified offset, maybe convert */
+static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, 
+		    tdb_len_t len, int cv)
+{
+	if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0) {
+		return -1;
+	}
+
+	if (tdb->map_ptr) {
+		memcpy(buf, off + (char *)tdb->map_ptr, len);
+	} else {
+		ssize_t ret = pread(tdb->fd, buf, len, off);
+		if (ret != (ssize_t)len) {
+			/* Ensure ecode is set for log fn. */
+			tdb->ecode = TDB_ERR_IO;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d "
+				 "len=%d ret=%d (%s) map_size=%d\n",
+				 (int)off, (int)len, (int)ret, strerror(errno),
+				 (int)tdb->map_size));
+			return -1;
+		}
+	}
+	if (cv) {
+		tdb_convert(buf, len);
+	}
+	return 0;
+}
+
+
+
+/*
+  do an unlocked scan of the hash table heads to find the next non-zero head. The value
+  will then be confirmed with the lock held
+*/		
+static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
+{
+	uint32_t h = *chain;
+	if (tdb->map_ptr) {
+		for (;h < tdb->header.hash_size;h++) {
+			if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) {
+				break;
+			}
+		}
+	} else {
+		uint32_t off=0;
+		for (;h < tdb->header.hash_size;h++) {
+			if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) {
+				break;
+			}
+		}
+	}
+	(*chain) = h;
+}
+
+
+int tdb_munmap(struct tdb_context *tdb)
+{
+	if (tdb->flags & TDB_INTERNAL)
+		return 0;
+
+#ifdef HAVE_MMAP
+	if (tdb->map_ptr) {
+		int ret;
+
+		ret = munmap(tdb->map_ptr, tdb->map_size);
+		if (ret != 0)
+			return ret;
+	}
+#endif
+	tdb->map_ptr = NULL;
+	return 0;
+}
+
+void tdb_mmap(struct tdb_context *tdb)
+{
+	if (tdb->flags & TDB_INTERNAL)
+		return;
+
+#ifdef HAVE_MMAP
+	if (!(tdb->flags & TDB_NOMMAP)) {
+		tdb->map_ptr = mmap(NULL, tdb->map_size, 
+				    PROT_READ|(tdb->read_only? 0:PROT_WRITE), 
+				    MAP_SHARED|MAP_FILE, tdb->fd, 0);
+
+		/*
+		 * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
+		 */
+
+		if (tdb->map_ptr == MAP_FAILED) {
+			tdb->map_ptr = NULL;
+			TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", 
+				 tdb->map_size, strerror(errno)));
+		}
+	} else {
+		tdb->map_ptr = NULL;
+	}
+#else
+	tdb->map_ptr = NULL;
+#endif
+}
+
+/* expand a file.  we prefer to use ftruncate, as that is what posix
+  says to use for mmap expansion */
+static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition)
+{
+	char buf[8192];
+
+	if (tdb->read_only || tdb->traverse_read) {
+		tdb->ecode = TDB_ERR_RDONLY;
+		return -1;
+	}
+
+	if (ftruncate(tdb->fd, size+addition) == -1) {
+		char b = 0;
+		ssize_t written = pwrite(tdb->fd,  &b, 1, (size+addition) - 1);
+		if (written == 0) {
+			/* try once more, potentially revealing errno */
+			written = pwrite(tdb->fd,  &b, 1, (size+addition) - 1);
+		}
+		if (written == 0) {
+			/* again - give up, guessing errno */
+			errno = ENOSPC;
+		}
+		if (written != 1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n", 
+				 size+addition, strerror(errno)));
+			return -1;
+		}
+	}
+
+	/* now fill the file with something. This ensures that the
+	   file isn't sparse, which would be very bad if we ran out of
+	   disk. This must be done with write, not via mmap */
+	memset(buf, TDB_PAD_BYTE, sizeof(buf));
+	while (addition) {
+		size_t n = addition>sizeof(buf)?sizeof(buf):addition;
+		ssize_t written = pwrite(tdb->fd, buf, n, size);
+		if (written == 0) {
+			/* prevent infinite loops: try _once_ more */
+			written = pwrite(tdb->fd, buf, n, size);
+		}
+		if (written == 0) {
+			/* give up, trying to provide a useful errno */
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
+				"returned 0 twice: giving up!\n"));
+			errno = ENOSPC;
+			return -1;
+		} else if (written == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
+				 "%d bytes failed (%s)\n", (int)n,
+				 strerror(errno)));
+			return -1;
+		} else if (written != n) {
+			TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
+				 "only %d of %d bytes - retrying\n", (int)written,
+				 (int)n));
+		}
+		addition -= written;
+		size += written;
+	}
+	return 0;
+}
+
+
+/* expand the database at least size bytes by expanding the underlying
+   file and doing the mmap again if necessary */
+int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
+{
+	struct tdb_record rec;
+	tdb_off_t offset, new_size;	
+
+	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
+		return -1;
+	}
+
+	/* must know about any previous expansions by another process */
+	tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+
+	/* always make room for at least 100 more records, and at
+           least 25% more space. Round the database up to a multiple
+           of the page size */
+	new_size = MAX(tdb->map_size + size*100, tdb->map_size * 1.25);
+	size = TDB_ALIGN(new_size, tdb->page_size) - tdb->map_size;
+
+	if (!(tdb->flags & TDB_INTERNAL))
+		tdb_munmap(tdb);
+
+	/*
+	 * We must ensure the file is unmapped before doing this
+	 * to ensure consistency with systems like OpenBSD where
+	 * writes and mmaps are not consistent.
+	 */
+
+	/* expand the file itself */
+	if (!(tdb->flags & TDB_INTERNAL)) {
+		if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0)
+			goto fail;
+	}
+
+	tdb->map_size += size;
+
+	if (tdb->flags & TDB_INTERNAL) {
+		char *new_map_ptr = (char *)realloc(tdb->map_ptr,
+						    tdb->map_size);
+		if (!new_map_ptr) {
+			tdb->map_size -= size;
+			goto fail;
+		}
+		tdb->map_ptr = new_map_ptr;
+	} else {
+		/*
+		 * We must ensure the file is remapped before adding the space
+		 * to ensure consistency with systems like OpenBSD where
+		 * writes and mmaps are not consistent.
+		 */
+
+		/* We're ok if the mmap fails as we'll fallback to read/write */
+		tdb_mmap(tdb);
+	}
+
+	/* form a new freelist record */
+	memset(&rec,'\0',sizeof(rec));
+	rec.rec_len = size - sizeof(rec);
+
+	/* link it into the free list */
+	offset = tdb->map_size - size;
+	if (tdb_free(tdb, offset, &rec) == -1)
+		goto fail;
+
+	tdb_unlock(tdb, -1, F_WRLCK);
+	return 0;
+ fail:
+	tdb_unlock(tdb, -1, F_WRLCK);
+	return -1;
+}
+
+/* read/write a tdb_off_t */
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
+{
+	return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
+}
+
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
+{
+	tdb_off_t off = *d;
+	return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
+}
+
+
+/* read a lump of data, allocating the space for it */
+unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
+{
+	unsigned char *buf;
+
+	/* some systems don't like zero length malloc */
+
+	if (!(buf = (unsigned char *)malloc(len ? len : 1))) {
+		/* Ensure ecode is set for log fn. */
+		tdb->ecode = TDB_ERR_OOM;
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n",
+			   len, strerror(errno)));
+		return NULL;
+	}
+	if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) {
+		SAFE_FREE(buf);
+		return NULL;
+	}
+	return buf;
+}
+
+/* Give a piece of tdb data to a parser */
+
+int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
+		   tdb_off_t offset, tdb_len_t len,
+		   int (*parser)(TDB_DATA key, TDB_DATA data,
+				 void *private_data),
+		   void *private_data)
+{
+	TDB_DATA data;
+	int result;
+
+	data.dsize = len;
+
+	if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) {
+		/*
+		 * Optimize by avoiding the malloc/memcpy/free, point the
+		 * parser directly at the mmap area.
+		 */
+		if (tdb->methods->tdb_oob(tdb, offset+len, 0) != 0) {
+			return -1;
+		}
+		data.dptr = offset + (unsigned char *)tdb->map_ptr;
+		return parser(key, data, private_data);
+	}
+
+	if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) {
+		return -1;
+	}
+
+	result = parser(key, data, private_data);
+	free(data.dptr);
+	return result;
+}
+
+/* read/write a record */
+int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
+{
+	if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
+		return -1;
+	if (TDB_BAD_MAGIC(rec)) {
+		/* Ensure ecode is set for log fn. */
+		tdb->ecode = TDB_ERR_CORRUPT;
+		TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
+		return -1;
+	}
+	return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0);
+}
+
+int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
+{
+	struct tdb_record r = *rec;
+	return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r));
+}
+
+static const struct tdb_methods io_methods = {
+	tdb_read,
+	tdb_write,
+	tdb_next_hash_chain,
+	tdb_oob,
+	tdb_expand_file,
+};
+
+/*
+  initialise the default methods table
+*/
+void tdb_io_init(struct tdb_context *tdb)
+{
+	tdb->methods = &io_methods;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/common/lock.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/lock.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/lock.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,883 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              1999-2005
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000-2003
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr)
+{
+	tdb->interrupt_sig_ptr = ptr;
+}
+
+static int fcntl_lock(struct tdb_context *tdb,
+		      int rw, off_t off, off_t len, bool waitflag)
+{
+	struct flock fl;
+
+	fl.l_type = rw;
+	fl.l_whence = SEEK_SET;
+	fl.l_start = off;
+	fl.l_len = len;
+	fl.l_pid = 0;
+
+	if (waitflag)
+		return fcntl(tdb->fd, F_SETLKW, &fl);
+	else
+		return fcntl(tdb->fd, F_SETLK, &fl);
+}
+
+static int fcntl_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len)
+{
+	struct flock fl;
+#if 0 /* Check they matched up locks and unlocks correctly. */
+	char line[80];
+	FILE *locks;
+	bool found = false;
+
+	locks = fopen("/proc/locks", "r");
+
+	while (fgets(line, 80, locks)) {
+		char *p;
+		int type, start, l;
+
+		/* eg. 1: FLOCK  ADVISORY  WRITE 2440 08:01:2180826 0 EOF */
+		p = strchr(line, ':') + 1;
+		if (strncmp(p, " POSIX  ADVISORY  ", strlen(" POSIX  ADVISORY  ")))
+			continue;
+		p += strlen(" FLOCK  ADVISORY  ");
+		if (strncmp(p, "READ  ", strlen("READ  ")) == 0)
+			type = F_RDLCK;
+		else if (strncmp(p, "WRITE ", strlen("WRITE ")) == 0)
+			type = F_WRLCK;
+		else
+			abort();
+		p += 6;
+		if (atoi(p) != getpid())
+			continue;
+		p = strchr(strchr(p, ' ') + 1, ' ') + 1;
+		start = atoi(p);
+		p = strchr(p, ' ') + 1;
+		if (strncmp(p, "EOF", 3) == 0)
+			l = 0;
+		else
+			l = atoi(p) - start + 1;
+
+		if (off == start) {
+			if (len != l) {
+				fprintf(stderr, "Len %u should be %u: %s",
+					(int)len, l, line);
+				abort();
+			}
+			if (type != rw) {
+				fprintf(stderr, "Type %s wrong: %s",
+					rw == F_RDLCK ? "READ" : "WRITE", line);
+				abort();
+			}
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		fprintf(stderr, "Unlock on %u@%u not found!\n",
+			(int)off, (int)len);
+		abort();
+	}
+
+	fclose(locks);
+#endif
+
+	fl.l_type = F_UNLCK;
+	fl.l_whence = SEEK_SET;
+	fl.l_start = off;
+	fl.l_len = len;
+	fl.l_pid = 0;
+
+	return fcntl(tdb->fd, F_SETLKW, &fl);
+}
+
+/* list -1 is the alloc list, otherwise a hash chain. */
+static tdb_off_t lock_offset(int list)
+{
+	return FREELIST_TOP + 4*list;
+}
+
+/* a byte range locking function - return 0 on success
+   this functions locks/unlocks 1 byte at the specified offset.
+
+   On error, errno is also set so that errors are passed back properly
+   through tdb_open(). 
+
+   note that a len of zero means lock to end of file
+*/
+int tdb_brlock(struct tdb_context *tdb,
+	       int rw_type, tdb_off_t offset, size_t len,
+	       enum tdb_lock_flags flags)
+{
+	int ret;
+
+	if (tdb->flags & TDB_NOLOCK) {
+		return 0;
+	}
+
+	if (flags & TDB_LOCK_MARK_ONLY) {
+		return 0;
+	}
+
+	if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) {
+		tdb->ecode = TDB_ERR_RDONLY;
+		return -1;
+	}
+
+	do {
+		ret = fcntl_lock(tdb, rw_type, offset, len,
+				 flags & TDB_LOCK_WAIT);
+		/* Check for a sigalarm break. */
+		if (ret == -1 && errno == EINTR &&
+				tdb->interrupt_sig_ptr &&
+				*tdb->interrupt_sig_ptr) {
+			break;
+		}
+	} while (ret == -1 && errno == EINTR);
+
+	if (ret == -1) {
+		tdb->ecode = TDB_ERR_LOCK;
+		/* Generic lock error. errno set by fcntl.
+		 * EAGAIN is an expected return from non-blocking
+		 * locks. */
+		if (!(flags & TDB_LOCK_PROBE) && errno != EAGAIN) {
+			TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d flags=%d len=%d\n",
+				 tdb->fd, offset, rw_type, flags, (int)len));
+		}
+		return -1;
+	}
+	return 0;
+}
+
+int tdb_brunlock(struct tdb_context *tdb,
+		 int rw_type, tdb_off_t offset, size_t len)
+{
+	int ret;
+
+	if (tdb->flags & TDB_NOLOCK) {
+		return 0;
+	}
+
+	do {
+		ret = fcntl_unlock(tdb, rw_type, offset, len);
+	} while (ret == -1 && errno == EINTR);
+
+	if (ret == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %d rw_type=%d len=%d\n",
+			 tdb->fd, offset, rw_type, (int)len));
+	}
+	return ret;
+}
+
+/*
+  upgrade a read lock to a write lock. This needs to be handled in a
+  special way as some OSes (such as solaris) have too conservative
+  deadlock detection and claim a deadlock when progress can be
+  made. For those OSes we may loop for a while.  
+*/
+int tdb_allrecord_upgrade(struct tdb_context *tdb)
+{
+	int count = 1000;
+
+	if (tdb->allrecord_lock.count != 1) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "tdb_allrecord_upgrade failed: count %u too high\n",
+			 tdb->allrecord_lock.count));
+		return -1;
+	}
+
+	if (tdb->allrecord_lock.off != 1) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+			 "tdb_allrecord_upgrade failed: already upgraded?\n"));
+		return -1;
+	}
+
+	while (count--) {
+		struct timeval tv;
+		if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
+			       TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) {
+			tdb->allrecord_lock.ltype = F_WRLCK;
+			tdb->allrecord_lock.off = 0;
+			return 0;
+		}
+		if (errno != EDEADLK) {
+			break;
+		}
+		/* sleep for as short a time as we can - more portable than usleep() */
+		tv.tv_sec = 0;
+		tv.tv_usec = 1;
+		select(0, NULL, NULL, NULL, &tv);
+	}
+	TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n"));
+	return -1;
+}
+
+static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb,
+					   tdb_off_t offset)
+{
+	unsigned int i;
+
+	for (i=0; i<tdb->num_lockrecs; i++) {
+		if (tdb->lockrecs[i].off == offset) {
+			return &tdb->lockrecs[i];
+		}
+	}
+	return NULL;
+}
+
+/* lock an offset in the database. */
+int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
+		  enum tdb_lock_flags flags)
+{
+	struct tdb_lock_type *new_lck;
+
+	if (offset >= lock_offset(tdb->header.hash_size)) {
+		tdb->ecode = TDB_ERR_LOCK;
+		TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid offset %u for ltype=%d\n",
+			 offset, ltype));
+		return -1;
+	}
+	if (tdb->flags & TDB_NOLOCK)
+		return 0;
+
+	new_lck = find_nestlock(tdb, offset);
+	if (new_lck) {
+		/*
+		 * Just increment the in-memory struct, posix locks
+		 * don't stack.
+		 */
+		new_lck->count++;
+		return 0;
+	}
+
+	new_lck = (struct tdb_lock_type *)realloc(
+		tdb->lockrecs,
+		sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
+	if (new_lck == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	tdb->lockrecs = new_lck;
+
+	/* Since fcntl locks don't nest, we do a lock for the first one,
+	   and simply bump the count for future ones */
+	if (tdb_brlock(tdb, ltype, offset, 1, flags)) {
+		return -1;
+	}
+
+	tdb->lockrecs[tdb->num_lockrecs].off = offset;
+	tdb->lockrecs[tdb->num_lockrecs].count = 1;
+	tdb->lockrecs[tdb->num_lockrecs].ltype = ltype;
+	tdb->num_lockrecs++;
+
+	return 0;
+}
+
+static int tdb_lock_and_recover(struct tdb_context *tdb)
+{
+	int ret;
+
+	/* We need to match locking order in transaction commit. */
+	if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, TDB_LOCK_WAIT)) {
+		return -1;
+	}
+
+	if (tdb_brlock(tdb, F_WRLCK, OPEN_LOCK, 1, TDB_LOCK_WAIT)) {
+		tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
+		return -1;
+	}
+
+	ret = tdb_transaction_recover(tdb);
+
+	tdb_brunlock(tdb, F_WRLCK, OPEN_LOCK, 1);
+	tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
+
+	return ret;
+}
+
+static bool have_data_locks(const struct tdb_context *tdb)
+{
+	unsigned int i;
+
+	for (i = 0; i < tdb->num_lockrecs; i++) {
+		if (tdb->lockrecs[i].off >= lock_offset(-1))
+			return true;
+	}
+	return false;
+}
+
+static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype,
+			 enum tdb_lock_flags waitflag)
+{
+	int ret;
+	bool check = false;
+
+	/* a allrecord lock allows us to avoid per chain locks */
+	if (tdb->allrecord_lock.count &&
+	    (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) {
+		return 0;
+	}
+
+	if (tdb->allrecord_lock.count) {
+		tdb->ecode = TDB_ERR_LOCK;
+		ret = -1;
+	} else {
+		/* Only check when we grab first data lock. */
+		check = !have_data_locks(tdb);
+		ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag);
+
+		if (ret == 0 && check && tdb_needs_recovery(tdb)) {
+			tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
+
+			if (tdb_lock_and_recover(tdb) == -1) {
+				return -1;
+			}
+			return tdb_lock_list(tdb, list, ltype, waitflag);
+		}
+	}
+	return ret;
+}
+
+/* lock a list in the database. list -1 is the alloc list */
+int tdb_lock(struct tdb_context *tdb, int list, int ltype)
+{
+	int ret;
+
+	ret = tdb_lock_list(tdb, list, ltype, TDB_LOCK_WAIT);
+	if (ret) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d "
+			 "ltype=%d (%s)\n",  list, ltype, strerror(errno)));
+	}
+	return ret;
+}
+
+/* lock a list in the database. list -1 is the alloc list. non-blocking lock */
+int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype)
+{
+	return tdb_lock_list(tdb, list, ltype, TDB_LOCK_NOWAIT);
+}
+
+
+int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
+		    bool mark_lock)
+{
+	int ret = -1;
+	struct tdb_lock_type *lck;
+
+	if (tdb->flags & TDB_NOLOCK)
+		return 0;
+
+	/* Sanity checks */
+	if (offset >= lock_offset(tdb->header.hash_size)) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->header.hash_size));
+		return ret;
+	}
+
+	lck = find_nestlock(tdb, offset);
+	if ((lck == NULL) || (lck->count == 0)) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
+		return -1;
+	}
+
+	if (lck->count > 1) {
+		lck->count--;
+		return 0;
+	}
+
+	/*
+	 * This lock has count==1 left, so we need to unlock it in the
+	 * kernel. We don't bother with decrementing the in-memory array
+	 * element, we're about to overwrite it with the last array element
+	 * anyway.
+	 */
+
+	if (mark_lock) {
+		ret = 0;
+	} else {
+		ret = tdb_brunlock(tdb, ltype, offset, 1);
+	}
+
+	/*
+	 * Shrink the array by overwriting the element just unlocked with the
+	 * last array element.
+	 */
+	*lck = tdb->lockrecs[--tdb->num_lockrecs];
+
+	/*
+	 * We don't bother with realloc when the array shrinks, but if we have
+	 * a completely idle tdb we should get rid of the locked array.
+	 */
+
+	if (tdb->num_lockrecs == 0) {
+		SAFE_FREE(tdb->lockrecs);
+	}
+
+	if (ret)
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n")); 
+	return ret;
+}
+
+int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
+{
+	/* a global lock allows us to avoid per chain locks */
+	if (tdb->allrecord_lock.count &&
+	    (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) {
+		return 0;
+	}
+
+	if (tdb->allrecord_lock.count) {
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	return tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
+}
+
+/*
+  get the transaction lock
+ */
+int tdb_transaction_lock(struct tdb_context *tdb, int ltype,
+			 enum tdb_lock_flags lockflags)
+{
+	return tdb_nest_lock(tdb, TRANSACTION_LOCK, ltype, lockflags);
+}
+
+/*
+  release the transaction lock
+ */
+int tdb_transaction_unlock(struct tdb_context *tdb, int ltype)
+{
+	return tdb_nest_unlock(tdb, TRANSACTION_LOCK, ltype, false);
+}
+
+/* Returns 0 if all done, -1 if error, 1 if ok. */
+static int tdb_allrecord_check(struct tdb_context *tdb, int ltype,
+			       enum tdb_lock_flags flags, bool upgradable)
+{
+	/* There are no locks on read-only dbs */
+	if (tdb->read_only || tdb->traverse_read) {
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) {
+		tdb->allrecord_lock.count++;
+		return 0;
+	}
+
+	if (tdb->allrecord_lock.count) {
+		/* a global lock of a different type exists */
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	if (tdb_have_extra_locks(tdb)) {
+		/* can't combine global and chain locks */
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	if (upgradable && ltype != F_RDLCK) {
+		/* tdb error: you can't upgrade a write lock! */
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+	return 1;
+}
+
+/* We only need to lock individual bytes, but Linux merges consecutive locks
+ * so we lock in contiguous ranges. */
+static int tdb_chainlock_gradual(struct tdb_context *tdb,
+				 int ltype, enum tdb_lock_flags flags,
+				 size_t off, size_t len)
+{
+	int ret;
+	enum tdb_lock_flags nb_flags = (flags & ~TDB_LOCK_WAIT);
+
+	if (len <= 4) {
+		/* Single record.  Just do blocking lock. */
+		return tdb_brlock(tdb, ltype, off, len, flags);
+	}
+
+	/* First we try non-blocking. */
+	ret = tdb_brlock(tdb, ltype, off, len, nb_flags);
+	if (ret == 0) {
+		return 0;
+	}
+
+	/* Try locking first half, then second. */
+	ret = tdb_chainlock_gradual(tdb, ltype, flags, off, len / 2);
+	if (ret == -1)
+		return -1;
+
+	ret = tdb_chainlock_gradual(tdb, ltype, flags,
+				    off + len / 2, len - len / 2);
+	if (ret == -1) {
+		tdb_brunlock(tdb, ltype, off, len / 2);
+		return -1;
+	}
+	return 0;
+}
+
+/* lock/unlock entire database.  It can only be upgradable if you have some
+ * other way of guaranteeing exclusivity (ie. transaction write lock).
+ * We do the locking gradually to avoid being starved by smaller locks. */
+int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
+		       enum tdb_lock_flags flags, bool upgradable)
+{
+	switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) {
+	case -1:
+		return -1;
+	case 0:
+		return 0;
+	}
+
+	/* We cover two kinds of locks:
+	 * 1) Normal chain locks.  Taken for almost all operations.
+	 * 3) Individual records locks.  Taken after normal or free
+	 *    chain locks.
+	 *
+	 * It is (1) which cause the starvation problem, so we're only
+	 * gradual for that. */
+	if (tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP,
+				  tdb->header.hash_size * 4) == -1) {
+		return -1;
+	}
+
+	/* Grab individual record locks. */
+	if (tdb_brlock(tdb, ltype, lock_offset(tdb->header.hash_size), 0,
+		       flags) == -1) {
+		tdb_brunlock(tdb, ltype, FREELIST_TOP,
+			     tdb->header.hash_size * 4);
+		return -1;
+	}
+
+	tdb->allrecord_lock.count = 1;
+	/* If it's upgradable, it's actually exclusive so we can treat
+	 * it as a write lock. */
+	tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype;
+	tdb->allrecord_lock.off = upgradable;
+
+	if (tdb_needs_recovery(tdb)) {
+		bool mark = flags & TDB_LOCK_MARK_ONLY;
+		tdb_allrecord_unlock(tdb, ltype, mark);
+		if (mark) {
+			tdb->ecode = TDB_ERR_LOCK;
+			TDB_LOG((tdb, TDB_DEBUG_ERROR,
+				 "tdb_lockall_mark cannot do recovery\n"));
+			return -1;
+		}
+		if (tdb_lock_and_recover(tdb) == -1) {
+			return -1;
+		}
+		return tdb_allrecord_lock(tdb, ltype, flags, upgradable);
+	}
+
+	return 0;
+}
+
+
+
+/* unlock entire db */
+int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock)
+{
+	/* There are no locks on read-only dbs */
+	if (tdb->read_only || tdb->traverse_read) {
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	if (tdb->allrecord_lock.count == 0) {
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	/* Upgradable locks are marked as write locks. */
+	if (tdb->allrecord_lock.ltype != ltype
+	    && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) {
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	if (tdb->allrecord_lock.count > 1) {
+		tdb->allrecord_lock.count--;
+		return 0;
+	}
+
+	if (!mark_lock && tdb_brunlock(tdb, ltype, FREELIST_TOP, 0)) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno)));
+		return -1;
+	}
+
+	tdb->allrecord_lock.count = 0;
+	tdb->allrecord_lock.ltype = 0;
+
+	return 0;
+}
+
+/* lock entire database with write lock */
+int tdb_lockall(struct tdb_context *tdb)
+{
+	tdb_trace(tdb, "tdb_lockall");
+	return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
+}
+
+/* lock entire database with write lock - mark only */
+int tdb_lockall_mark(struct tdb_context *tdb)
+{
+	tdb_trace(tdb, "tdb_lockall_mark");
+	return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY, false);
+}
+
+/* unlock entire database with write lock - unmark only */
+int tdb_lockall_unmark(struct tdb_context *tdb)
+{
+	tdb_trace(tdb, "tdb_lockall_unmark");
+	return tdb_allrecord_unlock(tdb, F_WRLCK, true);
+}
+
+/* lock entire database with write lock - nonblocking varient */
+int tdb_lockall_nonblock(struct tdb_context *tdb)
+{
+	int ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false);
+	tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret);
+	return ret;
+}
+
+/* unlock entire database with write lock */
+int tdb_unlockall(struct tdb_context *tdb)
+{
+	tdb_trace(tdb, "tdb_unlockall");
+	return tdb_allrecord_unlock(tdb, F_WRLCK, false);
+}
+
+/* lock entire database with read lock */
+int tdb_lockall_read(struct tdb_context *tdb)
+{
+	tdb_trace(tdb, "tdb_lockall_read");
+	return tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false);
+}
+
+/* lock entire database with read lock - nonblock varient */
+int tdb_lockall_read_nonblock(struct tdb_context *tdb)
+{
+	int ret = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_NOWAIT, false);
+	tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret);
+	return ret;
+}
+
+/* unlock entire database with read lock */
+int tdb_unlockall_read(struct tdb_context *tdb)
+{
+	tdb_trace(tdb, "tdb_unlockall_read");
+	return tdb_allrecord_unlock(tdb, F_RDLCK, false);
+}
+
+/* lock/unlock one hash chain. This is meant to be used to reduce
+   contention - it cannot guarantee how many records will be locked */
+int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
+{
+	int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+	tdb_trace_1rec(tdb, "tdb_chainlock", key);
+	return ret;
+}
+
+/* lock/unlock one hash chain, non-blocking. This is meant to be used
+   to reduce contention - it cannot guarantee how many records will be
+   locked */
+int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)
+{
+	int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+	tdb_trace_1rec_ret(tdb, "tdb_chainlock_nonblock", key, ret);
+	return ret;
+}
+
+/* mark a chain as locked without actually locking it. Warning! use with great caution! */
+int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key)
+{
+	int ret = tdb_nest_lock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))),
+				F_WRLCK, TDB_LOCK_MARK_ONLY);
+	tdb_trace_1rec(tdb, "tdb_chainlock_mark", key);
+	return ret;
+}
+
+/* unmark a chain as locked without actually locking it. Warning! use with great caution! */
+int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)
+{
+	tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key);
+	return tdb_nest_unlock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))),
+			       F_WRLCK, true);
+}
+
+int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
+{
+	tdb_trace_1rec(tdb, "tdb_chainunlock", key);
+	return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+}
+
+int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)
+{
+	int ret;
+	ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+	tdb_trace_1rec(tdb, "tdb_chainlock_read", key);
+	return ret;
+}
+
+int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
+{
+	tdb_trace_1rec(tdb, "tdb_chainunlock_read", key);
+	return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+}
+
+
+
+/* record lock stops delete underneath */
+int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+	if (tdb->allrecord_lock.count) {
+		return 0;
+	}
+	return off ? tdb_brlock(tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT) : 0;
+}
+
+/*
+  Write locks override our own fcntl readlocks, so check it here.
+  Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+  an error to fail to get the lock here.
+*/
+int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+	struct tdb_traverse_lock *i;
+	for (i = &tdb->travlocks; i; i = i->next)
+		if (i->off == off)
+			return -1;
+	if (tdb->allrecord_lock.count) {
+		if (tdb->allrecord_lock.ltype == F_WRLCK) {
+			return 0;
+		}
+		return -1;
+	}
+	return tdb_brlock(tdb, F_WRLCK, off, 1, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
+}
+
+int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+	if (tdb->allrecord_lock.count) {
+		return 0;
+	}
+	return tdb_brunlock(tdb, F_WRLCK, off, 1);
+}
+
+/* fcntl locks don't stack: avoid unlocking someone else's */
+int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+	struct tdb_traverse_lock *i;
+	uint32_t count = 0;
+
+	if (tdb->allrecord_lock.count) {
+		return 0;
+	}
+
+	if (off == 0)
+		return 0;
+	for (i = &tdb->travlocks; i; i = i->next)
+		if (i->off == off)
+			count++;
+	return (count == 1 ? tdb_brunlock(tdb, F_RDLCK, off, 1) : 0);
+}
+
+bool tdb_have_extra_locks(struct tdb_context *tdb)
+{
+	unsigned int extra = tdb->num_lockrecs;
+
+	/* A transaction holds the lock for all records. */
+	if (!tdb->transaction && tdb->allrecord_lock.count) {
+		return true;
+	}
+
+	/* We always hold the active lock if CLEAR_IF_FIRST. */
+	if (find_nestlock(tdb, ACTIVE_LOCK)) {
+		extra--;
+	}
+
+	/* In a transaction, we expect to hold the transaction lock */
+	if (tdb->transaction && find_nestlock(tdb, TRANSACTION_LOCK)) {
+		extra--;
+	}
+
+	return extra;
+}
+
+/* The transaction code uses this to remove all locks. */
+void tdb_release_transaction_locks(struct tdb_context *tdb)
+{
+	unsigned int i, active = 0;
+
+	if (tdb->allrecord_lock.count != 0) {
+		tdb_brunlock(tdb, tdb->allrecord_lock.ltype, FREELIST_TOP, 0);
+		tdb->allrecord_lock.count = 0;
+	}
+
+	for (i=0;i<tdb->num_lockrecs;i++) {
+		struct tdb_lock_type *lck = &tdb->lockrecs[i];
+
+		/* Don't release the active lock!  Copy it to first entry. */
+		if (lck->off == ACTIVE_LOCK) {
+			tdb->lockrecs[active++] = *lck;
+		} else {
+			tdb_brunlock(tdb, lck->ltype, lck->off, 1);
+		}
+	}
+	tdb->num_lockrecs = active;
+	if (tdb->num_lockrecs == 0) {
+		SAFE_FREE(tdb->lockrecs);
+	}
+}
+
+int tdb_transaction_write_lock_mark(struct tdb_context *tdb)
+{
+	return tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY);
+}
+
+int tdb_transaction_write_lock(struct tdb_context *tdb)
+{
+	return tdb_transaction_lock(tdb, F_WRLCK, 0);
+}
+
+int tdb_transaction_write_unlock(struct tdb_context *tdb)
+{
+	return tdb_transaction_unlock(tdb, F_WRLCK);
+}
+
+int tdb_transaction_write_lock_unmark(struct tdb_context *tdb)
+{
+	return tdb_nest_unlock(tdb, TRANSACTION_LOCK, F_WRLCK, true);
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/common/open.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/open.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/open.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,614 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              1999-2005
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000-2003
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
+static struct tdb_context *tdbs = NULL;
+
+/* We use two hashes to double-check they're using the right hash function. */
+void tdb_header_hash(struct tdb_context *tdb,
+		     uint32_t *magic1_hash, uint32_t *magic2_hash)
+{
+	TDB_DATA hash_key;
+	uint32_t tdb_magic = TDB_MAGIC;
+
+	hash_key.dptr = discard_const_p(unsigned char, TDB_MAGIC_FOOD);
+	hash_key.dsize = sizeof(TDB_MAGIC_FOOD);
+	*magic1_hash = tdb->hash_fn(&hash_key);
+
+	hash_key.dptr = (unsigned char *)CONVERT(tdb_magic);
+	hash_key.dsize = sizeof(tdb_magic);
+	*magic2_hash = tdb->hash_fn(&hash_key);
+
+	/* Make sure at least one hash is non-zero! */
+	if (*magic1_hash == 0 && *magic2_hash == 0)
+		*magic1_hash = 1;
+}
+
+/* initialise a new database with a specified hash size */
+static int tdb_new_database(struct tdb_context *tdb, int hash_size)
+{
+	struct tdb_header *newdb;
+	size_t size;
+	int ret = -1;
+
+	/* We make it up in memory, then write it out if not internal */
+	size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t);
+	if (!(newdb = (struct tdb_header *)calloc(size, 1))) {
+		tdb->ecode = TDB_ERR_OOM;
+		return -1;
+	}
+
+	/* Fill in the header */
+	newdb->version = TDB_VERSION;
+	newdb->hash_size = hash_size;
+
+	tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash);
+
+	/* Make sure older tdbs (which don't check the magic hash fields)
+	 * will refuse to open this TDB. */
+	if (tdb->flags & TDB_INCOMPATIBLE_HASH)
+		newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC;
+
+	if (tdb->flags & TDB_INTERNAL) {
+		tdb->map_size = size;
+		tdb->map_ptr = (char *)newdb;
+		memcpy(&tdb->header, newdb, sizeof(tdb->header));
+		/* Convert the `ondisk' version if asked. */
+		CONVERT(*newdb);
+		return 0;
+	}
+	if (lseek(tdb->fd, 0, SEEK_SET) == -1)
+		goto fail;
+
+	if (ftruncate(tdb->fd, 0) == -1)
+		goto fail;
+
+	/* This creates an endian-converted header, as if read from disk */
+	CONVERT(*newdb);
+	memcpy(&tdb->header, newdb, sizeof(tdb->header));
+	/* Don't endian-convert the magic food! */
+	memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
+	/* we still have "ret == -1" here */
+	if (tdb_write_all(tdb->fd, newdb, size))
+		ret = 0;
+
+  fail:
+	SAFE_FREE(newdb);
+	return ret;
+}
+
+
+
+static int tdb_already_open(dev_t device,
+			    ino_t ino)
+{
+	struct tdb_context *i;
+
+	for (i = tdbs; i; i = i->next) {
+		if (i->device == device && i->inode == ino) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* open the database, creating it if necessary 
+
+   The open_flags and mode are passed straight to the open call on the
+   database file. A flags value of O_WRONLY is invalid. The hash size
+   is advisory, use zero for a default value.
+
+   Return is NULL on error, in which case errno is also set.  Don't 
+   try to call tdb_error or tdb_errname, just do strerror(errno).
+
+   @param name may be NULL for internal databases. */
+struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
+		      int open_flags, mode_t mode)
+{
+	return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL);
+}
+
+/* a default logging function */
+static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+}
+
+static bool check_header_hash(struct tdb_context *tdb,
+			      bool default_hash, uint32_t *m1, uint32_t *m2)
+{
+	tdb_header_hash(tdb, m1, m2);
+	if (tdb->header.magic1_hash == *m1 &&
+	    tdb->header.magic2_hash == *m2) {
+		return true;
+	}
+
+	/* If they explicitly set a hash, always respect it. */
+	if (!default_hash)
+		return false;
+
+	/* Otherwise, try the other inbuilt hash. */
+	if (tdb->hash_fn == tdb_old_hash)
+		tdb->hash_fn = tdb_jenkins_hash;
+	else
+		tdb->hash_fn = tdb_old_hash;
+	return check_header_hash(tdb, false, m1, m2);
+}
+
+struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+				int open_flags, mode_t mode,
+				const struct tdb_logging_context *log_ctx,
+				tdb_hash_func hash_fn)
+{
+	struct tdb_context *tdb;
+	struct stat st;
+	int rev = 0, locked = 0;
+	unsigned char *vp;
+	uint32_t vertest;
+	unsigned v;
+	const char *hash_alg;
+	uint32_t magic1, magic2;
+
+	if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
+		/* Can't log this */
+		errno = ENOMEM;
+		goto fail;
+	}
+	tdb_io_init(tdb);
+	tdb->fd = -1;
+#ifdef TDB_TRACE
+	tdb->tracefd = -1;
+#endif
+	tdb->name = NULL;
+	tdb->map_ptr = NULL;
+	tdb->flags = tdb_flags;
+	tdb->open_flags = open_flags;
+	if (log_ctx) {
+		tdb->log = *log_ctx;
+	} else {
+		tdb->log.log_fn = null_log_fn;
+		tdb->log.log_private = NULL;
+	}
+
+	if (hash_fn) {
+		tdb->hash_fn = hash_fn;
+		hash_alg = "the user defined";
+	} else {
+		/* This controls what we use when creating a tdb. */
+		if (tdb->flags & TDB_INCOMPATIBLE_HASH) {
+			tdb->hash_fn = tdb_jenkins_hash;
+		} else {
+			tdb->hash_fn = tdb_old_hash;
+		}
+		hash_alg = "either default";
+	}
+
+	/* cache the page size */
+	tdb->page_size = getpagesize();
+	if (tdb->page_size <= 0) {
+		tdb->page_size = 0x2000;
+	}
+
+	tdb->max_dead_records = (tdb_flags & TDB_VOLATILE) ? 5 : 0;
+
+	if ((open_flags & O_ACCMODE) == O_WRONLY) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n",
+			 name));
+		errno = EINVAL;
+		goto fail;
+	}
+
+	if (hash_size == 0)
+		hash_size = DEFAULT_HASH_SIZE;
+	if ((open_flags & O_ACCMODE) == O_RDONLY) {
+		tdb->read_only = 1;
+		/* read only databases don't do locking or clear if first */
+		tdb->flags |= TDB_NOLOCK;
+		tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+	}
+
+	if ((tdb->flags & TDB_ALLOW_NESTING) &&
+	    (tdb->flags & TDB_DISALLOW_NESTING)) {
+		tdb->ecode = TDB_ERR_NESTING;
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+			"allow_nesting and disallow_nesting are not allowed together!"));
+		errno = EINVAL;
+		goto fail;
+	}
+
+	if (getenv("TDB_NO_FSYNC")) {
+		tdb->flags |= TDB_NOSYNC;
+	}
+
+	/*
+	 * TDB_ALLOW_NESTING is the default behavior.
+	 * Note: this may change in future versions!
+	 */
+	if (!(tdb->flags & TDB_DISALLOW_NESTING)) {
+		tdb->flags |= TDB_ALLOW_NESTING;
+	}
+
+	/* internal databases don't mmap or lock, and start off cleared */
+	if (tdb->flags & TDB_INTERNAL) {
+		tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
+		tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+		if (tdb_new_database(tdb, hash_size) != 0) {
+			TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
+			goto fail;
+		}
+		goto internal;
+	}
+
+	if ((tdb->fd = open(name, open_flags, mode)) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n",
+			 name, strerror(errno)));
+		goto fail;	/* errno set by open(2) */
+	}
+
+	/* on exec, don't inherit the fd */
+	v = fcntl(tdb->fd, F_GETFD, 0);
+        fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC);
+
+	/* ensure there is only one process initialising at once */
+	if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n",
+			 name, strerror(errno)));
+		goto fail;	/* errno set by tdb_brlock */
+	}
+
+	/* we need to zero database if we are the only one with it open */
+	if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
+	    (!tdb->read_only) &&
+	    (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
+		open_flags |= O_CREAT;
+		if (ftruncate(tdb->fd, 0) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+				 "failed to truncate %s: %s\n",
+				 name, strerror(errno)));
+			goto fail; /* errno set by ftruncate */
+		}
+	}
+
+	errno = 0;
+	if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
+	    || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0) {
+		if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
+			if (errno == 0) {
+				errno = EIO; /* ie bad format or something */
+			}
+			goto fail;
+		}
+		rev = (tdb->flags & TDB_CONVERT);
+	} else if (tdb->header.version != TDB_VERSION
+		   && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION)))) {
+		/* wrong version */
+		errno = EIO;
+		goto fail;
+	}
+	vp = (unsigned char *)&tdb->header.version;
+	vertest = (((uint32_t)vp[0]) << 24) | (((uint32_t)vp[1]) << 16) |
+		  (((uint32_t)vp[2]) << 8) | (uint32_t)vp[3];
+	tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
+	if (!rev)
+		tdb->flags &= ~TDB_CONVERT;
+	else {
+		tdb->flags |= TDB_CONVERT;
+		tdb_convert(&tdb->header, sizeof(tdb->header));
+	}
+	if (fstat(tdb->fd, &st) == -1)
+		goto fail;
+
+	if (tdb->header.rwlocks != 0 &&
+	    tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
+		goto fail;
+	}
+
+	if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) {
+		/* older TDB without magic hash references */
+		tdb->hash_fn = tdb_old_hash;
+	} else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+			 "%s was not created with %s hash function we are using\n"
+			 "magic1_hash[0x%08X %s 0x%08X] "
+			 "magic2_hash[0x%08X %s 0x%08X]\n",
+			 name, hash_alg,
+			 tdb->header.magic1_hash,
+			 (tdb->header.magic1_hash == magic1) ? "==" : "!=",
+			 magic1,
+			 tdb->header.magic2_hash,
+			 (tdb->header.magic2_hash == magic2) ? "==" : "!=",
+			 magic2));
+		errno = EINVAL;
+		goto fail;
+	}
+
+	/* Is it already in the open list?  If so, fail. */
+	if (tdb_already_open(st.st_dev, st.st_ino)) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+			 "%s (%d,%d) is already open in this process\n",
+			 name, (int)st.st_dev, (int)st.st_ino));
+		errno = EBUSY;
+		goto fail;
+	}
+
+	if (!(tdb->name = (char *)strdup(name))) {
+		errno = ENOMEM;
+		goto fail;
+	}
+
+	tdb->map_size = st.st_size;
+	tdb->device = st.st_dev;
+	tdb->inode = st.st_ino;
+	tdb_mmap(tdb);
+	if (locked) {
+		if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+				 "failed to release ACTIVE_LOCK on %s: %s\n",
+				 name, strerror(errno)));
+			goto fail;
+		}
+
+	}
+
+	/* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
+	   we didn't get the initial exclusive lock as we need to let all other
+	   users know we're using it. */
+
+	if (tdb_flags & TDB_CLEAR_IF_FIRST) {
+		/* leave this lock in place to indicate it's in use */
+		if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
+			goto fail;
+		}
+	}
+
+	/* if needed, run recovery */
+	if (tdb_transaction_recover(tdb) == -1) {
+		goto fail;
+	}
+
+#ifdef TDB_TRACE
+	{
+		char tracefile[strlen(name) + 32];
+
+		snprintf(tracefile, sizeof(tracefile),
+			 "%s.trace.%li", name, (long)getpid());
+		tdb->tracefd = open(tracefile, O_WRONLY|O_CREAT|O_EXCL, 0600);
+		if (tdb->tracefd >= 0) {
+			tdb_enable_seqnum(tdb);
+			tdb_trace_open(tdb, "tdb_open", hash_size, tdb_flags,
+				       open_flags);
+		} else
+			TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to open trace file %s!\n", tracefile));
+	}
+#endif
+
+ internal:
+	/* Internal (memory-only) databases skip all the code above to
+	 * do with disk files, and resume here by releasing their
+	 * open lock and hooking into the active list. */
+	if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) {
+		goto fail;
+	}
+	tdb->next = tdbs;
+	tdbs = tdb;
+	return tdb;
+
+ fail:
+	{ int save_errno = errno;
+
+	if (!tdb)
+		return NULL;
+
+#ifdef TDB_TRACE
+	close(tdb->tracefd);
+#endif
+	if (tdb->map_ptr) {
+		if (tdb->flags & TDB_INTERNAL)
+			SAFE_FREE(tdb->map_ptr);
+		else
+			tdb_munmap(tdb);
+	}
+	SAFE_FREE(tdb->name);
+	if (tdb->fd != -1)
+		if (close(tdb->fd) != 0)
+			TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
+	SAFE_FREE(tdb->lockrecs);
+	SAFE_FREE(tdb);
+	errno = save_errno;
+	return NULL;
+	}
+}
+
+/*
+ * Set the maximum number of dead records per hash chain
+ */
+
+void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
+{
+	tdb->max_dead_records = max_dead;
+}
+
+/**
+ * Close a database.
+ *
+ * @returns -1 for error; 0 for success.
+ **/
+int tdb_close(struct tdb_context *tdb)
+{
+	struct tdb_context **i;
+	int ret = 0;
+
+	if (tdb->transaction) {
+		tdb_transaction_cancel(tdb);
+	}
+	tdb_trace(tdb, "tdb_close");
+
+	if (tdb->map_ptr) {
+		if (tdb->flags & TDB_INTERNAL)
+			SAFE_FREE(tdb->map_ptr);
+		else
+			tdb_munmap(tdb);
+	}
+	SAFE_FREE(tdb->name);
+	if (tdb->fd != -1) {
+		ret = close(tdb->fd);
+		tdb->fd = -1;
+	}
+	SAFE_FREE(tdb->lockrecs);
+
+	/* Remove from contexts list */
+	for (i = &tdbs; *i; i = &(*i)->next) {
+		if (*i == tdb) {
+			*i = tdb->next;
+			break;
+		}
+	}
+
+#ifdef TDB_TRACE
+	close(tdb->tracefd);
+#endif
+	memset(tdb, 0, sizeof(*tdb));
+	SAFE_FREE(tdb);
+
+	return ret;
+}
+
+/* register a loging function */
+void tdb_set_logging_function(struct tdb_context *tdb,
+                              const struct tdb_logging_context *log_ctx)
+{
+        tdb->log = *log_ctx;
+}
+
+void *tdb_get_logging_private(struct tdb_context *tdb)
+{
+	return tdb->log.log_private;
+}
+
+static int tdb_reopen_internal(struct tdb_context *tdb, bool active_lock)
+{
+#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \
+	!defined(LIBREPLACE_PWRITE_NOT_REPLACED)
+	struct stat st;
+#endif
+
+	if (tdb->flags & TDB_INTERNAL) {
+		return 0; /* Nothing to do. */
+	}
+
+	if (tdb_have_extra_locks(tdb)) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
+		goto fail;
+	}
+
+	if (tdb->transaction != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n"));
+		goto fail;
+	}
+
+/* If we have real pread & pwrite, we can skip reopen. */
+#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \
+	!defined(LIBREPLACE_PWRITE_NOT_REPLACED)
+	if (tdb_munmap(tdb) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
+		goto fail;
+	}
+	if (close(tdb->fd) != 0)
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
+	tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
+	if (tdb->fd == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno)));
+		goto fail;
+	}
+	if (fstat(tdb->fd, &st) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
+		goto fail;
+	}
+	if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n"));
+		goto fail;
+	}
+	tdb_mmap(tdb);
+#endif /* fake pread or pwrite */
+
+	/* We may still think we hold the active lock. */
+	tdb->num_lockrecs = 0;
+	SAFE_FREE(tdb->lockrecs);
+
+	if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	tdb_close(tdb);
+	return -1;
+}
+
+/* reopen a tdb - this can be used after a fork to ensure that we have an independent
+   seek pointer from our parent and to re-establish locks */
+int tdb_reopen(struct tdb_context *tdb)
+{
+	return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST);
+}
+
+/* reopen all tdb's */
+int tdb_reopen_all(int parent_longlived)
+{
+	struct tdb_context *tdb;
+
+	for (tdb=tdbs; tdb; tdb = tdb->next) {
+		bool active_lock = (tdb->flags & TDB_CLEAR_IF_FIRST);
+
+		/*
+		 * If the parent is longlived (ie. a
+		 * parent daemon architecture), we know
+		 * it will keep it's active lock on a
+		 * tdb opened with CLEAR_IF_FIRST. Thus
+		 * for child processes we don't have to
+		 * add an active lock. This is essential
+		 * to improve performance on systems that
+		 * keep POSIX locks as a non-scalable data
+		 * structure in the kernel.
+		 */
+		if (parent_longlived) {
+			/* Ensure no clear-if-first. */
+			active_lock = false;
+		}
+
+		if (tdb_reopen_internal(tdb, active_lock) != 0)
+			return -1;
+	}
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/common/tdb.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/tdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/tdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1157 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              1999-2005
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000-2003
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+TDB_DATA tdb_null;
+
+/*
+  non-blocking increment of the tdb sequence number if the tdb has been opened using
+  the TDB_SEQNUM flag
+*/
+void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
+{
+	tdb_off_t seqnum=0;
+
+	if (!(tdb->flags & TDB_SEQNUM)) {
+		return;
+	}
+
+	/* we ignore errors from this, as we have no sane way of
+	   dealing with them.
+	*/
+	tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+	seqnum++;
+	tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
+}
+
+/*
+  increment the tdb sequence number if the tdb has been opened using
+  the TDB_SEQNUM flag
+*/
+static void tdb_increment_seqnum(struct tdb_context *tdb)
+{
+	if (!(tdb->flags & TDB_SEQNUM)) {
+		return;
+	}
+
+	if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK,
+			  TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) {
+		return;
+	}
+
+	tdb_increment_seqnum_nonblock(tdb);
+
+	tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false);
+}
+
+static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+	return memcmp(data.dptr, key.dptr, data.dsize);
+}
+
+/* Returns 0 on fail.  On success, return offset of record, and fills
+   in rec */
+static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
+			struct tdb_record *r)
+{
+	tdb_off_t rec_ptr;
+
+	/* read in the hash top */
+	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+		return 0;
+
+	/* keep looking until we find the right record */
+	while (rec_ptr) {
+		if (tdb_rec_read(tdb, rec_ptr, r) == -1)
+			return 0;
+
+		if (!TDB_DEAD(r) && hash==r->full_hash
+		    && key.dsize==r->key_len
+		    && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
+				      r->key_len, tdb_key_compare,
+				      NULL) == 0) {
+			return rec_ptr;
+		}
+		/* detect tight infinite loop */
+		if (rec_ptr == r->next) {
+			tdb->ecode = TDB_ERR_CORRUPT;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_find: loop detected.\n"));
+			return 0;
+		}
+		rec_ptr = r->next;
+	}
+	tdb->ecode = TDB_ERR_NOEXIST;
+	return 0;
+}
+
+/* As tdb_find, but if you succeed, keep the lock */
+tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
+			   struct tdb_record *rec)
+{
+	uint32_t rec_ptr;
+
+	if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
+		return 0;
+	if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
+		tdb_unlock(tdb, BUCKET(hash), locktype);
+	return rec_ptr;
+}
+
+static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
+
+/* update an entry in place - this only works if the new data size
+   is <= the old data size and the key exists.
+   on failure return -1.
+*/
+static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf)
+{
+	struct tdb_record rec;
+	tdb_off_t rec_ptr;
+
+	/* find entry */
+	if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
+		return -1;
+
+	/* it could be an exact duplicate of what is there - this is
+	 * surprisingly common (eg. with a ldb re-index). */
+	if (rec.key_len == key.dsize && 
+	    rec.data_len == dbuf.dsize &&
+	    rec.full_hash == hash) {
+		TDB_DATA data = _tdb_fetch(tdb, key);
+		if (data.dsize == dbuf.dsize &&
+		    memcmp(data.dptr, dbuf.dptr, data.dsize) == 0) {
+			if (data.dptr) {
+				free(data.dptr);
+			}
+			return 0;
+		}
+		if (data.dptr) {
+			free(data.dptr);
+		}
+	}
+
+	/* must be long enough key, data and tailer */
+	if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) {
+		tdb->ecode = TDB_SUCCESS; /* Not really an error */
+		return -1;
+	}
+
+	if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+		      dbuf.dptr, dbuf.dsize) == -1)
+		return -1;
+
+	if (dbuf.dsize != rec.data_len) {
+		/* update size */
+		rec.data_len = dbuf.dsize;
+		return tdb_rec_write(tdb, rec_ptr, &rec);
+	}
+
+	return 0;
+}
+
+/* find an entry in the database given a key */
+/* If an entry doesn't exist tdb_err will be set to
+ * TDB_ERR_NOEXIST. If a key has no data attached
+ * then the TDB_DATA will have zero length but
+ * a non-zero pointer
+ */
+static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
+{
+	tdb_off_t rec_ptr;
+	struct tdb_record rec;
+	TDB_DATA ret;
+	uint32_t hash;
+
+	/* find which hash bucket it is in */
+	hash = tdb->hash_fn(&key);
+	if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
+		return tdb_null;
+
+	ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+				  rec.data_len);
+	ret.dsize = rec.data_len;
+	tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+	return ret;
+}
+
+TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
+{
+	TDB_DATA ret = _tdb_fetch(tdb, key);
+
+	tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
+	return ret;
+}
+
+/*
+ * Find an entry in the database and hand the record's data to a parsing
+ * function. The parsing function is executed under the chain read lock, so it
+ * should be fast and should not block on other syscalls.
+ *
+ * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
+ *
+ * For mmapped tdb's that do not have a transaction open it points the parsing
+ * function directly at the mmap area, it avoids the malloc/memcpy in this
+ * case. If a transaction is open or no mmap is available, it has to do
+ * malloc/read/parse/free.
+ *
+ * This is interesting for all readers of potentially large data structures in
+ * the tdb records, ldb indexes being one example.
+ *
+ * Return -1 if the record was not found.
+ */
+
+int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
+		     int (*parser)(TDB_DATA key, TDB_DATA data,
+				   void *private_data),
+		     void *private_data)
+{
+	tdb_off_t rec_ptr;
+	struct tdb_record rec;
+	int ret;
+	uint32_t hash;
+
+	/* find which hash bucket it is in */
+	hash = tdb->hash_fn(&key);
+
+	if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
+		/* record not found */
+		tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
+		tdb->ecode = TDB_ERR_NOEXIST;
+		return -1;
+	}
+	tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
+
+	ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
+			     rec.data_len, parser, private_data);
+
+	tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+
+	return ret;
+}
+
+/* check if an entry in the database exists 
+
+   note that 1 is returned if the key is found and 0 is returned if not found
+   this doesn't match the conventions in the rest of this module, but is
+   compatible with gdbm
+*/
+static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
+{
+	struct tdb_record rec;
+
+	if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
+		return 0;
+	tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+	return 1;
+}
+
+int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
+{
+	uint32_t hash = tdb->hash_fn(&key);
+	int ret;
+
+	ret = tdb_exists_hash(tdb, key, hash);
+	tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
+	return ret;
+}
+
+/* actually delete an entry in the database given the offset */
+int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec)
+{
+	tdb_off_t last_ptr, i;
+	struct tdb_record lastrec;
+
+	if (tdb->read_only || tdb->traverse_read) return -1;
+
+	if (((tdb->traverse_write != 0) && (!TDB_DEAD(rec))) ||
+	    tdb_write_lock_record(tdb, rec_ptr) == -1) {
+		/* Someone traversing here: mark it as dead */
+		rec->magic = TDB_DEAD_MAGIC;
+		return tdb_rec_write(tdb, rec_ptr, rec);
+	}
+	if (tdb_write_unlock_record(tdb, rec_ptr) != 0)
+		return -1;
+
+	/* find previous record in hash chain */
+	if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
+		return -1;
+	for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
+		if (tdb_rec_read(tdb, i, &lastrec) == -1)
+			return -1;
+
+	/* unlink it: next ptr is at start of record. */
+	if (last_ptr == 0)
+		last_ptr = TDB_HASH_TOP(rec->full_hash);
+	if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1)
+		return -1;
+
+	/* recover the space */
+	if (tdb_free(tdb, rec_ptr, rec) == -1)
+		return -1;
+	return 0;
+}
+
+static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash)
+{
+	int res = 0;
+	tdb_off_t rec_ptr;
+	struct tdb_record rec;
+
+	/* read in the hash top */
+	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+		return 0;
+
+	while (rec_ptr) {
+		if (tdb_rec_read(tdb, rec_ptr, &rec) == -1)
+			return 0;
+
+		if (rec.magic == TDB_DEAD_MAGIC) {
+			res += 1;
+		}
+		rec_ptr = rec.next;
+	}
+	return res;
+}
+
+/*
+ * Purge all DEAD records from a hash chain
+ */
+static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
+{
+	int res = -1;
+	struct tdb_record rec;
+	tdb_off_t rec_ptr;
+
+	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+		return -1;
+	}
+
+	/* read in the hash top */
+	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+		goto fail;
+
+	while (rec_ptr) {
+		tdb_off_t next;
+
+		if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) {
+			goto fail;
+		}
+
+		next = rec.next;
+
+		if (rec.magic == TDB_DEAD_MAGIC
+		    && tdb_do_delete(tdb, rec_ptr, &rec) == -1) {
+			goto fail;
+		}
+		rec_ptr = next;
+	}
+	res = 0;
+ fail:
+	tdb_unlock(tdb, -1, F_WRLCK);
+	return res;
+}
+
+/* delete an entry in the database given a key */
+static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
+{
+	tdb_off_t rec_ptr;
+	struct tdb_record rec;
+	int ret;
+
+	if (tdb->max_dead_records != 0) {
+
+		/*
+		 * Allow for some dead records per hash chain, mainly for
+		 * tdb's with a very high create/delete rate like locking.tdb.
+		 */
+
+		if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+			return -1;
+
+		if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) {
+			/*
+			 * Don't let the per-chain freelist grow too large,
+			 * delete all existing dead records
+			 */
+			tdb_purge_dead(tdb, hash);
+		}
+
+		if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {
+			tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+			return -1;
+		}
+
+		/*
+		 * Just mark the record as dead.
+		 */
+		rec.magic = TDB_DEAD_MAGIC;
+		ret = tdb_rec_write(tdb, rec_ptr, &rec);
+	}
+	else {
+		if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK,
+						   &rec)))
+			return -1;
+
+		ret = tdb_do_delete(tdb, rec_ptr, &rec);
+	}
+
+	if (ret == 0) {
+		tdb_increment_seqnum(tdb);
+	}
+
+	if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
+		TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
+	return ret;
+}
+
+int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
+{
+	uint32_t hash = tdb->hash_fn(&key);
+	int ret;
+
+	ret = tdb_delete_hash(tdb, key, hash);
+	tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
+	return ret;
+}
+
+/*
+ * See if we have a dead record around with enough space
+ */
+static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
+			       struct tdb_record *r, tdb_len_t length)
+{
+	tdb_off_t rec_ptr;
+
+	/* read in the hash top */
+	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+		return 0;
+
+	/* keep looking until we find the right record */
+	while (rec_ptr) {
+		if (tdb_rec_read(tdb, rec_ptr, r) == -1)
+			return 0;
+
+		if (TDB_DEAD(r) && r->rec_len >= length) {
+			/*
+			 * First fit for simple coding, TODO: change to best
+			 * fit
+			 */
+			return rec_ptr;
+		}
+		rec_ptr = r->next;
+	}
+	return 0;
+}
+
+static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
+		       TDB_DATA dbuf, int flag, uint32_t hash)
+{
+	struct tdb_record rec;
+	tdb_off_t rec_ptr;
+	char *p = NULL;
+	int ret = -1;
+
+	/* check for it existing, on insert. */
+	if (flag == TDB_INSERT) {
+		if (tdb_exists_hash(tdb, key, hash)) {
+			tdb->ecode = TDB_ERR_EXISTS;
+			goto fail;
+		}
+	} else {
+		/* first try in-place update, on modify or replace. */
+		if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {
+			goto done;
+		}
+		if (tdb->ecode == TDB_ERR_NOEXIST &&
+		    flag == TDB_MODIFY) {
+			/* if the record doesn't exist and we are in TDB_MODIFY mode then
+			 we should fail the store */
+			goto fail;
+		}
+	}
+	/* reset the error code potentially set by the tdb_update() */
+	tdb->ecode = TDB_SUCCESS;
+
+	/* delete any existing record - if it doesn't exist we don't
+           care.  Doing this first reduces fragmentation, and avoids
+           coalescing with `allocated' block before it's updated. */
+	if (flag != TDB_INSERT)
+		tdb_delete_hash(tdb, key, hash);
+
+	/* Copy key+value *before* allocating free space in case malloc
+	   fails and we are left with a dead spot in the tdb. */
+
+	if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
+		tdb->ecode = TDB_ERR_OOM;
+		goto fail;
+	}
+
+	memcpy(p, key.dptr, key.dsize);
+	if (dbuf.dsize)
+		memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
+
+	if (tdb->max_dead_records != 0) {
+		/*
+		 * Allow for some dead records per hash chain, look if we can
+		 * find one that can hold the new record. We need enough space
+		 * for key, data and tailer. If we find one, we don't have to
+		 * consult the central freelist.
+		 */
+		rec_ptr = tdb_find_dead(
+			tdb, hash, &rec,
+			key.dsize + dbuf.dsize + sizeof(tdb_off_t));
+
+		if (rec_ptr != 0) {
+			rec.key_len = key.dsize;
+			rec.data_len = dbuf.dsize;
+			rec.full_hash = hash;
+			rec.magic = TDB_MAGIC;
+			if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
+			    || tdb->methods->tdb_write(
+				    tdb, rec_ptr + sizeof(rec),
+				    p, key.dsize + dbuf.dsize) == -1) {
+				goto fail;
+			}
+			goto done;
+		}
+	}
+
+	/*
+	 * We have to allocate some space from the freelist, so this means we
+	 * have to lock it. Use the chance to purge all the DEAD records from
+	 * the hash chain under the freelist lock.
+	 */
+
+	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+		goto fail;
+	}
+
+	if ((tdb->max_dead_records != 0)
+	    && (tdb_purge_dead(tdb, hash) == -1)) {
+		tdb_unlock(tdb, -1, F_WRLCK);
+		goto fail;
+	}
+
+	/* we have to allocate some space */
+	rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
+
+	tdb_unlock(tdb, -1, F_WRLCK);
+
+	if (rec_ptr == 0) {
+		goto fail;
+	}
+
+	/* Read hash top into next ptr */
+	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
+		goto fail;
+
+	rec.key_len = key.dsize;
+	rec.data_len = dbuf.dsize;
+	rec.full_hash = hash;
+	rec.magic = TDB_MAGIC;
+
+	/* write out and point the top of the hash chain at it */
+	if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
+	    || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
+	    || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
+		/* Need to tdb_unallocate() here */
+		goto fail;
+	}
+
+ done:
+	ret = 0;
+ fail:
+	if (ret == 0) {
+		tdb_increment_seqnum(tdb);
+	}
+
+	SAFE_FREE(p); 
+	return ret;
+}
+
+/* store an element in the database, replacing any existing element
+   with the same key
+
+   return 0 on success, -1 on failure
+*/
+int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+{
+	uint32_t hash;
+	int ret;
+
+	if (tdb->read_only || tdb->traverse_read) {
+		tdb->ecode = TDB_ERR_RDONLY;
+		tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1);
+		return -1;
+	}
+
+	/* find which hash bucket it is in */
+	hash = tdb->hash_fn(&key);
+	if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+		return -1;
+
+	ret = _tdb_store(tdb, key, dbuf, flag, hash);
+	tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
+	tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+	return ret;
+}
+
+/* Append to an entry. Create if not exist. */
+int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
+{
+	uint32_t hash;
+	TDB_DATA dbuf;
+	int ret = -1;
+
+	/* find which hash bucket it is in */
+	hash = tdb->hash_fn(&key);
+	if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+		return -1;
+
+	dbuf = _tdb_fetch(tdb, key);
+
+	if (dbuf.dptr == NULL) {
+		dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
+	} else {
+		unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
+		unsigned char *new_dptr;
+
+		/* realloc '0' is special: don't do that. */
+		if (new_len == 0)
+			new_len = 1;
+		new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
+		if (new_dptr == NULL) {
+			free(dbuf.dptr);
+		}
+		dbuf.dptr = new_dptr;
+	}
+
+	if (dbuf.dptr == NULL) {
+		tdb->ecode = TDB_ERR_OOM;
+		goto failed;
+	}
+
+	memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
+	dbuf.dsize += new_dbuf.dsize;
+
+	ret = _tdb_store(tdb, key, dbuf, 0, hash);
+	tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf);
+
+failed:
+	tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+	SAFE_FREE(dbuf.dptr);
+	return ret;
+}
+
+
+/*
+  return the name of the current tdb file
+  useful for external logging functions
+*/
+const char *tdb_name(struct tdb_context *tdb)
+{
+	return tdb->name;
+}
+
+/*
+  return the underlying file descriptor being used by tdb, or -1
+  useful for external routines that want to check the device/inode
+  of the fd
+*/
+int tdb_fd(struct tdb_context *tdb)
+{
+	return tdb->fd;
+}
+
+/*
+  return the current logging function
+  useful for external tdb routines that wish to log tdb errors
+*/
+tdb_log_func tdb_log_fn(struct tdb_context *tdb)
+{
+	return tdb->log.log_fn;
+}
+
+
+/*
+  get the tdb sequence number. Only makes sense if the writers opened
+  with TDB_SEQNUM set. Note that this sequence number will wrap quite
+  quickly, so it should only be used for a 'has something changed'
+  test, not for code that relies on the count of the number of changes
+  made. If you want a counter then use a tdb record.
+
+  The aim of this sequence number is to allow for a very lightweight
+  test of a possible tdb change.
+*/
+int tdb_get_seqnum(struct tdb_context *tdb)
+{
+	tdb_off_t seqnum=0;
+
+	tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+	return seqnum;
+}
+
+int tdb_hash_size(struct tdb_context *tdb)
+{
+	return tdb->header.hash_size;
+}
+
+size_t tdb_map_size(struct tdb_context *tdb)
+{
+	return tdb->map_size;
+}
+
+int tdb_get_flags(struct tdb_context *tdb)
+{
+	return tdb->flags;
+}
+
+void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
+{
+	if ((flags & TDB_ALLOW_NESTING) &&
+	    (flags & TDB_DISALLOW_NESTING)) {
+		tdb->ecode = TDB_ERR_NESTING;
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_add_flags: "
+			"allow_nesting and disallow_nesting are not allowed together!"));
+		return;
+	}
+
+	if (flags & TDB_ALLOW_NESTING) {
+		tdb->flags &= ~TDB_DISALLOW_NESTING;
+	}
+	if (flags & TDB_DISALLOW_NESTING) {
+		tdb->flags &= ~TDB_ALLOW_NESTING;
+	}
+
+	tdb->flags |= flags;
+}
+
+void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
+{
+	if ((flags & TDB_ALLOW_NESTING) &&
+	    (flags & TDB_DISALLOW_NESTING)) {
+		tdb->ecode = TDB_ERR_NESTING;
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: "
+			"allow_nesting and disallow_nesting are not allowed together!"));
+		return;
+	}
+
+	if (flags & TDB_ALLOW_NESTING) {
+		tdb->flags |= TDB_DISALLOW_NESTING;
+	}
+	if (flags & TDB_DISALLOW_NESTING) {
+		tdb->flags |= TDB_ALLOW_NESTING;
+	}
+
+	tdb->flags &= ~flags;
+}
+
+
+/*
+  enable sequence number handling on an open tdb
+*/
+void tdb_enable_seqnum(struct tdb_context *tdb)
+{
+	tdb->flags |= TDB_SEQNUM;
+}
+
+
+/*
+  add a region of the file to the freelist. Length is the size of the region in bytes, 
+  which includes the free list header that needs to be added
+ */
+static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
+{
+	struct tdb_record rec;
+	if (length <= sizeof(rec)) {
+		/* the region is not worth adding */
+		return 0;
+	}
+	if (length + offset > tdb->map_size) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
+		return -1;		
+	}
+	memset(&rec,'\0',sizeof(rec));
+	rec.rec_len = length - sizeof(rec);
+	if (tdb_free(tdb, offset, &rec) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  wipe the entire database, deleting all records. This can be done
+  very fast by using a allrecord lock. The entire data portion of the
+  file becomes a single entry in the freelist.
+
+  This code carefully steps around the recovery area, leaving it alone
+ */
+int tdb_wipe_all(struct tdb_context *tdb)
+{
+	int i;
+	tdb_off_t offset = 0;
+	ssize_t data_len;
+	tdb_off_t recovery_head;
+	tdb_len_t recovery_size = 0;
+
+	if (tdb_lockall(tdb) != 0) {
+		return -1;
+	}
+
+	tdb_trace(tdb, "tdb_wipe_all");
+
+	/* see if the tdb has a recovery area, and remember its size
+	   if so. We don't want to lose this as otherwise each
+	   tdb_wipe_all() in a transaction will increase the size of
+	   the tdb by the size of the recovery area */
+	if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n"));
+		goto failed;
+	}
+
+	if (recovery_head != 0) {
+		struct tdb_record rec;
+		if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
+			return -1;
+		}	
+		recovery_size = rec.rec_len + sizeof(rec);
+	}
+
+	/* wipe the hashes */
+	for (i=0;i<tdb->header.hash_size;i++) {
+		if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
+			goto failed;
+		}
+	}
+
+	/* wipe the freelist */
+	if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
+		goto failed;
+	}
+
+	/* add all the rest of the file to the freelist, possibly leaving a gap 
+	   for the recovery area */
+	if (recovery_size == 0) {
+		/* the simple case - the whole file can be used as a freelist */
+		data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size));
+		if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
+			goto failed;
+		}
+	} else {
+		/* we need to add two freelist entries - one on either
+		   side of the recovery area 
+
+		   Note that we cannot shift the recovery area during
+		   this operation. Only the transaction.c code may
+		   move the recovery area or we risk subtle data
+		   corruption
+		*/
+		data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size));
+		if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
+			goto failed;
+		}
+		/* and the 2nd free list entry after the recovery area - if any */
+		data_len = tdb->map_size - (recovery_head+recovery_size);
+		if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
+			goto failed;
+		}
+	}
+
+	if (tdb_unlockall(tdb) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	tdb_unlockall(tdb);
+	return -1;
+}
+
+struct traverse_state {
+	bool error;
+	struct tdb_context *dest_db;
+};
+
+/*
+  traverse function for repacking
+ */
+static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
+{
+	struct traverse_state *state = (struct traverse_state *)private_data;
+	if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
+		state->error = true;
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  repack a tdb
+ */
+int tdb_repack(struct tdb_context *tdb)
+{
+	struct tdb_context *tmp_db;
+	struct traverse_state state;
+
+	tdb_trace(tdb, "tdb_repack");
+
+	if (tdb_transaction_start(tdb) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n"));
+		return -1;
+	}
+
+	tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0);
+	if (tmp_db == NULL) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n"));
+		tdb_transaction_cancel(tdb);
+		return -1;
+	}
+
+	state.error = false;
+	state.dest_db = tmp_db;
+
+	if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;		
+	}
+
+	if (state.error) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	if (tdb_wipe_all(tdb) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	state.error = false;
+	state.dest_db = tdb;
+
+	if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;		
+	}
+
+	if (state.error) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	tdb_close(tmp_db);
+
+	if (tdb_transaction_commit(tdb) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Even on files, we can get partial writes due to signals. */
+bool tdb_write_all(int fd, const void *buf, size_t count)
+{
+	while (count) {
+		size_t ret;
+		ret = write(fd, buf, count);
+		if (ret < 0)
+			return false;
+		buf = (const char *)buf + ret;
+		count -= ret;
+	}
+	return true;
+}
+
+#ifdef TDB_TRACE
+static void tdb_trace_write(struct tdb_context *tdb, const char *str)
+{
+	if (!tdb_write_alltdb->tracefd, str, strlen(str)) {
+		close(tdb->tracefd);
+		tdb->tracefd = -1;
+	}
+}
+
+static void tdb_trace_start(struct tdb_context *tdb)
+{
+	tdb_off_t seqnum=0;
+	char msg[sizeof(tdb_off_t) * 4 + 1];
+
+	tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+	snprintf(msg, sizeof(msg), "%u ", seqnum);
+	tdb_trace_write(tdb, msg);
+}
+
+static void tdb_trace_end(struct tdb_context *tdb)
+{
+	tdb_trace_write(tdb, "\n");
+}
+
+static void tdb_trace_end_ret(struct tdb_context *tdb, int ret)
+{
+	char msg[sizeof(ret) * 4 + 4];
+	snprintf(msg, sizeof(msg), " = %i\n", ret);
+	tdb_trace_write(tdb, msg);
+}
+
+static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec)
+{
+	char msg[20 + rec.dsize*2], *p;
+	unsigned int i;
+
+	/* We differentiate zero-length records from non-existent ones. */
+	if (rec.dptr == NULL) {
+		tdb_trace_write(tdb, " NULL");
+		return;
+	}
+
+	/* snprintf here is purely cargo-cult programming. */
+	p = msg;
+	p += snprintf(p, sizeof(msg), " %zu:", rec.dsize);
+	for (i = 0; i < rec.dsize; i++)
+		p += snprintf(p, 2, "%02x", rec.dptr[i]);
+
+	tdb_trace_write(tdb, msg);
+}
+
+void tdb_trace(struct tdb_context *tdb, const char *op)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op)
+{
+	char msg[sizeof(tdb_off_t) * 4 + 1];
+
+	snprintf(msg, sizeof(msg), "%u ", seqnum);
+	tdb_trace_write(tdb, msg);
+	tdb_trace_write(tdb, op);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_open(struct tdb_context *tdb, const char *op,
+		    unsigned hash_size, unsigned tdb_flags, unsigned open_flags)
+{
+	char msg[128];
+
+	snprintf(msg, sizeof(msg),
+		 "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags);
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, msg);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_write(tdb, " =");
+	tdb_trace_record(tdb, ret);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
+		    TDB_DATA rec)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_record(tdb, rec);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
+			TDB_DATA rec, int ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_record(tdb, rec);
+	tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
+			   TDB_DATA rec, TDB_DATA ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_record(tdb, rec);
+	tdb_trace_write(tdb, " =");
+	tdb_trace_record(tdb, ret);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
+			     TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
+			     int ret)
+{
+	char msg[1 + sizeof(ret) * 4];
+
+	snprintf(msg, sizeof(msg), " %#x", flag);
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_record(tdb, rec1);
+	tdb_trace_record(tdb, rec2);
+	tdb_trace_write(tdb, msg);
+	tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
+			   TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_record(tdb, rec1);
+	tdb_trace_record(tdb, rec2);
+	tdb_trace_write(tdb, " =");
+	tdb_trace_record(tdb, ret);
+	tdb_trace_end(tdb);
+}
+#endif

Added: branches/ctdb/squeeze-backports/lib/tdb/common/tdb_private.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/tdb_private.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/tdb_private.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,276 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library - private includes
+
+   Copyright (C) Andrew Tridgell              2005
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/shmem.h"
+#include "system/select.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+/* #define TDB_TRACE 1 */
+#ifndef HAVE_GETPAGESIZE
+#define getpagesize() 0x2000
+#endif
+
+typedef uint32_t tdb_len_t;
+typedef uint32_t tdb_off_t;
+
+#ifndef offsetof
+#define offsetof(t,f) ((unsigned int)&((t *)0)->f)
+#endif
+
+#define TDB_MAGIC_FOOD "TDB file\n"
+#define TDB_VERSION (0x26011967 + 6)
+#define TDB_MAGIC (0x26011999U)
+#define TDB_FREE_MAGIC (~TDB_MAGIC)
+#define TDB_DEAD_MAGIC (0xFEE1DEAD)
+#define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
+#define TDB_RECOVERY_INVALID_MAGIC (0x0)
+#define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U)
+#define TDB_ALIGNMENT 4
+#define DEFAULT_HASH_SIZE 131
+#define FREELIST_TOP (sizeof(struct tdb_header))
+#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1))
+#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24))
+#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC)
+#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
+#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off_t))
+#define TDB_HASHTABLE_SIZE(tdb) ((tdb->header.hash_size+1)*sizeof(tdb_off_t))
+#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + sizeof(tdb_off_t))
+#define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start)
+#define TDB_SEQNUM_OFS    offsetof(struct tdb_header, sequence_number)
+#define TDB_PAD_BYTE 0x42
+#define TDB_PAD_U32  0x42424242
+
+/* NB assumes there is a local variable called "tdb" that is the
+ * current context, also takes doubly-parenthesized print-style
+ * argument. */
+#define TDB_LOG(x) tdb->log.log_fn x
+
+#ifdef TDB_TRACE
+void tdb_trace(struct tdb_context *tdb, const char *op);
+void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op);
+void tdb_trace_open(struct tdb_context *tdb, const char *op,
+		    unsigned hash_size, unsigned tdb_flags, unsigned open_flags);
+void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret);
+void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret);
+void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
+		    TDB_DATA rec);
+void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
+			TDB_DATA rec, int ret);
+void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
+			   TDB_DATA rec, TDB_DATA ret);
+void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
+			     TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
+			     int ret);
+void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
+			   TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret);
+#else
+#define tdb_trace(tdb, op)
+#define tdb_trace_seqnum(tdb, seqnum, op)
+#define tdb_trace_open(tdb, op, hash_size, tdb_flags, open_flags)
+#define tdb_trace_ret(tdb, op, ret)
+#define tdb_trace_retrec(tdb, op, ret)
+#define tdb_trace_1rec(tdb, op, rec)
+#define tdb_trace_1rec_ret(tdb, op, rec, ret)
+#define tdb_trace_1rec_retrec(tdb, op, rec, ret)
+#define tdb_trace_2rec_flag_ret(tdb, op, rec1, rec2, flag, ret)
+#define tdb_trace_2rec_retrec(tdb, op, rec1, rec2, ret)
+#endif /* !TDB_TRACE */
+
+/* lock offsets */
+#define OPEN_LOCK        0
+#define ACTIVE_LOCK      4
+#define TRANSACTION_LOCK 8
+
+/* free memory if the pointer is valid and zero the pointer */
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
+#endif
+
+#define BUCKET(hash) ((hash) % tdb->header.hash_size)
+
+#define DOCONV() (tdb->flags & TDB_CONVERT)
+#define CONVERT(x) (DOCONV() ? tdb_convert(&x, sizeof(x)) : &x)
+
+
+/* the body of the database is made of one tdb_record for the free space
+   plus a separate data list for each hash value */
+struct tdb_record {
+	tdb_off_t next; /* offset of the next record in the list */
+	tdb_len_t rec_len; /* total byte length of record */
+	tdb_len_t key_len; /* byte length of key */
+	tdb_len_t data_len; /* byte length of data */
+	uint32_t full_hash; /* the full 32 bit hash of the key */
+	uint32_t magic;   /* try to catch errors */
+	/* the following union is implied:
+		union {
+			char record[rec_len];
+			struct {
+				char key[key_len];
+				char data[data_len];
+			}
+			uint32_t totalsize; (tailer)
+		}
+	*/
+};
+
+
+/* this is stored at the front of every database */
+struct tdb_header {
+	char magic_food[32]; /* for /etc/magic */
+	uint32_t version; /* version of the code */
+	uint32_t hash_size; /* number of hash entries */
+	tdb_off_t rwlocks; /* obsolete - kept to detect old formats */
+	tdb_off_t recovery_start; /* offset of transaction recovery region */
+	tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */
+	uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */
+	uint32_t magic2_hash; /* hash of TDB_MAGIC. */
+	tdb_off_t reserved[27];
+};
+
+struct tdb_lock_type {
+	uint32_t off;
+	uint32_t count;
+	uint32_t ltype;
+};
+
+struct tdb_traverse_lock {
+	struct tdb_traverse_lock *next;
+	uint32_t off;
+	uint32_t hash;
+	int lock_rw;
+};
+
+enum tdb_lock_flags {
+	/* WAIT == F_SETLKW, NOWAIT == F_SETLK */
+	TDB_LOCK_NOWAIT = 0,
+	TDB_LOCK_WAIT = 1,
+	/* If set, don't log an error on failure. */
+	TDB_LOCK_PROBE = 2,
+	/* If set, don't actually lock at all. */
+	TDB_LOCK_MARK_ONLY = 4,
+};
+
+struct tdb_methods {
+	int (*tdb_read)(struct tdb_context *, tdb_off_t , void *, tdb_len_t , int );
+	int (*tdb_write)(struct tdb_context *, tdb_off_t, const void *, tdb_len_t);
+	void (*next_hash_chain)(struct tdb_context *, uint32_t *);
+	int (*tdb_oob)(struct tdb_context *, tdb_off_t , int );
+	int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t );
+};
+
+struct tdb_context {
+	char *name; /* the name of the database */
+	void *map_ptr; /* where it is currently mapped */
+	int fd; /* open file descriptor for the database */
+	tdb_len_t map_size; /* how much space has been mapped */
+	int read_only; /* opened read-only */
+	int traverse_read; /* read-only traversal */
+	int traverse_write; /* read-write traversal */
+	struct tdb_lock_type allrecord_lock; /* .offset == upgradable */
+	int num_lockrecs;
+	struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
+	enum TDB_ERROR ecode; /* error code for last tdb error */
+	struct tdb_header header; /* a cached copy of the header */
+	uint32_t flags; /* the flags passed to tdb_open */
+	struct tdb_traverse_lock travlocks; /* current traversal locks */
+	struct tdb_context *next; /* all tdbs to avoid multiple opens */
+	dev_t device;	/* uniquely identifies this tdb */
+	ino_t inode;	/* uniquely identifies this tdb */
+	struct tdb_logging_context log;
+	unsigned int (*hash_fn)(TDB_DATA *key);
+	int open_flags; /* flags used in the open - needed by reopen */
+	const struct tdb_methods *methods;
+	struct tdb_transaction *transaction;
+	int page_size;
+	int max_dead_records;
+#ifdef TDB_TRACE
+	int tracefd;
+#endif
+	volatile sig_atomic_t *interrupt_sig_ptr;
+};
+
+
+/*
+  internal prototypes
+*/
+int tdb_munmap(struct tdb_context *tdb);
+void tdb_mmap(struct tdb_context *tdb);
+int tdb_lock(struct tdb_context *tdb, int list, int ltype);
+int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
+int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
+		  enum tdb_lock_flags flags);
+int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
+		    bool mark_lock);
+int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
+int tdb_brlock(struct tdb_context *tdb,
+	       int rw_type, tdb_off_t offset, size_t len,
+	       enum tdb_lock_flags flags);
+int tdb_brunlock(struct tdb_context *tdb,
+		 int rw_type, tdb_off_t offset, size_t len);
+bool tdb_have_extra_locks(struct tdb_context *tdb);
+void tdb_release_transaction_locks(struct tdb_context *tdb);
+int tdb_transaction_lock(struct tdb_context *tdb, int ltype,
+			 enum tdb_lock_flags lockflags);
+int tdb_transaction_unlock(struct tdb_context *tdb, int ltype);
+int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
+		       enum tdb_lock_flags flags, bool upgradable);
+int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock);
+int tdb_allrecord_upgrade(struct tdb_context *tdb);
+int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+void *tdb_convert(void *buf, uint32_t size);
+int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
+tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec);
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off);
+bool tdb_needs_recovery(struct tdb_context *tdb);
+int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
+int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
+int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec);
+unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len);
+int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
+		   tdb_off_t offset, tdb_len_t len,
+		   int (*parser)(TDB_DATA key, TDB_DATA data,
+				 void *private_data),
+		   void *private_data);
+tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
+			   struct tdb_record *rec);
+void tdb_io_init(struct tdb_context *tdb);
+int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
+int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off,
+		      struct tdb_record *rec);
+bool tdb_write_all(int fd, const void *buf, size_t count);
+int tdb_transaction_recover(struct tdb_context *tdb);
+void tdb_header_hash(struct tdb_context *tdb,
+		     uint32_t *magic1_hash, uint32_t *magic2_hash);
+unsigned int tdb_old_hash(TDB_DATA *key);

Added: branches/ctdb/squeeze-backports/lib/tdb/common/transaction.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/transaction.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/transaction.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1232 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              2005
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/*
+  transaction design:
+
+  - only allow a single transaction at a time per database. This makes
+    using the transaction API simpler, as otherwise the caller would
+    have to cope with temporary failures in transactions that conflict
+    with other current transactions
+
+  - keep the transaction recovery information in the same file as the
+    database, using a special 'transaction recovery' record pointed at
+    by the header. This removes the need for extra journal files as
+    used by some other databases
+
+  - dynamically allocated the transaction recover record, re-using it
+    for subsequent transactions. If a larger record is needed then
+    tdb_free() the old record to place it on the normal tdb freelist
+    before allocating the new record
+
+  - during transactions, keep a linked list of writes all that have
+    been performed by intercepting all tdb_write() calls. The hooked
+    transaction versions of tdb_read() and tdb_write() check this
+    linked list and try to use the elements of the list in preference
+    to the real database.
+
+  - don't allow any locks to be held when a transaction starts,
+    otherwise we can end up with deadlock (plus lack of lock nesting
+    in posix locks would mean the lock is lost)
+
+  - if the caller gains a lock during the transaction but doesn't
+    release it then fail the commit
+
+  - allow for nested calls to tdb_transaction_start(), re-using the
+    existing transaction record. If the inner transaction is cancelled
+    then a subsequent commit will fail
+
+  - keep a mirrored copy of the tdb hash chain heads to allow for the
+    fast hash heads scan on traverse, updating the mirrored copy in
+    the transaction version of tdb_write
+
+  - allow callers to mix transaction and non-transaction use of tdb,
+    although once a transaction is started then an exclusive lock is
+    gained until the transaction is committed or cancelled
+
+  - the commit stategy involves first saving away all modified data
+    into a linearised buffer in the transaction recovery area, then
+    marking the transaction recovery area with a magic value to
+    indicate a valid recovery record. In total 4 fsync/msync calls are
+    needed per commit to prevent race conditions. It might be possible
+    to reduce this to 3 or even 2 with some more work.
+
+  - check for a valid recovery record on open of the tdb, while the
+    open lock is held. Automatically recover from the transaction
+    recovery area if needed, then continue with the open as
+    usual. This allows for smooth crash recovery with no administrator
+    intervention.
+
+  - if TDB_NOSYNC is passed to flags in tdb_open then transactions are
+    still available, but no transaction recovery area is used and no
+    fsync/msync calls are made.
+
+  - if TDB_ALLOW_NESTING is passed to flags in tdb open, or added using
+    tdb_add_flags() transaction nesting is enabled.
+    It resets the TDB_DISALLOW_NESTING flag, as both cannot be used together.
+    The default is that transaction nesting is allowed.
+    Note: this default may change in future versions of tdb.
+
+    Beware. when transactions are nested a transaction successfully
+    completed with tdb_transaction_commit() can be silently unrolled later.
+
+  - if TDB_DISALLOW_NESTING is passed to flags in tdb open, or added using
+    tdb_add_flags() transaction nesting is disabled.
+    It resets the TDB_ALLOW_NESTING flag, as both cannot be used together.
+    An attempt create a nested transaction will fail with TDB_ERR_NESTING.
+    The default is that transaction nesting is allowed.
+    Note: this default may change in future versions of tdb.
+*/
+
+
+/*
+  hold the context of any current transaction
+*/
+struct tdb_transaction {
+	/* we keep a mirrored copy of the tdb hash heads here so
+	   tdb_next_hash_chain() can operate efficiently */
+	uint32_t *hash_heads;
+
+	/* the original io methods - used to do IOs to the real db */
+	const struct tdb_methods *io_methods;
+
+	/* the list of transaction blocks. When a block is first
+	   written to, it gets created in this list */
+	uint8_t **blocks;
+	uint32_t num_blocks;
+	uint32_t block_size;      /* bytes in each block */
+	uint32_t last_block_size; /* number of valid bytes in the last block */
+
+	/* non-zero when an internal transaction error has
+	   occurred. All write operations will then fail until the
+	   transaction is ended */
+	int transaction_error;
+
+	/* when inside a transaction we need to keep track of any
+	   nested tdb_transaction_start() calls, as these are allowed,
+	   but don't create a new transaction */
+	int nesting;
+
+	/* set when a prepare has already occurred */
+	bool prepared;
+	tdb_off_t magic_offset;
+
+	/* old file size before transaction */
+	tdb_len_t old_map_size;
+
+	/* we should re-pack on commit */
+	bool need_repack;
+};
+
+
+/*
+  read while in a transaction. We need to check first if the data is in our list
+  of transaction elements, then if not do a real read
+*/
+static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf, 
+			    tdb_len_t len, int cv)
+{
+	uint32_t blk;
+
+	/* break it down into block sized ops */
+	while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+		tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+		if (transaction_read(tdb, off, buf, len2, cv) != 0) {
+			return -1;
+		}
+		len -= len2;
+		off += len2;
+		buf = (void *)(len2 + (char *)buf);
+	}
+
+	if (len == 0) {
+		return 0;
+	}
+
+	blk = off / tdb->transaction->block_size;
+
+	/* see if we have it in the block list */
+	if (tdb->transaction->num_blocks <= blk ||
+	    tdb->transaction->blocks[blk] == NULL) {
+		/* nope, do a real read */
+		if (tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv) != 0) {
+			goto fail;
+		}
+		return 0;
+	}
+
+	/* it is in the block list. Now check for the last block */
+	if (blk == tdb->transaction->num_blocks-1) {
+		if (len > tdb->transaction->last_block_size) {
+			goto fail;
+		}
+	}
+
+	/* now copy it out of this block */
+	memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len);
+	if (cv) {
+		tdb_convert(buf, len);
+	}
+	return 0;
+
+fail:
+	TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%d len=%d\n", off, len));
+	tdb->ecode = TDB_ERR_IO;
+	tdb->transaction->transaction_error = 1;
+	return -1;
+}
+
+
+/*
+  write while in a transaction
+*/
+static int transaction_write(struct tdb_context *tdb, tdb_off_t off, 
+			     const void *buf, tdb_len_t len)
+{
+	uint32_t blk;
+
+	/* Only a commit is allowed on a prepared transaction */
+	if (tdb->transaction->prepared) {
+		tdb->ecode = TDB_ERR_EINVAL;
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: transaction already prepared, write not allowed\n"));
+		tdb->transaction->transaction_error = 1;
+		return -1;
+	}
+
+	/* if the write is to a hash head, then update the transaction
+	   hash heads */
+	if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP &&
+	    off < FREELIST_TOP+TDB_HASHTABLE_SIZE(tdb)) {
+		uint32_t chain = (off-FREELIST_TOP) / sizeof(tdb_off_t);
+		memcpy(&tdb->transaction->hash_heads[chain], buf, len);
+	}
+
+	/* break it up into block sized chunks */
+	while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+		tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+		if (transaction_write(tdb, off, buf, len2) != 0) {
+			return -1;
+		}
+		len -= len2;
+		off += len2;
+		if (buf != NULL) {
+			buf = (const void *)(len2 + (const char *)buf);
+		}
+	}
+
+	if (len == 0) {
+		return 0;
+	}
+
+	blk = off / tdb->transaction->block_size;
+	off = off % tdb->transaction->block_size;
+
+	if (tdb->transaction->num_blocks <= blk) {
+		uint8_t **new_blocks;
+		/* expand the blocks array */
+		if (tdb->transaction->blocks == NULL) {
+			new_blocks = (uint8_t **)malloc(
+				(blk+1)*sizeof(uint8_t *));
+		} else {
+			new_blocks = (uint8_t **)realloc(
+				tdb->transaction->blocks,
+				(blk+1)*sizeof(uint8_t *));
+		}
+		if (new_blocks == NULL) {
+			tdb->ecode = TDB_ERR_OOM;
+			goto fail;
+		}
+		memset(&new_blocks[tdb->transaction->num_blocks], 0, 
+		       (1+(blk - tdb->transaction->num_blocks))*sizeof(uint8_t *));
+		tdb->transaction->blocks = new_blocks;
+		tdb->transaction->num_blocks = blk+1;
+		tdb->transaction->last_block_size = 0;
+	}
+
+	/* allocate and fill a block? */
+	if (tdb->transaction->blocks[blk] == NULL) {
+		tdb->transaction->blocks[blk] = (uint8_t *)calloc(tdb->transaction->block_size, 1);
+		if (tdb->transaction->blocks[blk] == NULL) {
+			tdb->ecode = TDB_ERR_OOM;
+			tdb->transaction->transaction_error = 1;
+			return -1;			
+		}
+		if (tdb->transaction->old_map_size > blk * tdb->transaction->block_size) {
+			tdb_len_t len2 = tdb->transaction->block_size;
+			if (len2 + (blk * tdb->transaction->block_size) > tdb->transaction->old_map_size) {
+				len2 = tdb->transaction->old_map_size - (blk * tdb->transaction->block_size);
+			}
+			if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size, 
+								   tdb->transaction->blocks[blk], 
+								   len2, 0) != 0) {
+				SAFE_FREE(tdb->transaction->blocks[blk]);				
+				tdb->ecode = TDB_ERR_IO;
+				goto fail;
+			}
+			if (blk == tdb->transaction->num_blocks-1) {
+				tdb->transaction->last_block_size = len2;
+			}			
+		}
+	}
+
+	/* overwrite part of an existing block */
+	if (buf == NULL) {
+		memset(tdb->transaction->blocks[blk] + off, 0, len);
+	} else {
+		memcpy(tdb->transaction->blocks[blk] + off, buf, len);
+	}
+	if (blk == tdb->transaction->num_blocks-1) {
+		if (len + off > tdb->transaction->last_block_size) {
+			tdb->transaction->last_block_size = len + off;
+		}
+	}
+
+	return 0;
+
+fail:
+	TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n", 
+		 (blk*tdb->transaction->block_size) + off, len));
+	tdb->transaction->transaction_error = 1;
+	return -1;
+}
+
+
+/*
+  write while in a transaction - this varient never expands the transaction blocks, it only
+  updates existing blocks. This means it cannot change the recovery size
+*/
+static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off, 
+				      const void *buf, tdb_len_t len)
+{
+	uint32_t blk;
+
+	/* break it up into block sized chunks */
+	while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+		tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+		if (transaction_write_existing(tdb, off, buf, len2) != 0) {
+			return -1;
+		}
+		len -= len2;
+		off += len2;
+		if (buf != NULL) {
+			buf = (const void *)(len2 + (const char *)buf);
+		}
+	}
+
+	if (len == 0) {
+		return 0;
+	}
+
+	blk = off / tdb->transaction->block_size;
+	off = off % tdb->transaction->block_size;
+
+	if (tdb->transaction->num_blocks <= blk ||
+	    tdb->transaction->blocks[blk] == NULL) {
+		return 0;
+	}
+
+	if (blk == tdb->transaction->num_blocks-1 &&
+	    off + len > tdb->transaction->last_block_size) {
+		if (off >= tdb->transaction->last_block_size) {
+			return 0;
+		}
+		len = tdb->transaction->last_block_size - off;
+	}
+
+	/* overwrite part of an existing block */
+	memcpy(tdb->transaction->blocks[blk] + off, buf, len);
+
+	return 0;
+}
+
+
+/*
+  accelerated hash chain head search, using the cached hash heads
+*/
+static void transaction_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
+{
+	uint32_t h = *chain;
+	for (;h < tdb->header.hash_size;h++) {
+		/* the +1 takes account of the freelist */
+		if (0 != tdb->transaction->hash_heads[h+1]) {
+			break;
+		}
+	}
+	(*chain) = h;
+}
+
+/*
+  out of bounds check during a transaction
+*/
+static int transaction_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
+{
+	if (len <= tdb->map_size) {
+		return 0;
+	}
+	tdb->ecode = TDB_ERR_IO;
+	return -1;
+}
+
+/*
+  transaction version of tdb_expand().
+*/
+static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size, 
+				   tdb_off_t addition)
+{
+	/* add a write to the transaction elements, so subsequent
+	   reads see the zero data */
+	if (transaction_write(tdb, size, NULL, addition) != 0) {
+		return -1;
+	}
+
+	tdb->transaction->need_repack = true;
+
+	return 0;
+}
+
+static const struct tdb_methods transaction_methods = {
+	transaction_read,
+	transaction_write,
+	transaction_next_hash_chain,
+	transaction_oob,
+	transaction_expand_file,
+};
+
+
+/*
+  start a tdb transaction. No token is returned, as only a single
+  transaction is allowed to be pending per tdb_context
+*/
+static int _tdb_transaction_start(struct tdb_context *tdb,
+				  enum tdb_lock_flags lockflags)
+{
+	/* some sanity checks */
+	if (tdb->read_only || (tdb->flags & TDB_INTERNAL) || tdb->traverse_read) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n"));
+		tdb->ecode = TDB_ERR_EINVAL;
+		return -1;
+	}
+
+	/* cope with nested tdb_transaction_start() calls */
+	if (tdb->transaction != NULL) {
+		if (!(tdb->flags & TDB_ALLOW_NESTING)) {
+			tdb->ecode = TDB_ERR_NESTING;
+			return -1;
+		}
+		tdb->transaction->nesting++;
+		TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", 
+			 tdb->transaction->nesting));
+		return 0;
+	}
+
+	if (tdb_have_extra_locks(tdb)) {
+		/* the caller must not have any locks when starting a
+		   transaction as otherwise we'll be screwed by lack
+		   of nested locks in posix */
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction with locks held\n"));
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	if (tdb->travlocks.next != NULL) {
+		/* you cannot use transactions inside a traverse (although you can use
+		   traverse inside a transaction) as otherwise you can end up with
+		   deadlock */
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction within a traverse\n"));
+		tdb->ecode = TDB_ERR_LOCK;
+		return -1;
+	}
+
+	tdb->transaction = (struct tdb_transaction *)
+		calloc(sizeof(struct tdb_transaction), 1);
+	if (tdb->transaction == NULL) {
+		tdb->ecode = TDB_ERR_OOM;
+		return -1;
+	}
+
+	/* a page at a time seems like a reasonable compromise between compactness and efficiency */
+	tdb->transaction->block_size = tdb->page_size;
+
+	/* get the transaction write lock. This is a blocking lock. As
+	   discussed with Volker, there are a number of ways we could
+	   make this async, which we will probably do in the future */
+	if (tdb_transaction_lock(tdb, F_WRLCK, lockflags) == -1) {
+		SAFE_FREE(tdb->transaction->blocks);
+		SAFE_FREE(tdb->transaction);
+		if ((lockflags & TDB_LOCK_WAIT) == 0) {
+			tdb->ecode = TDB_ERR_NOLOCK;
+		}
+		return -1;
+	}
+
+	/* get a read lock from the freelist to the end of file. This
+	   is upgraded to a write lock during the commit */
+	if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, true) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n"));
+		goto fail_allrecord_lock;
+	}
+
+	/* setup a copy of the hash table heads so the hash scan in
+	   traverse can be fast */
+	tdb->transaction->hash_heads = (uint32_t *)
+		calloc(tdb->header.hash_size+1, sizeof(uint32_t));
+	if (tdb->transaction->hash_heads == NULL) {
+		tdb->ecode = TDB_ERR_OOM;
+		goto fail;
+	}
+	if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
+				   TDB_HASHTABLE_SIZE(tdb), 0) != 0) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to read hash heads\n"));
+		tdb->ecode = TDB_ERR_IO;
+		goto fail;
+	}
+
+	/* make sure we know about any file expansions already done by
+	   anyone else */
+	tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+	tdb->transaction->old_map_size = tdb->map_size;
+
+	/* finally hook the io methods, replacing them with
+	   transaction specific methods */
+	tdb->transaction->io_methods = tdb->methods;
+	tdb->methods = &transaction_methods;
+
+	/* Trace at the end, so we get sequence number correct. */
+	tdb_trace(tdb, "tdb_transaction_start");
+	return 0;
+
+fail:
+	tdb_allrecord_unlock(tdb, F_RDLCK, false);
+fail_allrecord_lock:
+	tdb_transaction_unlock(tdb, F_WRLCK);
+	SAFE_FREE(tdb->transaction->blocks);
+	SAFE_FREE(tdb->transaction->hash_heads);
+	SAFE_FREE(tdb->transaction);
+	return -1;
+}
+
+int tdb_transaction_start(struct tdb_context *tdb)
+{
+	return _tdb_transaction_start(tdb, TDB_LOCK_WAIT);
+}
+
+int tdb_transaction_start_nonblock(struct tdb_context *tdb)
+{
+	return _tdb_transaction_start(tdb, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
+}
+
+/*
+  sync to disk
+*/
+static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
+{	
+	if (tdb->flags & TDB_NOSYNC) {
+		return 0;
+	}
+
+	if (fdatasync(tdb->fd) != 0) {
+		tdb->ecode = TDB_ERR_IO;
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
+		return -1;
+	}
+#ifdef HAVE_MMAP
+	if (tdb->map_ptr) {
+		tdb_off_t moffset = offset & ~(tdb->page_size-1);
+		if (msync(moffset + (char *)tdb->map_ptr, 
+			  length + (offset - moffset), MS_SYNC) != 0) {
+			tdb->ecode = TDB_ERR_IO;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
+				 strerror(errno)));
+			return -1;
+		}
+	}
+#endif
+	return 0;
+}
+
+
+static int _tdb_transaction_cancel(struct tdb_context *tdb)
+{	
+	int i, ret = 0;
+
+	if (tdb->transaction == NULL) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
+		return -1;
+	}
+
+	if (tdb->transaction->nesting != 0) {
+		tdb->transaction->transaction_error = 1;
+		tdb->transaction->nesting--;
+		return 0;
+	}		
+
+	tdb->map_size = tdb->transaction->old_map_size;
+
+	/* free all the transaction blocks */
+	for (i=0;i<tdb->transaction->num_blocks;i++) {
+		if (tdb->transaction->blocks[i] != NULL) {
+			free(tdb->transaction->blocks[i]);
+		}
+	}
+	SAFE_FREE(tdb->transaction->blocks);
+
+	if (tdb->transaction->magic_offset) {
+		const struct tdb_methods *methods = tdb->transaction->io_methods;
+		const uint32_t invalid = TDB_RECOVERY_INVALID_MAGIC;
+
+		/* remove the recovery marker */
+		if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &invalid, 4) == -1 ||
+		transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n"));
+			ret = -1;
+		}
+	}
+
+	/* This also removes the OPEN_LOCK, if we have it. */
+	tdb_release_transaction_locks(tdb);
+
+	/* restore the normal io methods */
+	tdb->methods = tdb->transaction->io_methods;
+
+	SAFE_FREE(tdb->transaction->hash_heads);
+	SAFE_FREE(tdb->transaction);
+
+	return ret;
+}
+
+/*
+  cancel the current transaction
+*/
+int tdb_transaction_cancel(struct tdb_context *tdb)
+{
+	tdb_trace(tdb, "tdb_transaction_cancel");
+	return _tdb_transaction_cancel(tdb);
+}
+
+/*
+  work out how much space the linearised recovery data will consume
+*/
+static tdb_len_t tdb_recovery_size(struct tdb_context *tdb)
+{
+	tdb_len_t recovery_size = 0;
+	int i;
+
+	recovery_size = sizeof(uint32_t);
+	for (i=0;i<tdb->transaction->num_blocks;i++) {
+		if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) {
+			break;
+		}
+		if (tdb->transaction->blocks[i] == NULL) {
+			continue;
+		}
+		recovery_size += 2*sizeof(tdb_off_t);
+		if (i == tdb->transaction->num_blocks-1) {
+			recovery_size += tdb->transaction->last_block_size;
+		} else {
+			recovery_size += tdb->transaction->block_size;
+		}
+	}	
+
+	return recovery_size;
+}
+
+/*
+  allocate the recovery area, or use an existing recovery area if it is
+  large enough
+*/
+static int tdb_recovery_allocate(struct tdb_context *tdb, 
+				 tdb_len_t *recovery_size,
+				 tdb_off_t *recovery_offset,
+				 tdb_len_t *recovery_max_size)
+{
+	struct tdb_record rec;
+	const struct tdb_methods *methods = tdb->transaction->io_methods;
+	tdb_off_t recovery_head;
+
+	if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n"));
+		return -1;
+	}
+
+	rec.rec_len = 0;
+
+	if (recovery_head != 0) {
+		if (methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n"));
+			return -1;
+		}
+		/* ignore invalid recovery regions: can happen in crash */
+		if (rec.magic != TDB_RECOVERY_MAGIC &&
+		    rec.magic != TDB_RECOVERY_INVALID_MAGIC) {
+			recovery_head = 0;
+		}
+	}
+
+	*recovery_size = tdb_recovery_size(tdb);
+
+	if (recovery_head != 0 && *recovery_size <= rec.rec_len) {
+		/* it fits in the existing area */
+		*recovery_max_size = rec.rec_len;
+		*recovery_offset = recovery_head;
+		return 0;
+	}
+
+	/* we need to free up the old recovery area, then allocate a
+	   new one at the end of the file. Note that we cannot use
+	   tdb_allocate() to allocate the new one as that might return
+	   us an area that is being currently used (as of the start of
+	   the transaction) */
+	if (recovery_head != 0) {
+		if (tdb_free(tdb, recovery_head, &rec) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to free previous recovery area\n"));
+			return -1;
+		}
+	}
+
+	/* the tdb_free() call might have increased the recovery size */
+	*recovery_size = tdb_recovery_size(tdb);
+
+	/* round up to a multiple of page size */
+	*recovery_max_size = TDB_ALIGN(sizeof(rec) + *recovery_size, tdb->page_size) - sizeof(rec);
+	*recovery_offset = tdb->map_size;
+	recovery_head = *recovery_offset;
+
+	if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, 
+				     (tdb->map_size - tdb->transaction->old_map_size) +
+				     sizeof(rec) + *recovery_max_size) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n"));
+		return -1;
+	}
+
+	/* remap the file (if using mmap) */
+	methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+
+	/* we have to reset the old map size so that we don't try to expand the file
+	   again in the transaction commit, which would destroy the recovery area */
+	tdb->transaction->old_map_size = tdb->map_size;
+
+	/* write the recovery header offset and sync - we can sync without a race here
+	   as the magic ptr in the recovery record has not been set */
+	CONVERT(recovery_head);
+	if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD, 
+			       &recovery_head, sizeof(tdb_off_t)) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
+		return -1;
+	}
+	if (transaction_write_existing(tdb, TDB_RECOVERY_HEAD, &recovery_head, sizeof(tdb_off_t)) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+  setup the recovery data that will be used on a crash during commit
+*/
+static int transaction_setup_recovery(struct tdb_context *tdb, 
+				      tdb_off_t *magic_offset)
+{
+	tdb_len_t recovery_size;
+	unsigned char *data, *p;
+	const struct tdb_methods *methods = tdb->transaction->io_methods;
+	struct tdb_record *rec;
+	tdb_off_t recovery_offset, recovery_max_size;
+	tdb_off_t old_map_size = tdb->transaction->old_map_size;
+	uint32_t magic, tailer;
+	int i;
+
+	/*
+	  check that the recovery area has enough space
+	*/
+	if (tdb_recovery_allocate(tdb, &recovery_size, 
+				  &recovery_offset, &recovery_max_size) == -1) {
+		return -1;
+	}
+
+	data = (unsigned char *)malloc(recovery_size + sizeof(*rec));
+	if (data == NULL) {
+		tdb->ecode = TDB_ERR_OOM;
+		return -1;
+	}
+
+	rec = (struct tdb_record *)data;
+	memset(rec, 0, sizeof(*rec));
+
+	rec->magic    = TDB_RECOVERY_INVALID_MAGIC;
+	rec->data_len = recovery_size;
+	rec->rec_len  = recovery_max_size;
+	rec->key_len  = old_map_size;
+	CONVERT(rec);
+
+	/* build the recovery data into a single blob to allow us to do a single
+	   large write, which should be more efficient */
+	p = data + sizeof(*rec);
+	for (i=0;i<tdb->transaction->num_blocks;i++) {
+		tdb_off_t offset;
+		tdb_len_t length;
+
+		if (tdb->transaction->blocks[i] == NULL) {
+			continue;
+		}
+
+		offset = i * tdb->transaction->block_size;
+		length = tdb->transaction->block_size;
+		if (i == tdb->transaction->num_blocks-1) {
+			length = tdb->transaction->last_block_size;
+		}
+
+		if (offset >= old_map_size) {
+			continue;
+		}
+		if (offset + length > tdb->transaction->old_map_size) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: transaction data over new region boundary\n"));
+			free(data);
+			tdb->ecode = TDB_ERR_CORRUPT;
+			return -1;
+		}
+		memcpy(p, &offset, 4);
+		memcpy(p+4, &length, 4);
+		if (DOCONV()) {
+			tdb_convert(p, 8);
+		}
+		/* the recovery area contains the old data, not the
+		   new data, so we have to call the original tdb_read
+		   method to get it */
+		if (methods->tdb_read(tdb, offset, p + 8, length, 0) != 0) {
+			free(data);
+			tdb->ecode = TDB_ERR_IO;
+			return -1;
+		}
+		p += 8 + length;
+	}
+
+	/* and the tailer */
+	tailer = sizeof(*rec) + recovery_max_size;
+	memcpy(p, &tailer, 4);
+	CONVERT(p);
+
+	/* write the recovery data to the recovery area */
+	if (methods->tdb_write(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery data\n"));
+		free(data);
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+	if (transaction_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery data\n"));
+		free(data);
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+	/* as we don't have ordered writes, we have to sync the recovery
+	   data before we update the magic to indicate that the recovery
+	   data is present */
+	if (transaction_sync(tdb, recovery_offset, sizeof(*rec) + recovery_size) == -1) {
+		free(data);
+		return -1;
+	}
+
+	free(data);
+
+	magic = TDB_RECOVERY_MAGIC;
+	CONVERT(magic);
+
+	*magic_offset = recovery_offset + offsetof(struct tdb_record, magic);
+
+	if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery magic\n"));
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+	if (transaction_write_existing(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery magic\n"));
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+	/* ensure the recovery magic marker is on disk */
+	if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int _tdb_transaction_prepare_commit(struct tdb_context *tdb)
+{	
+	const struct tdb_methods *methods;
+
+	if (tdb->transaction == NULL) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: no transaction\n"));
+		return -1;
+	}
+
+	if (tdb->transaction->prepared) {
+		tdb->ecode = TDB_ERR_EINVAL;
+		_tdb_transaction_cancel(tdb);
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n"));
+		return -1;
+	}
+
+	if (tdb->transaction->transaction_error) {
+		tdb->ecode = TDB_ERR_IO;
+		_tdb_transaction_cancel(tdb);
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n"));
+		return -1;
+	}
+
+
+	if (tdb->transaction->nesting != 0) {
+		return 0;
+	}		
+
+	/* check for a null transaction */
+	if (tdb->transaction->blocks == NULL) {
+		return 0;
+	}
+
+	methods = tdb->transaction->io_methods;
+
+	/* if there are any locks pending then the caller has not
+	   nested their locks properly, so fail the transaction */
+	if (tdb_have_extra_locks(tdb)) {
+		tdb->ecode = TDB_ERR_LOCK;
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n"));
+		_tdb_transaction_cancel(tdb);
+		return -1;
+	}
+
+	/* upgrade the main transaction lock region to a write lock */
+	if (tdb_allrecord_upgrade(tdb) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n"));
+		_tdb_transaction_cancel(tdb);
+		return -1;
+	}
+
+	/* get the open lock - this prevents new users attaching to the database
+	   during the commit */
+	if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get open lock\n"));
+		_tdb_transaction_cancel(tdb);
+		return -1;
+	}
+
+	if (!(tdb->flags & TDB_NOSYNC)) {
+		/* write the recovery data to the end of the file */
+		if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
+			_tdb_transaction_cancel(tdb);
+			return -1;
+		}
+	}
+
+	tdb->transaction->prepared = true;
+
+	/* expand the file to the new size if needed */
+	if (tdb->map_size != tdb->transaction->old_map_size) {
+		if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, 
+					     tdb->map_size - 
+					     tdb->transaction->old_map_size) == -1) {
+			tdb->ecode = TDB_ERR_IO;
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n"));
+			_tdb_transaction_cancel(tdb);
+			return -1;
+		}
+		tdb->map_size = tdb->transaction->old_map_size;
+		methods->tdb_oob(tdb, tdb->map_size + 1, 1);
+	}
+
+	/* Keep the open lock until the actual commit */
+
+	return 0;
+}
+
+/*
+   prepare to commit the current transaction
+*/
+int tdb_transaction_prepare_commit(struct tdb_context *tdb)
+{	
+	tdb_trace(tdb, "tdb_transaction_prepare_commit");
+	return _tdb_transaction_prepare_commit(tdb);
+}
+
+/*
+  commit the current transaction
+*/
+int tdb_transaction_commit(struct tdb_context *tdb)
+{	
+	const struct tdb_methods *methods;
+	int i;
+	bool need_repack;
+
+	if (tdb->transaction == NULL) {
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
+		return -1;
+	}
+
+	tdb_trace(tdb, "tdb_transaction_commit");
+
+	if (tdb->transaction->transaction_error) {
+		tdb->ecode = TDB_ERR_IO;
+		_tdb_transaction_cancel(tdb);
+		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
+		return -1;
+	}
+
+
+	if (tdb->transaction->nesting != 0) {
+		tdb->transaction->nesting--;
+		return 0;
+	}
+
+	/* check for a null transaction */
+	if (tdb->transaction->blocks == NULL) {
+		_tdb_transaction_cancel(tdb);
+		return 0;
+	}
+
+	if (!tdb->transaction->prepared) {
+		int ret = _tdb_transaction_prepare_commit(tdb);
+		if (ret)
+			return ret;
+	}
+
+	methods = tdb->transaction->io_methods;
+
+	/* perform all the writes */
+	for (i=0;i<tdb->transaction->num_blocks;i++) {
+		tdb_off_t offset;
+		tdb_len_t length;
+
+		if (tdb->transaction->blocks[i] == NULL) {
+			continue;
+		}
+
+		offset = i * tdb->transaction->block_size;
+		length = tdb->transaction->block_size;
+		if (i == tdb->transaction->num_blocks-1) {
+			length = tdb->transaction->last_block_size;
+		}
+
+		if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n"));
+
+			/* we've overwritten part of the data and
+			   possibly expanded the file, so we need to
+			   run the crash recovery code */
+			tdb->methods = methods;
+			tdb_transaction_recover(tdb); 
+
+			_tdb_transaction_cancel(tdb);
+
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n"));
+			return -1;
+		}
+		SAFE_FREE(tdb->transaction->blocks[i]);
+	} 
+
+	SAFE_FREE(tdb->transaction->blocks);
+	tdb->transaction->num_blocks = 0;
+
+	/* ensure the new data is on disk */
+	if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
+		return -1;
+	}
+
+	/*
+	  TODO: maybe write to some dummy hdr field, or write to magic
+	  offset without mmap, before the last sync, instead of the
+	  utime() call
+	*/
+
+	/* on some systems (like Linux 2.6.x) changes via mmap/msync
+	   don't change the mtime of the file, this means the file may
+	   not be backed up (as tdb rounding to block sizes means that
+	   file size changes are quite rare too). The following forces
+	   mtime changes when a transaction completes */
+#ifdef HAVE_UTIME
+	utime(tdb->name, NULL);
+#endif
+
+	need_repack = tdb->transaction->need_repack;
+
+	/* use a transaction cancel to free memory and remove the
+	   transaction locks */
+	_tdb_transaction_cancel(tdb);
+
+	if (need_repack) {
+		return tdb_repack(tdb);
+	}
+
+	return 0;
+}
+
+
+/*
+  recover from an aborted transaction. Must be called with exclusive
+  database write access already established (including the open
+  lock to prevent new processes attaching)
+*/
+int tdb_transaction_recover(struct tdb_context *tdb)
+{
+	tdb_off_t recovery_head, recovery_eof;
+	unsigned char *data, *p;
+	uint32_t zero = 0;
+	struct tdb_record rec;
+
+	/* find the recovery area */
+	if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery head\n"));
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+	if (recovery_head == 0) {
+		/* we have never allocated a recovery record */
+		return 0;
+	}
+
+	/* read the recovery record */
+	if (tdb->methods->tdb_read(tdb, recovery_head, &rec, 
+				   sizeof(rec), DOCONV()) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n"));		
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+	if (rec.magic != TDB_RECOVERY_MAGIC) {
+		/* there is no valid recovery data */
+		return 0;
+	}
+
+	if (tdb->read_only) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: attempt to recover read only database\n"));
+		tdb->ecode = TDB_ERR_CORRUPT;
+		return -1;
+	}
+
+	recovery_eof = rec.key_len;
+
+	data = (unsigned char *)malloc(rec.data_len);
+	if (data == NULL) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n"));		
+		tdb->ecode = TDB_ERR_OOM;
+		return -1;
+	}
+
+	/* read the full recovery data */
+	if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
+				   rec.data_len, 0) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n"));		
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+	/* recover the file data */
+	p = data;
+	while (p+8 < data + rec.data_len) {
+		uint32_t ofs, len;
+		if (DOCONV()) {
+			tdb_convert(p, 8);
+		}
+		memcpy(&ofs, p, 4);
+		memcpy(&len, p+4, 4);
+
+		if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) {
+			free(data);
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %d bytes at offset %d\n", len, ofs));
+			tdb->ecode = TDB_ERR_IO;
+			return -1;
+		}
+		p += 8 + len;
+	}
+
+	free(data);
+
+	if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync recovery\n"));
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+	/* if the recovery area is after the recovered eof then remove it */
+	if (recovery_eof <= recovery_head) {
+		if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n"));
+			tdb->ecode = TDB_ERR_IO;
+			return -1;			
+		}
+	}
+
+	/* remove the recovery magic */
+	if (tdb_ofs_write(tdb, recovery_head + offsetof(struct tdb_record, magic),
+			  &zero) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n"));
+		tdb->ecode = TDB_ERR_IO;
+		return -1;			
+	}
+
+	if (transaction_sync(tdb, 0, recovery_eof) == -1) {
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync2 recovery\n"));
+		tdb->ecode = TDB_ERR_IO;
+		return -1;
+	}
+
+	TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %d byte database\n", 
+		 recovery_eof));
+
+	/* all done */
+	return 0;
+}
+
+/* Any I/O failures we say "needs recovery". */
+bool tdb_needs_recovery(struct tdb_context *tdb)
+{
+	tdb_off_t recovery_head;
+	struct tdb_record rec;
+
+	/* find the recovery area */
+	if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+		return true;
+	}
+
+	if (recovery_head == 0) {
+		/* we have never allocated a recovery record */
+		return false;
+	}
+
+	/* read the recovery record */
+	if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
+				   sizeof(rec), DOCONV()) == -1) {
+		return true;
+	}
+
+	return (rec.magic == TDB_RECOVERY_MAGIC);
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/common/traverse.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/common/traverse.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/common/traverse.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,366 @@
+ /* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell              1999-2005
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000-2003
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+#define TDB_NEXT_LOCK_ERR ((tdb_off_t)-1)
+
+/* Uses traverse lock: 0 = finish, TDB_NEXT_LOCK_ERR = error,
+   other = record offset */
+static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tlock,
+			 struct tdb_record *rec)
+{
+	int want_next = (tlock->off != 0);
+
+	/* Lock each chain from the start one. */
+	for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
+		if (!tlock->off && tlock->hash != 0) {
+			/* this is an optimisation for the common case where
+			   the hash chain is empty, which is particularly
+			   common for the use of tdb with ldb, where large
+			   hashes are used. In that case we spend most of our
+			   time in tdb_brlock(), locking empty hash chains.
+
+			   To avoid this, we do an unlocked pre-check to see
+			   if the hash chain is empty before starting to look
+			   inside it. If it is empty then we can avoid that
+			   hash chain. If it isn't empty then we can't believe
+			   the value we get back, as we read it without a
+			   lock, so instead we get the lock and re-fetch the
+			   value below.
+
+			   Notice that not doing this optimisation on the
+			   first hash chain is critical. We must guarantee
+			   that we have done at least one fcntl lock at the
+			   start of a search to guarantee that memory is
+			   coherent on SMP systems. If records are added by
+			   others during the search then thats OK, and we
+			   could possibly miss those with this trick, but we
+			   could miss them anyway without this trick, so the
+			   semantics don't change.
+
+			   With a non-indexed ldb search this trick gains us a
+			   factor of around 80 in speed on a linux 2.6.x
+			   system (testing using ldbtest).
+			*/
+			tdb->methods->next_hash_chain(tdb, &tlock->hash);
+			if (tlock->hash == tdb->header.hash_size) {
+				continue;
+			}
+		}
+
+		if (tdb_lock(tdb, tlock->hash, tlock->lock_rw) == -1)
+			return TDB_NEXT_LOCK_ERR;
+
+		/* No previous record?  Start at top of chain. */
+		if (!tlock->off) {
+			if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->hash),
+				     &tlock->off) == -1)
+				goto fail;
+		} else {
+			/* Otherwise unlock the previous record. */
+			if (tdb_unlock_record(tdb, tlock->off) != 0)
+				goto fail;
+		}
+
+		if (want_next) {
+			/* We have offset of old record: grab next */
+			if (tdb_rec_read(tdb, tlock->off, rec) == -1)
+				goto fail;
+			tlock->off = rec->next;
+		}
+
+		/* Iterate through chain */
+		while( tlock->off) {
+			tdb_off_t current;
+			if (tdb_rec_read(tdb, tlock->off, rec) == -1)
+				goto fail;
+
+			/* Detect infinite loops. From "Shlomi Yaakobovich" <Shlomi at exanet.com>. */
+			if (tlock->off == rec->next) {
+				tdb->ecode = TDB_ERR_CORRUPT;
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: loop detected.\n"));
+				goto fail;
+			}
+
+			if (!TDB_DEAD(rec)) {
+				/* Woohoo: we found one! */
+				if (tdb_lock_record(tdb, tlock->off) != 0)
+					goto fail;
+				return tlock->off;
+			}
+
+			/* Try to clean dead ones from old traverses */
+			current = tlock->off;
+			tlock->off = rec->next;
+			if (!(tdb->read_only || tdb->traverse_read) && 
+			    tdb_do_delete(tdb, current, rec) != 0)
+				goto fail;
+		}
+		tdb_unlock(tdb, tlock->hash, tlock->lock_rw);
+		want_next = 0;
+	}
+	/* We finished iteration without finding anything */
+	tdb->ecode = TDB_SUCCESS;
+	return 0;
+
+ fail:
+	tlock->off = 0;
+	if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0)
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n"));
+	return TDB_NEXT_LOCK_ERR;
+}
+
+/* traverse the entire database - calling fn(tdb, key, data) on each element.
+   return -1 on error or the record count traversed
+   if fn is NULL then it is not called
+   a non-zero return value from fn() indicates that the traversal should stop
+  */
+static int tdb_traverse_internal(struct tdb_context *tdb, 
+				 tdb_traverse_func fn, void *private_data,
+				 struct tdb_traverse_lock *tl)
+{
+	TDB_DATA key, dbuf;
+	struct tdb_record rec;
+	int ret = 0, count = 0;
+	tdb_off_t off;
+
+	/* This was in the initializaton, above, but the IRIX compiler
+	 * did not like it.  crh
+	 */
+	tl->next = tdb->travlocks.next;
+
+	/* fcntl locks don't stack: beware traverse inside traverse */
+	tdb->travlocks.next = tl;
+
+	/* tdb_next_lock places locks on the record returned, and its chain */
+	while ((off = tdb_next_lock(tdb, tl, &rec)) != 0) {
+		if (off == TDB_NEXT_LOCK_ERR) {
+			ret = -1;
+			goto out;
+		}
+		count++;
+		/* now read the full record */
+		key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec), 
+					  rec.key_len + rec.data_len);
+		if (!key.dptr) {
+			ret = -1;
+			if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0)
+				goto out;
+			if (tdb_unlock_record(tdb, tl->off) != 0)
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
+			goto out;
+		}
+		key.dsize = rec.key_len;
+		dbuf.dptr = key.dptr + rec.key_len;
+		dbuf.dsize = rec.data_len;
+
+		tdb_trace_1rec_retrec(tdb, "traverse", key, dbuf);
+
+		/* Drop chain lock, call out */
+		if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) {
+			ret = -1;
+			SAFE_FREE(key.dptr);
+			goto out;
+		}
+		if (fn && fn(tdb, key, dbuf, private_data)) {
+			/* They want us to terminate traversal */
+			tdb_trace_ret(tdb, "tdb_traverse_end", count);
+			if (tdb_unlock_record(tdb, tl->off) != 0) {
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: unlock_record failed!\n"));;
+				ret = -1;
+			}
+			SAFE_FREE(key.dptr);
+			goto out;
+		}
+		SAFE_FREE(key.dptr);
+	}
+	tdb_trace(tdb, "tdb_traverse_end");
+out:
+	tdb->travlocks.next = tl->next;
+	if (ret < 0)
+		return -1;
+	else
+		return count;
+}
+
+
+/*
+  a write style traverse - temporarily marks the db read only
+*/
+int tdb_traverse_read(struct tdb_context *tdb, 
+		      tdb_traverse_func fn, void *private_data)
+{
+	struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK };
+	int ret;
+
+	/* we need to get a read lock on the transaction lock here to
+	   cope with the lock ordering semantics of solaris10 */
+	if (tdb_transaction_lock(tdb, F_RDLCK, TDB_LOCK_WAIT)) {
+		return -1;
+	}
+
+	tdb->traverse_read++;
+	tdb_trace(tdb, "tdb_traverse_read_start");
+	ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
+	tdb->traverse_read--;
+
+	tdb_transaction_unlock(tdb, F_RDLCK);
+
+	return ret;
+}
+
+/*
+  a write style traverse - needs to get the transaction lock to
+  prevent deadlocks
+
+  WARNING: The data buffer given to the callback fn does NOT meet the
+  alignment restrictions malloc gives you.
+*/
+int tdb_traverse(struct tdb_context *tdb, 
+		 tdb_traverse_func fn, void *private_data)
+{
+	struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
+	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)) {
+		return -1;
+	}
+
+	tdb->traverse_write++;
+	tdb_trace(tdb, "tdb_traverse_start");
+	ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
+	tdb->traverse_write--;
+
+	tdb_transaction_unlock(tdb, F_WRLCK);
+
+	return ret;
+}
+
+
+/* find the first entry in the database and return its key */
+TDB_DATA tdb_firstkey(struct tdb_context *tdb)
+{
+	TDB_DATA key;
+	struct tdb_record rec;
+	tdb_off_t off;
+
+	/* release any old lock */
+	if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0)
+		return tdb_null;
+	tdb->travlocks.off = tdb->travlocks.hash = 0;
+	tdb->travlocks.lock_rw = F_RDLCK;
+
+	/* Grab first record: locks chain and returned record. */
+	off = tdb_next_lock(tdb, &tdb->travlocks, &rec);
+	if (off == 0 || off == TDB_NEXT_LOCK_ERR) {
+		tdb_trace_retrec(tdb, "tdb_firstkey", tdb_null);
+		return tdb_null;
+	}
+	/* now read the key */
+	key.dsize = rec.key_len;
+	key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
+
+	tdb_trace_retrec(tdb, "tdb_firstkey", key);
+
+	/* Unlock the hash chain of the record we just read. */
+	if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
+	return key;
+}
+
+/* find the next entry in the database, returning its key */
+TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
+{
+	uint32_t oldhash;
+	TDB_DATA key = tdb_null;
+	struct tdb_record rec;
+	unsigned char *k = NULL;
+	tdb_off_t off;
+
+	/* Is locked key the old key?  If so, traverse will be reliable. */
+	if (tdb->travlocks.off) {
+		if (tdb_lock(tdb,tdb->travlocks.hash,tdb->travlocks.lock_rw))
+			return tdb_null;
+		if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1
+		    || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
+					    rec.key_len))
+		    || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
+			/* No, it wasn't: unlock it and start from scratch */
+			if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) {
+				tdb_trace_1rec_retrec(tdb, "tdb_nextkey",
+						      oldkey, tdb_null);
+				SAFE_FREE(k);
+				return tdb_null;
+			}
+			if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) {
+				SAFE_FREE(k);
+				return tdb_null;
+			}
+			tdb->travlocks.off = 0;
+		}
+
+		SAFE_FREE(k);
+	}
+
+	if (!tdb->travlocks.off) {
+		/* No previous element: do normal find, and lock record */
+		tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb->hash_fn(&oldkey), tdb->travlocks.lock_rw, &rec);
+		if (!tdb->travlocks.off) {
+			tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, tdb_null);
+			return tdb_null;
+		}
+		tdb->travlocks.hash = BUCKET(rec.full_hash);
+		if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) {
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
+			return tdb_null;
+		}
+	}
+	oldhash = tdb->travlocks.hash;
+
+	/* Grab next record: locks chain and returned record,
+	   unlocks old record */
+	off = tdb_next_lock(tdb, &tdb->travlocks, &rec);
+	if (off != TDB_NEXT_LOCK_ERR && off != 0) {
+		key.dsize = rec.key_len;
+		key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
+					  key.dsize);
+		/* Unlock the chain of this new record */
+		if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
+			TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+	}
+	/* Unlock the chain of old record */
+	if (tdb_unlock(tdb, BUCKET(oldhash), tdb->travlocks.lock_rw) != 0)
+		TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+	tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, key);
+	return key;
+}
+

Added: branches/ctdb/squeeze-backports/lib/tdb/config.guess
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/config.guess	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/config.guess	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1561 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2009-04-27'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd | genuineintel)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel at ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/lib/tdb/config.guess
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tdb/config.mk
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/config.mk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/config.mk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,66 @@
+################################################
+# Start SUBSYSTEM LIBTDB
+[LIBRARY::LIBTDB]
+OUTPUT_TYPE = MERGED_OBJ
+CFLAGS = -I$(tdbsrcdir)/include
+#
+# End SUBSYSTEM ldb
+################################################
+
+LIBTDB_OBJ_FILES = $(addprefix $(tdbsrcdir)/common/, \
+	tdb.o dump.o io.o lock.o \
+	open.o traverse.o freelist.o \
+	error.o transaction.o check.o)
+
+################################################
+# Start BINARY tdbtool
+[BINARY::tdbtool]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+		LIBTDB
+# End BINARY tdbtool
+################################################
+
+tdbtool_OBJ_FILES = $(tdbsrcdir)/tools/tdbtool.o
+
+################################################
+# Start BINARY tdbtorture
+[BINARY::tdbtorture]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+		LIBTDB
+# End BINARY tdbtorture
+################################################
+
+tdbtorture_OBJ_FILES = $(tdbsrcdir)/tools/tdbtorture.o
+
+################################################
+# Start BINARY tdbrestore
+[BINARY::tdbrestore]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+		LIBTDB
+# End BINARY tdbrestore
+################################################
+
+################################################
+# Start BINARY tdbdump
+[BINARY::tdbdump]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+		LIBTDB
+# End BINARY tdbdump
+################################################
+
+tdbdump_OBJ_FILES = $(tdbsrcdir)/tools/tdbdump.o
+
+################################################
+# Start BINARY tdbbackup
+[BINARY::tdbbackup]
+INSTALLDIR = BINDIR
+PRIVATE_DEPENDENCIES = \
+		LIBTDB
+# End BINARY tdbbackup
+################################################
+
+tdbbackup_OBJ_FILES = $(tdbsrcdir)/tools/tdbbackup.o

Added: branches/ctdb/squeeze-backports/lib/tdb/config.sub
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/config.sub	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/config.sub	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1686 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2009-04-17'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/lib/tdb/config.sub
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tdb/configure.ac
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/configure.ac	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/configure.ac	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,44 @@
+AC_PREREQ(2.50)
+AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
+AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
+AC_DEFUN([SMB_ENABLE], [echo -n ""])
+AC_INIT(tdb, 1.2.6)
+AC_CONFIG_SRCDIR([common/tdb.c])
+AC_CONFIG_HEADER(include/config.h)
+AC_LIBREPLACE_ALL_CHECKS
+AC_LD_SONAMEFLAG
+AC_LD_VERSIONSCRIPT
+AC_LD_PICFLAG
+AC_LD_SHLIBEXT
+AC_LIBREPLACE_SHLD
+AC_LIBREPLACE_SHLD_FLAGS
+AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR
+m4_include(libtdb.m4)
+AC_PATH_PROGS([PYTHON_CONFIG], [python2.6-config python2.5-config python2.4-config python-config])
+AC_PATH_PROGS([PYTHON], [python2.6 python2.5 python2.4 python])
+
+PYTHON_BUILD_TARGET="build-python"
+PYTHON_INSTALL_TARGET="install-python"
+PYTHON_CHECK_TARGET="check-python"
+AC_SUBST(PYTHON_BUILD_TARGET)
+AC_SUBST(PYTHON_INSTALL_TARGET)
+AC_SUBST(PYTHON_CHECK_TARGET)
+if test -z "$PYTHON_CONFIG"; then
+	PYTHON_BUILD_TARGET=""
+	PYTHON_INSTALL_TARGET=""
+	PYTHON_CHECK_TARGET=""
+fi
+
+AC_ARG_ENABLE(python,
+	AS_HELP_STRING([--enable-python], [Enables python binding]),
+		[ if test "x$enableval" = "xno" ; then
+			PYTHON_BUILD_TARGET=""
+			PYTHON_INSTALL_TARGET=""
+			PYTHON_CHECK_TARGET=""
+		  fi
+		])
+
+m4_include(build_macros.m4)
+BUILD_WITH_SHARED_BUILD_DIR
+
+AC_OUTPUT(Makefile tdb.pc)

Added: branches/ctdb/squeeze-backports/lib/tdb/docs/README
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/docs/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/docs/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,273 @@
+tdb - a trivial database system
+tridge at linuxcare.com December 1999
+==================================
+
+This is a simple database API. It was inspired by the realisation that
+in Samba we have several ad-hoc bits of code that essentially
+implement small databases for sharing structures between parts of
+Samba. As I was about to add another I realised that a generic
+database module was called for to replace all the ad-hoc bits.
+
+I based the interface on gdbm. I couldn't use gdbm as we need to be
+able to have multiple writers to the databases at one time.
+
+Compilation
+-----------
+
+add HAVE_MMAP=1 to use mmap instead of read/write
+add NOLOCK=1 to disable locking code
+
+Testing
+-------
+
+Compile tdbtest.c and link with gdbm for testing. tdbtest will perform
+identical operations via tdb and gdbm then make sure the result is the
+same
+
+Also included is tdbtool, which allows simple database manipulation
+on the commandline.
+
+tdbtest and tdbtool are not built as part of Samba, but are included
+for completeness.
+
+Interface
+---------
+
+The interface is very similar to gdbm except for the following:
+
+- different open interface. The tdb_open call is more similar to a
+  traditional open()
+- no tdbm_reorganise() function
+- no tdbm_sync() function. No operations are cached in the library anyway
+- added a tdb_traverse() function for traversing the whole database
+- added transactions support
+
+A general rule for using tdb is that the caller frees any returned
+TDB_DATA structures. Just call free(p.dptr) to free a TDB_DATA
+return value called p. This is the same as gdbm.
+
+here is a full list of tdb functions with brief descriptions.
+
+
+----------------------------------------------------------------------
+TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
+		      int open_flags, mode_t mode)
+
+   open the database, creating it if necessary 
+
+   The open_flags and mode are passed straight to the open call on the database
+   file. A flags value of O_WRONLY is invalid
+
+   The hash size is advisory, use zero for a default value. 
+
+   return is NULL on error
+
+   possible tdb_flags are:
+    TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open
+    TDB_INTERNAL - don't use a file, instaed store the data in
+                   memory. The filename is ignored in this case.
+    TDB_NOLOCK - don't do any locking
+    TDB_NOMMAP - don't use mmap
+    TDB_NOSYNC - don't synchronise transactions to disk
+    TDB_SEQNUM - maintain a sequence number
+    TDB_VOLATILE - activate the per-hashchain freelist, default 5
+    TDB_ALLOW_NESTING - allow transactions to nest
+    TDB_DISALLOW_NESTING - disallow transactions to nest
+
+----------------------------------------------------------------------
+TDB_CONTEXT *tdb_open_ex(char *name, int hash_size, int tdb_flags,
+		         int open_flags, mode_t mode,
+			 const struct tdb_logging_context *log_ctx,
+			 tdb_hash_func hash_fn)
+
+This is like tdb_open(), but allows you to pass an initial logging and
+hash function. Be careful when passing a hash function - all users of
+the database must use the same hash function or you will get data
+corruption.
+
+
+----------------------------------------------------------------------
+char *tdb_error(TDB_CONTEXT *tdb);
+
+     return a error string for the last tdb error
+
+----------------------------------------------------------------------
+int tdb_close(TDB_CONTEXT *tdb);
+
+   close a database
+
+----------------------------------------------------------------------
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
+
+   fetch an entry in the database given a key 
+   if the return value has a null dptr then a error occurred
+
+   caller must free the resulting data
+
+----------------------------------------------------------------------
+int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
+		     int (*parser)(TDB_DATA key, TDB_DATA data,
+				   void *private_data),
+		     void *private_data);
+
+   Hand a record to a parser function without allocating it.
+
+   This function is meant as a fast tdb_fetch alternative for large records
+   that are frequently read. The "key" and "data" arguments point directly
+   into the tdb shared memory, they are not aligned at any boundary.
+
+   WARNING: The parser is called while tdb holds a lock on the record. DO NOT
+   call other tdb routines from within the parser. Also, for good performance
+   you should make the parser fast to allow parallel operations.
+
+   tdb_parse_record returns -1 if the record was not found.  If the record was
+   found, the return value of "parser" is passed up to the caller.
+
+----------------------------------------------------------------------
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
+
+   check if an entry in the database exists 
+
+   note that 1 is returned if the key is found and 0 is returned if not found
+   this doesn't match the conventions in the rest of this module, but is
+   compatible with gdbm
+
+----------------------------------------------------------------------
+int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
+                 TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
+
+   traverse the entire database - calling fn(tdb, key, data, state) on each 
+   element.
+
+   return -1 on error or the record count traversed
+
+   if fn is NULL then it is not called
+
+   a non-zero return value from fn() indicates that the traversal
+   should stop. Traversal callbacks may not start transactions.
+
+   WARNING: The data buffer given to the callback fn does NOT meet the
+   alignment restrictions malloc gives you.
+
+----------------------------------------------------------------------
+int tdb_traverse_read(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
+                     TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
+
+   traverse the entire database - calling fn(tdb, key, data, state) on
+   each element, but marking the database read only during the
+   traversal, so any write operations will fail. This allows tdb to
+   use read locks, which increases the parallelism possible during the
+   traversal.
+
+   return -1 on error or the record count traversed
+
+   if fn is NULL then it is not called
+
+   a non-zero return value from fn() indicates that the traversal
+   should stop. Traversal callbacks may not start transactions.
+
+----------------------------------------------------------------------
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
+
+   find the first entry in the database and return its key
+
+   the caller must free the returned data
+
+----------------------------------------------------------------------
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
+
+   find the next entry in the database, returning its key
+
+   the caller must free the returned data
+
+----------------------------------------------------------------------
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
+
+   delete an entry in the database given a key
+
+----------------------------------------------------------------------
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+
+   store an element in the database, replacing any existing element
+   with the same key 
+
+   If flag==TDB_INSERT then don't overwrite an existing entry
+   If flag==TDB_MODIFY then don't create a new entry
+
+   return 0 on success, -1 on failure
+
+----------------------------------------------------------------------
+int tdb_writelock(TDB_CONTEXT *tdb);
+
+   lock the database. If we already have it locked then don't do anything
+
+----------------------------------------------------------------------
+int tdb_writeunlock(TDB_CONTEXT *tdb);
+   unlock the database
+
+----------------------------------------------------------------------
+int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key);
+
+   lock one hash chain. This is meant to be used to reduce locking
+   contention - it cannot guarantee how many records will be locked
+
+----------------------------------------------------------------------
+int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key);
+
+   unlock one hash chain
+
+----------------------------------------------------------------------
+int tdb_transaction_start(TDB_CONTEXT *tdb)
+
+   start a transaction. All operations after the transaction start can
+   either be committed with tdb_transaction_commit() or cancelled with
+   tdb_transaction_cancel(). 
+
+   If you call tdb_transaction_start() again on the same tdb context
+   while a transaction is in progress, then the same transaction
+   buffer is re-used. The number of tdb_transaction_{commit,cancel}
+   operations must match the number of successful
+   tdb_transaction_start() calls.
+
+   Note that transactions are by default disk synchronous, and use a
+   recover area in the database to automatically recover the database
+   on the next open if the system crashes during a transaction. You
+   can disable the synchronous transaction recovery setup using the
+   TDB_NOSYNC flag, which will greatly speed up operations at the risk
+   of corrupting your database if the system crashes.
+
+   Operations made within a transaction are not visible to other users
+   of the database until a successful commit.
+
+----------------------------------------------------------------------
+int tdb_transaction_cancel(TDB_CONTEXT *tdb)
+
+   cancel a current transaction, discarding all write and lock
+   operations that have been made since the transaction started.
+
+
+----------------------------------------------------------------------
+int tdb_transaction_commit(TDB_CONTEXT *tdb)
+
+   commit a current transaction, updating the database and releasing
+   the transaction locks.
+
+----------------------------------------------------------------------
+int tdb_transaction_prepare_commit(TDB_CONTEXT *tdb)
+
+   prepare to commit a current transaction, for two-phase commits.
+   Once prepared for commit, the only allowed calls are
+   tdb_transaction_commit() or tdb_transaction_cancel(). Preparing
+   allocates disk space for the pending updates, so a subsequent
+   commit should succeed (barring any hardware failures).
+
+----------------------------------------------------------------------
+int tdb_check(TDB_CONTEXT *tdb,
+	      int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
+	      void *private_data);)
+
+   check the consistency of the database, calling back the check function
+   (if non-NULL) with each record.  If some consistency check fails, or
+   the supplied check function returns -1, tdb_check returns -1, otherwise
+   0.  Note that logging function (if set) will be called with additional
+   information on the corruption found.

Added: branches/ctdb/squeeze-backports/lib/tdb/docs/tdb.magic
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/docs/tdb.magic	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/docs/tdb.magic	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,10 @@
+# Magic file(1) information about tdb files.
+#
+# Install this into /etc/magic or the corresponding location for your
+# system, or pass as a -m argument to file(1).
+
+# You may use and redistribute this file without restriction.
+
+0	string	TDB\ file		TDB database
+>32	lelong	=0x2601196D		version 6, little-endian
+>>36	lelong	x			hash size %d bytes

Added: branches/ctdb/squeeze-backports/lib/tdb/docs/tracing.txt
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/docs/tracing.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/docs/tracing.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,46 @@
+How And Why To Use TDB Tracing
+==============================
+
+You can trace all TDB operations, using TDB_TRACE.  It is not complete
+(error conditions which expect to the logged will not always be traced
+correctly, so you should set up a logging function too), but is designed
+to collect benchmark-style traces to allow us to optimize TDB.
+
+Note: tracing is not efficient, and the trace files are huge: a
+traverse of the database is particularly large!  But they compress very
+well with rzip (http://rzip.samba.org)
+
+How to gather trace files:
+--------------------------
+1) Uncomment /* #define TDB_TRACE 1 */ in tdb_private.h.
+2) Rebuild TDB, and everything that uses it.
+3) Run something.
+
+Your trace files will be called <tdbname>.trace.<pid>.  These files
+will not be overwritten: if the same process reopens the same TDB, an
+error will be logged and tracing will be disabled.
+
+How to replay trace files:
+--------------------------
+1) For benchmarking, remember to rebuild tdb with #define TDB_TRACE commented
+   out again!
+2) Grab the latest "replace_trace.c" from CCAN's tdb module (tools/ dir):
+	http://ccan.ozlabs.org/tarballs/tdb.tar.bz2
+3) Compile up replay_trace, munging as necessary.
+4) Run replay_trace <scratch-tdb-name> <tracefiles>...
+
+If given more than one trace file (presumably from the same tdb)
+replay_trace will try to figure out the dependencies between the operations
+and fire off a child to run each trace.  Occasionally it gets stuck, in
+which case it will add another dependency and retry.  Eventually it will
+give a speed value.
+
+replay_trace can intuit the existence of previous data in the tdb (ie.
+activity prior to the trace(s) supplied) and will prepopulate as
+neccessary.
+
+You can run --quiet for straight benchmark results, and -n to run multiple
+times (this saves time, since it need only calculate dependencies once).
+
+Good luck!
+Rusty Russell <rusty at rustcorp.com.au>

Added: branches/ctdb/squeeze-backports/lib/tdb/include/tdb.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/include/tdb.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/include/tdb.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,187 @@
+#ifndef __TDB_H__
+#define __TDB_H__
+
+/* 
+   Unix SMB/CIFS implementation.
+
+   trivial database library
+
+   Copyright (C) Andrew Tridgell 1999-2004
+   
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include "signal.h"
+
+/* Samba sets hidden attribute when building libraries: we don't. */
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+/* flags to tdb_store() */
+#define TDB_REPLACE 1		/* Unused */
+#define TDB_INSERT 2 		/* Don't overwrite an existing entry */
+#define TDB_MODIFY 3		/* Don't create an existing entry    */
+
+/* flags for tdb_open() */
+#define TDB_DEFAULT 0 /* just a readability place holder */
+#define TDB_CLEAR_IF_FIRST 1
+#define TDB_INTERNAL 2 /* don't store on disk */
+#define TDB_NOLOCK   4 /* don't do any locking */
+#define TDB_NOMMAP   8 /* don't use mmap */
+#define TDB_CONVERT 16 /* convert endian (internal use) */
+#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
+#define TDB_NOSYNC   64 /* don't use synchronous transactions */
+#define TDB_SEQNUM   128 /* maintain a sequence number */
+#define TDB_VOLATILE   256 /* Activate the per-hashchain freelist, default 5 */
+#define TDB_ALLOW_NESTING 512 /* Allow transactions to nest */
+#define TDB_DISALLOW_NESTING 1024 /* Disallow transactions to nest */
+#define TDB_INCOMPATIBLE_HASH 2048 /* Better hashing: can't be opened by tdb < 1.2.6. */
+
+/* error codes */
+enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK, 
+		TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
+		TDB_ERR_NOEXIST, TDB_ERR_EINVAL, TDB_ERR_RDONLY,
+		TDB_ERR_NESTING};
+
+/* debugging uses one of the following levels */
+enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR, 
+		      TDB_DEBUG_WARNING, TDB_DEBUG_TRACE};
+
+typedef struct TDB_DATA {
+	unsigned char *dptr;
+	size_t dsize;
+} TDB_DATA;
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns.  a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+/* this is the context structure that is returned from a db open */
+typedef struct tdb_context TDB_CONTEXT;
+
+typedef int (*tdb_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *);
+typedef void (*tdb_log_func)(struct tdb_context *, enum tdb_debug_level, const char *, ...) PRINTF_ATTRIBUTE(3, 4);
+typedef unsigned int (*tdb_hash_func)(TDB_DATA *key);
+
+struct tdb_logging_context {
+        tdb_log_func log_fn;
+        void *log_private;
+};
+
+_PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
+		      int open_flags, mode_t mode);
+_PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+			 int open_flags, mode_t mode,
+			 const struct tdb_logging_context *log_ctx,
+			 tdb_hash_func hash_fn);
+_PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead);
+
+_PUBLIC_ int tdb_reopen(struct tdb_context *tdb);
+_PUBLIC_ int tdb_reopen_all(int parent_longlived);
+_PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log_ctx);
+_PUBLIC_ enum TDB_ERROR tdb_error(struct tdb_context *tdb);
+_PUBLIC_ const char *tdb_errorstr(struct tdb_context *tdb);
+_PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
+			      int (*parser)(TDB_DATA key, TDB_DATA data,
+					    void *private_data),
+			      void *private_data);
+_PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+_PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf);
+_PUBLIC_ int tdb_close(struct tdb_context *tdb);
+_PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb);
+_PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *);
+_PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *);
+_PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_lockall(struct tdb_context *tdb);
+_PUBLIC_ int tdb_lockall_nonblock(struct tdb_context *tdb);
+_PUBLIC_ int tdb_unlockall(struct tdb_context *tdb);
+_PUBLIC_ int tdb_lockall_read(struct tdb_context *tdb);
+_PUBLIC_ int tdb_lockall_read_nonblock(struct tdb_context *tdb);
+_PUBLIC_ int tdb_unlockall_read(struct tdb_context *tdb);
+_PUBLIC_ int tdb_lockall_mark(struct tdb_context *tdb);
+_PUBLIC_ int tdb_lockall_unmark(struct tdb_context *tdb);
+_PUBLIC_ const char *tdb_name(struct tdb_context *tdb);
+_PUBLIC_ int tdb_fd(struct tdb_context *tdb);
+_PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb);
+_PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_start(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_start_nonblock(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_prepare_commit(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_cancel(struct tdb_context *tdb);
+_PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb);
+_PUBLIC_ int tdb_hash_size(struct tdb_context *tdb);
+_PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb);
+_PUBLIC_ int tdb_get_flags(struct tdb_context *tdb);
+_PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flag);
+_PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flag);
+_PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb);
+_PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb);
+_PUBLIC_ unsigned int tdb_jenkins_hash(TDB_DATA *key);
+_PUBLIC_ int tdb_check(struct tdb_context *tdb,
+	      int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
+	      void *private_data);
+
+/* Low level locking functions: use with care */
+_PUBLIC_ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_transaction_write_lock(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_write_unlock(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_write_lock_mark(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_write_lock_unmark(struct tdb_context *tdb);
+
+_PUBLIC_ void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr);
+
+/* wipe and repack */
+_PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb);
+_PUBLIC_ int tdb_repack(struct tdb_context *tdb);
+
+/* Debug functions. Not used in production. */
+_PUBLIC_ void tdb_dump_all(struct tdb_context *tdb);
+_PUBLIC_ int tdb_printfreelist(struct tdb_context *tdb);
+_PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries);
+_PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb);
+
+_PUBLIC_ extern TDB_DATA tdb_null;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* tdb.h */

Added: branches/ctdb/squeeze-backports/lib/tdb/install-sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/install-sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/install-sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/lib/tdb/install-sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tdb/libtdb.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/libtdb.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/libtdb.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,35 @@
+dnl find the tdb sources. This is meant to work both for 
+dnl tdb standalone builds, and builds of packages using tdb
+tdbdir=""
+tdbpaths=". lib/tdb tdb ../tdb ../lib/tdb"
+for d in $tdbpaths; do
+	if test -f "$srcdir/$d/common/tdb.c"; then
+		tdbdir="$d"		
+		AC_SUBST(tdbdir)
+		break;
+	fi
+done
+if test x"$tdbdir" = "x"; then
+   AC_MSG_ERROR([cannot find tdb source in $tdbpaths])
+fi
+TDB_OBJ="common/tdb.o common/dump.o common/transaction.o common/error.o common/traverse.o"
+TDB_OBJ="$TDB_OBJ common/freelist.o common/freelistcheck.o common/io.o common/lock.o common/open.o common/check.o common/hash.o"
+AC_SUBST(TDB_OBJ)
+AC_SUBST(LIBREPLACEOBJ)
+
+TDB_LIBS=""
+AC_SUBST(TDB_LIBS)
+
+TDB_CFLAGS="-I$tdbdir/include"
+AC_SUBST(TDB_CFLAGS)
+
+AC_CHECK_FUNCS(mmap pread pwrite getpagesize utime)
+AC_CHECK_HEADERS(getopt.h sys/select.h sys/time.h)
+
+AC_HAVE_DECL(pread, [#include <unistd.h>])
+AC_HAVE_DECL(pwrite, [#include <unistd.h>])
+
+if test x"$VERSIONSCRIPT" != "x"; then
+    EXPORTSFILE=tdb.exports
+    AC_SUBST(EXPORTSFILE)
+fi

Added: branches/ctdb/squeeze-backports/lib/tdb/pytdb.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/pytdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/pytdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,601 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Python interface to tdb.
+
+   Copyright (C) 2004-2006 Tim Potter <tpot at samba.org>
+   Copyright (C) 2007-2008 Jelmer Vernooij <jelmer at samba.org>
+
+     ** NOTE! The following LGPL license applies to the tdb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+#include "replace.h"
+#include "system/filesys.h"
+
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
+#endif
+
+/* Include tdb headers */
+#include <tdb.h>
+
+typedef struct {
+	PyObject_HEAD
+	TDB_CONTEXT *ctx;
+	bool closed;
+} PyTdbObject;
+
+PyAPI_DATA(PyTypeObject) PyTdb;
+
+static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
+{
+	PyErr_SetObject(PyExc_RuntimeError, 
+		Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb)));
+}
+
+static TDB_DATA PyString_AsTDB_DATA(PyObject *data)
+{
+	TDB_DATA ret;
+	ret.dptr = (unsigned char *)PyString_AsString(data);
+	ret.dsize = PyString_Size(data);
+	return ret;
+}
+
+static PyObject *PyString_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);
+		free(data.dptr);
+		return ret;
+    }
+}
+
+#define PyErr_TDB_ERROR_IS_ERR_RAISE(ret, tdb) \
+	if (ret != 0) { \
+		PyErr_SetTDBError(tdb); \
+		return NULL; \
+	}
+
+static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+	char *name = NULL;
+	int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600;
+	TDB_CONTEXT *ctx;
+	PyTdbObject *ret;
+	const char *kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL };
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", (char **)kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
+		return NULL;
+
+	if (name == NULL) {
+		tdb_flags |= TDB_INTERNAL;
+	}
+
+	ctx = tdb_open(name, hash_size, tdb_flags, flags, mode);
+	if (ctx == NULL) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	ret = PyObject_New(PyTdbObject, &PyTdb);
+	if (!ret) {
+		tdb_close(ctx);
+		return NULL;
+	}
+
+	ret->ctx = ctx;
+	ret->closed = false;
+	return (PyObject *)ret;
+}
+
+static PyObject *obj_transaction_cancel(PyTdbObject *self)
+{
+	int ret = tdb_transaction_cancel(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_commit(PyTdbObject *self)
+{
+	int ret = tdb_transaction_commit(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_prepare_commit(PyTdbObject *self)
+{
+	int ret = tdb_transaction_prepare_commit(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_start(PyTdbObject *self)
+{
+	int ret = tdb_transaction_start(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_reopen(PyTdbObject *self)
+{
+	int ret = tdb_reopen(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_lockall(PyTdbObject *self)
+{
+	int ret = tdb_lockall(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_unlockall(PyTdbObject *self)
+{
+	int ret = tdb_unlockall(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_lockall_read(PyTdbObject *self)
+{
+	int ret = tdb_lockall_read(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_unlockall_read(PyTdbObject *self)
+{
+	int ret = tdb_unlockall_read(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_close(PyTdbObject *self)
+{
+	int ret;
+	if (self->closed)
+		Py_RETURN_NONE;
+	ret = tdb_close(self->ctx);
+	self->closed = true;
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_get(PyTdbObject *self, PyObject *args)
+{
+	TDB_DATA key;
+	PyObject *py_key;
+	if (!PyArg_ParseTuple(args, "O", &py_key))
+		return NULL;
+
+	key = PyString_AsTDB_DATA(py_key);
+
+	return PyString_FromTDB_DATA(tdb_fetch(self->ctx, key));
+}
+
+static PyObject *obj_append(PyTdbObject *self, PyObject *args)
+{
+	TDB_DATA key, data;
+	PyObject *py_key, *py_data;
+	int ret;
+	if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data))
+		return NULL;
+
+	key = PyString_AsTDB_DATA(py_key);
+	data = PyString_AsTDB_DATA(py_data);
+
+	ret = tdb_append(self->ctx, key, data);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_firstkey(PyTdbObject *self)
+{
+	return PyString_FromTDB_DATA(tdb_firstkey(self->ctx));
+}
+
+static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args)
+{
+	TDB_DATA key;
+	PyObject *py_key;
+	if (!PyArg_ParseTuple(args, "O", &py_key))
+		return NULL;
+
+	key = PyString_AsTDB_DATA(py_key);
+	
+	return PyString_FromTDB_DATA(tdb_nextkey(self->ctx, key));
+}
+
+static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
+{
+	TDB_DATA key;
+	PyObject *py_key;
+	int ret;
+	if (!PyArg_ParseTuple(args, "O", &py_key))
+		return NULL;
+
+	key = PyString_AsTDB_DATA(py_key);
+	ret = tdb_delete(self->ctx, key);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
+{
+	TDB_DATA key;
+	int ret;
+	PyObject *py_key;
+	if (!PyArg_ParseTuple(args, "O", &py_key))
+		return NULL;
+
+	key = PyString_AsTDB_DATA(py_key);
+	ret = tdb_exists(self->ctx, key);
+	if (ret != TDB_ERR_NOEXIST) {
+		PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	}
+
+	return (ret == TDB_ERR_NOEXIST)?Py_False:Py_True;
+}
+
+static PyObject *obj_store(PyTdbObject *self, PyObject *args)
+{
+	TDB_DATA key, value;
+	int ret;
+	int flag = TDB_REPLACE;
+	PyObject *py_key, *py_value;
+
+	if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag))
+		return NULL;
+
+	key = PyString_AsTDB_DATA(py_key);
+	value = PyString_AsTDB_DATA(py_value);
+
+	ret = tdb_store(self->ctx, key, value, flag);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_add_flags(PyTdbObject *self, PyObject *args)
+{
+	unsigned flags;
+
+	if (!PyArg_ParseTuple(args, "I", &flags))
+		return NULL;
+
+	tdb_add_flags(self->ctx, flags);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_remove_flags(PyTdbObject *self, PyObject *args)
+{
+	unsigned flags;
+
+	if (!PyArg_ParseTuple(args, "I", &flags))
+		return NULL;
+
+	tdb_remove_flags(self->ctx, flags);
+	Py_RETURN_NONE;
+}
+
+typedef struct {
+	PyObject_HEAD
+	TDB_DATA current;
+	PyTdbObject *iteratee;
+} PyTdbIteratorObject;
+
+static PyObject *tdb_iter_next(PyTdbIteratorObject *self)
+{
+	TDB_DATA current;
+	PyObject *ret;
+	if (self->current.dptr == NULL && self->current.dsize == 0)
+		return NULL;
+	current = self->current;
+	self->current = tdb_nextkey(self->iteratee->ctx, self->current);
+	ret = PyString_FromTDB_DATA(current);
+	return ret;
+}
+
+static void tdb_iter_dealloc(PyTdbIteratorObject *self)
+{
+	Py_DECREF(self->iteratee);
+	PyObject_Del(self);
+}
+
+PyTypeObject PyTdbIterator = {
+	.tp_name = "Iterator",
+	.tp_basicsize = sizeof(PyTdbIteratorObject),
+	.tp_iternext = (iternextfunc)tdb_iter_next,
+	.tp_dealloc = (destructor)tdb_iter_dealloc,
+	.tp_flags = Py_TPFLAGS_DEFAULT,
+	.tp_iter = PyObject_SelfIter,
+};
+
+static PyObject *tdb_object_iter(PyTdbObject *self)
+{
+	PyTdbIteratorObject *ret;	
+
+	ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator);
+	if (!ret)
+		return NULL;
+	ret->current = tdb_firstkey(self->ctx);
+	ret->iteratee = self;
+	Py_INCREF(self);
+	return (PyObject *)ret;
+}
+
+static PyObject *obj_clear(PyTdbObject *self)
+{
+	int ret = tdb_wipe_all(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_repack(PyTdbObject *self)
+{
+	int ret = tdb_repack(self->ctx);
+	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_enable_seqnum(PyTdbObject *self)
+{
+	tdb_enable_seqnum(self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self)
+{
+	tdb_increment_seqnum_nonblock(self->ctx);
+	Py_RETURN_NONE;
+}
+
+static PyMethodDef tdb_object_methods[] = {
+	{ "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS, 
+		"S.transaction_cancel() -> None\n"
+		"Cancel the currently active transaction." },
+	{ "transaction_commit", (PyCFunction)obj_transaction_commit, METH_NOARGS,
+		"S.transaction_commit() -> None\n"
+		"Commit the currently active transaction." },
+	{ "transaction_prepare_commit", (PyCFunction)obj_transaction_prepare_commit, METH_NOARGS,
+		"S.transaction_prepare_commit() -> None\n"
+		"Prepare to commit the currently active transaction" },
+	{ "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS,
+		"S.transaction_start() -> None\n"
+		"Start a new transaction." },
+	{ "reopen", (PyCFunction)obj_reopen, METH_NOARGS, "Reopen this file." },
+	{ "lock_all", (PyCFunction)obj_lockall, METH_NOARGS, NULL },
+	{ "unlock_all", (PyCFunction)obj_unlockall, METH_NOARGS, NULL },
+	{ "read_lock_all", (PyCFunction)obj_lockall_read, METH_NOARGS, NULL },
+	{ "read_unlock_all", (PyCFunction)obj_unlockall_read, METH_NOARGS, NULL },
+	{ "close", (PyCFunction)obj_close, METH_NOARGS, NULL },
+	{ "get", (PyCFunction)obj_get, METH_VARARGS, "S.get(key) -> value\n"
+		"Fetch a value." },
+	{ "append", (PyCFunction)obj_append, METH_VARARGS, "S.append(key, value) -> None\n"
+		"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"
+		"Return the next key in this database." },
+	{ "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n"
+		"Delete an entry." },
+	{ "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> None\n"
+		"Check whether key exists in this database." },
+	{ "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" },
+	{ "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
+	{ "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
+		"Wipe the entire database." },
+	{ "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
+		"Repack the entire database." },
+	{ "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS,
+		"S.enable_seqnum() -> None" },
+	{ "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
+		"S.increment_seqnum_nonblock() -> None" },
+	{ NULL }
+};
+
+static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure)
+{
+	return PyInt_FromLong(tdb_hash_size(self->ctx));
+}
+
+static int obj_set_max_dead(PyTdbObject *self, PyObject *max_dead, void *closure)
+{
+	if (!PyInt_Check(max_dead))
+		return -1;
+	tdb_set_max_dead(self->ctx, PyInt_AsLong(max_dead));
+	return 0;
+}
+
+static PyObject *obj_get_map_size(PyTdbObject *self, void *closure)
+{
+	return PyInt_FromLong(tdb_map_size(self->ctx));
+}
+
+static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure)
+{
+	return PyInt_FromLong(tdb_freelist_size(self->ctx));
+}
+
+static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
+{
+	return PyInt_FromLong(tdb_get_flags(self->ctx));
+}
+
+static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
+{
+	return PyString_FromString(tdb_name(self->ctx));
+}
+
+static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
+{
+	return PyInt_FromLong(tdb_get_seqnum(self->ctx));
+}
+
+
+static PyGetSetDef tdb_object_getsetters[] = {
+	{ (char *)"hash_size", (getter)obj_get_hash_size, NULL, NULL },
+	{ (char *)"map_size", (getter)obj_get_map_size, NULL, NULL },
+	{ (char *)"freelist_size", (getter)obj_get_freelist_size, NULL, NULL },
+	{ (char *)"flags", (getter)obj_get_flags, NULL, NULL },
+	{ (char *)"max_dead", NULL, (setter)obj_set_max_dead, NULL },
+	{ (char *)"filename", (getter)obj_get_filename, NULL, (char *)"The filename of this TDB file."},
+	{ (char *)"seqnum", (getter)obj_get_seqnum, NULL, NULL },
+	{ NULL }
+};
+
+static PyObject *tdb_object_repr(PyTdbObject *self)
+{
+	if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
+		return PyString_FromString("Tdb(<internal>)");
+	} else {
+		return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx));
+	}
+}
+
+static void tdb_object_dealloc(PyTdbObject *self)
+{
+	if (!self->closed)
+		tdb_close(self->ctx);
+	PyObject_Del(self);
+}
+
+static PyObject *obj_getitem(PyTdbObject *self, PyObject *key)
+{
+	TDB_DATA tkey, val;
+	if (!PyString_Check(key)) {
+		PyErr_SetString(PyExc_TypeError, "Expected string as key");
+		return NULL;
+	}
+
+	tkey.dptr = (unsigned char *)PyString_AsString(key);
+	tkey.dsize = PyString_Size(key);
+
+	val = tdb_fetch(self->ctx, tkey);
+	if (val.dptr == NULL) {
+		PyErr_SetString(PyExc_KeyError, "No such TDB entry");
+		return NULL;
+	} else {
+		return PyString_FromTDB_DATA(val);
+	}
+}
+
+static int obj_setitem(PyTdbObject *self, PyObject *key, PyObject *value)
+{
+	TDB_DATA tkey, tval;
+	int ret;
+	if (!PyString_Check(key)) {
+		PyErr_SetString(PyExc_TypeError, "Expected string as key");
+		return -1;
+	}
+
+	tkey = PyString_AsTDB_DATA(key);
+
+	if (value == NULL) { 
+		ret = tdb_delete(self->ctx, tkey);
+	} else { 
+		if (!PyString_Check(value)) {
+			PyErr_SetString(PyExc_TypeError, "Expected string as value");
+			return -1;
+		}
+
+		tval = PyString_AsTDB_DATA(value);
+
+		ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE);
+	}
+
+	if (ret != 0) {
+		PyErr_SetTDBError(self->ctx);
+		return -1;
+	} 
+
+	return ret;
+}
+
+static PyMappingMethods tdb_object_mapping = {
+	.mp_subscript = (binaryfunc)obj_getitem,
+	.mp_ass_subscript = (objobjargproc)obj_setitem,
+};
+PyTypeObject PyTdb = {
+	.tp_name = "Tdb",
+	.tp_basicsize = sizeof(PyTdbObject),
+	.tp_methods = tdb_object_methods,
+	.tp_getset = tdb_object_getsetters,
+	.tp_new = py_tdb_open,
+	.tp_doc = "A TDB file",
+	.tp_repr = (reprfunc)tdb_object_repr,
+	.tp_dealloc = (destructor)tdb_object_dealloc,
+	.tp_as_mapping = &tdb_object_mapping,
+	.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER,
+	.tp_iter = (getiterfunc)tdb_object_iter,
+};
+
+static PyMethodDef tdb_methods[] = {
+	{ "open", (PyCFunction)py_tdb_open, METH_VARARGS|METH_KEYWORDS, "open(name, hash_size=0, tdb_flags=TDB_DEFAULT, flags=O_RDWR, mode=0600)\n"
+		"Open a TDB file." },
+	{ NULL }
+};
+
+void inittdb(void)
+{
+	PyObject *m;
+
+	if (PyType_Ready(&PyTdb) < 0)
+		return;
+
+	if (PyType_Ready(&PyTdbIterator) < 0)
+		return;
+
+	m = Py_InitModule3("tdb", tdb_methods, "TDB is a simple key-value database similar to GDBM that supports multiple writers.");
+	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));
+
+	Py_INCREF(&PyTdb);
+	PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
+
+	Py_INCREF(&PyTdbIterator);
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/python/tdbdump.py
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/python/tdbdump.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/python/tdbdump.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+# Trivial reimplementation of tdbdump in Python
+
+import tdb, sys
+
+if len(sys.argv) < 2:
+    print "Usage: tdbdump.py <tdb-file>"
+    sys.exit(1)
+
+db = tdb.Tdb(sys.argv[1])
+for (k, v) in db.iteritems():
+    print "{\nkey(%d) = %r\ndata(%d) = %r\n}" % (len(k), k, len(v), v)

Added: branches/ctdb/squeeze-backports/lib/tdb/python/tests/simple.py
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/python/tests/simple.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/python/tests/simple.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+# Some simple tests for the Python bindings for TDB
+# Note that this tests the interface of the Python bindings
+# It does not test tdb itself.
+#
+# Copyright (C) 2007-2008 Jelmer Vernooij <jelmer at samba.org>
+# Published under the GNU LGPLv3 or later
+
+import tdb
+from unittest import TestCase
+import os, tempfile
+
+
+class OpenTdbTests(TestCase):
+    def test_nonexistant_read(self):
+        self.assertRaises(IOError, tdb.Tdb, "/some/nonexistant/file", 0, tdb.DEFAULT, os.O_RDWR)
+
+class CloseTdbTests(TestCase):
+
+    def test_double_close(self):
+        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, os.O_CREAT|os.O_RDWR)
+        self.assertNotEqual(None, self.tdb)
+
+        # ensure that double close does not crash python
+        self.tdb.close()
+        self.tdb.close()
+
+
+class InternalTdbTests(TestCase):
+
+    def test_repr(self):
+        self.tdb = tdb.Tdb()
+
+        # repr used to crash on internal db
+        self.assertEquals(repr(self.tdb), "Tdb(<internal>)")
+
+
+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 tearDown(self):
+        del self.tdb
+
+    def test_repr(self):
+        self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+
+    def test_lockall(self):
+        self.tdb.lock_all()
+
+    def test_max_dead(self):
+        self.tdb.max_dead = 20
+
+    def test_unlockall(self):
+        self.tdb.lock_all()
+        self.tdb.unlock_all()
+
+    def test_lockall_read(self):
+        self.tdb.read_lock_all()
+        self.tdb.read_unlock_all()
+
+    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
+
+    def test_map_size(self):
+        self.tdb.map_size
+
+    def test_freelist_size(self):
+        self.tdb.freelist_size
+
+    def test_name(self):
+        self.tdb.filename
+
+    def test_iterator(self):
+        self.tdb["bla"] = "1"
+        self.tdb["brainslug"] = "2"
+        self.assertEquals(["bla", "brainslug"], list(self.tdb))
+
+    def test_transaction_cancel(self):
+        self.tdb["bloe"] = "2"
+        self.tdb.transaction_start()
+        self.tdb["bloe"] = "1"
+        self.tdb.transaction_cancel()
+        self.assertEquals("2", self.tdb["bloe"])
+
+    def test_transaction_commit(self):
+        self.tdb["bloe"] = "2"
+        self.tdb.transaction_start()
+        self.tdb["bloe"] = "1"
+        self.tdb.transaction_commit()
+        self.assertEquals("1", self.tdb["bloe"])
+
+    def test_transaction_prepare_commit(self):
+        self.tdb["bloe"] = "2"
+        self.tdb.transaction_start()
+        self.tdb["bloe"] = "1"
+        self.tdb.transaction_prepare_commit()
+        self.tdb.transaction_commit()
+        self.assertEquals("1", self.tdb["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()]))
+
+    def test_clear(self):
+        self.tdb["bloe"] = "2"
+        self.tdb["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["foo"] = "abc"
+        self.tdb["bar"] = "def"
+        del self.tdb["foo"]
+        self.tdb.repack()
+
+    def test_seqnum(self):
+        self.tdb.enable_seqnum()
+        seq1 = self.tdb.seqnum
+        self.tdb.increment_seqnum_nonblock()
+        seq2 = self.tdb.seqnum
+        self.assertEquals(seq2-seq1, 1)
+
+    def test_len(self):
+        self.assertEquals(0, len(list(self.tdb)))
+        self.tdb["entry"] = "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 VersionTests(TestCase):
+
+    def test_present(self):
+        self.assertTrue(isinstance(tdb.__version__, str))
+
+
+if __name__ == '__main__':
+    import unittest
+    unittest.TestProgram()

Added: branches/ctdb/squeeze-backports/lib/tdb/python.mk
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/python.mk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/python.mk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,6 @@
+[PYTHON::pytdb]
+LIBRARY_REALNAME = tdb.$(SHLIBEXT)
+PUBLIC_DEPENDENCIES = LIBTDB DYNCONFIG
+
+pytdb_OBJ_FILES = $(tdbsrcdir)/pytdb.o
+

Added: branches/ctdb/squeeze-backports/lib/tdb/rules.mk
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/rules.mk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/rules.mk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,16 @@
+showflags::
+	@echo 'tdb will be compiled with flags:'
+	@echo '  CFLAGS = $(CFLAGS)'
+	@echo '  CPPFLAGS = $(CPPFLAGS)'
+	@echo '  LDFLAGS = $(LDFLAGS)'
+	@echo '  LIBS = $(LIBS)'
+
+.SUFFIXES: .c .o
+
+.c.o:
+	@echo Compiling $*.c
+	@mkdir -p `dirname $@`
+	@$(CC) $(PICFLAG) $(CFLAGS) $(ABI_CHECK) -c $< -o $@
+
+distclean::
+	rm -f *~ */*~

Added: branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,91 @@
+#!/bin/sh
+
+#
+# abi_checks.sh - check for possible abi changes
+#
+# Copyright (C) 2009 Michael Adam <obnox at samba.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# USAGE: abi_checks.sh LIBNAME header1 [header2 ...]
+#
+# This script creates symbol and signature lists from the provided header
+# files with the aid of the mksyms.sh and mksigs.pl scripts (saved as
+# $LIBNAME.exports.check and $LIBNAME.sigatures.check). It then compares
+# the resulting files with the files $LIBNAME.exports and $LIBNME.signatures
+# which it expects to find in the current directory.
+#
+
+LANG=C; export LANG
+LC_ALL=C; export LC_ALL
+LC_COLLATE=C; export LC_COLLATE
+
+script=$0
+dir_name=$(dirname ${script})
+
+if test x"$1" = "x" ; then
+	echo "USAGE: ${script} libname header [header ...]"
+	exit 1
+fi
+
+libname="$1"
+shift
+
+if test x"$1" = "x" ; then
+	echo "USAGE: ${script} libname header [header ...]"
+	exit 1
+fi
+
+headers="$*"
+
+exports_file=${libname}.exports
+exports_file_check=${exports_file}.check
+signatures_file=${libname}.signatures
+signatures_file_check=${signatures_file}.check
+
+
+${dir_name}/mksyms.sh awk ${exports_file_check} ${headers} 2>&1 > /dev/null
+
+cat ${headers} | ${dir_name}/mksigs.pl > ${signatures_file_check} 2> /dev/null
+
+normalize_exports_file() {
+	filename=$1
+	cat ${filename} \
+	| sed -e 's/^[ \t]*//g' \
+	| sed -e 's/^$//g' \
+	| sed -e 's/^#.*$//g' \
+	| sort | uniq > ${filename}.sort
+}
+
+normalize_exports_file ${exports_file}
+normalize_exports_file ${exports_file_check}
+
+normalize_exports_file ${signatures_file}
+normalize_exports_file ${signatures_file_check}
+
+diff -u ${exports_file}.sort ${exports_file_check}.sort
+if test "x$?" != "x0" ; then
+	echo "WARNING: possible ABI change detected in exports!"
+else
+	echo "exports check: OK"
+fi
+
+diff -u ${signatures_file}.sort ${signatures_file_check}.sort
+if test "x$?" != "x0" ; then
+	echo "WARNING: possible ABI change detected in signatures!"
+else
+	echo "signatures check: OK"
+fi


Property changes on: branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks_gcc.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks_gcc.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks_gcc.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+make clean
+
+mkdir -p abi/common
+mkdir -p abi/tools
+ABI_CHECKS="-aux-info abi/\$@.X"
+make ABI_CHECK="$ABI_CHECKS" CC="/usr/bin/gcc"
+
+for i in abi/*/*.X; do cat $i | grep 'tdb\.h'; done | sort | uniq | awk -F "extern " '{ print $2 }' | sort > abi/signatures
+grep '^extern' include/tdb.h | grep -v '"C"' | sort | uniq | awk -F "extern " '{ print $2 }' >> abi/signatures
+
+cat > abi/exports << EOF
+{
+    global:
+EOF
+#Functions
+cat abi/signatures | grep "(" | awk -F '(' '{ print $1 }' | awk -F ' ' '{ print "           "$NF";" }' | tr -d '*' | sort >> abi/exports
+#global vars
+cat abi/signatures | grep -v "(" | awk -F ';' '{print $1 }' | awk -F ' ' '{ print "           "$NF";" }' | tr -d '*' | sort >> abi/exports
+cat >> abi/exports << EOF
+
+    local: *;
+};
+EOF
+
+diff -u tdb.signatures abi/signatures
+if [ "$?" != "0" ]; then
+    echo "WARNING: Possible ABI Change!!"
+fi
+
+diff -u tdb.exports abi/exports
+if [ "$?" != "0" ]; then
+    echo "WARNING: Export file may be outdated!!"
+fi


Property changes on: branches/ctdb/squeeze-backports/lib/tdb/script/abi_checks_gcc.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tdb/script/mksigs.pl
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/script/mksigs.pl	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/script/mksigs.pl	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,183 @@
+#!/usr/bin/perl
+
+# mksigs.pl - extract signatures from C headers
+#
+# Copyright (C) Michael Adam 2009
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, see <http://www.gnu.org/licenses/>.
+
+# USAGE:  cat $header_files | mksigs.pl > $signature_file
+#
+# The header files to parse are read from stdin.
+# The output is in a form as produced by gcc with the -aux-info switch
+# and printed to stdout.
+
+use strict;
+use warnings;
+
+my $in_comment = 0;
+my $extern_C_block = 0;
+
+while (my $LINE = <>) {
+	# find end of started multi-line-comment
+	if ($in_comment) {
+		if ($LINE =~ /^.*?\*\/(.*)$/) {
+			$LINE = $1;
+			$in_comment = 0;
+		} else {
+			# whole line within comment
+			next;
+		}
+	}
+
+	# strip C++-style comments
+	$LINE =~ s/^(.*?)\/\/.*$/$1/;
+
+	# strip in-line-comments:
+	while ($LINE =~ /\/\*.*?\*\//) {
+		$LINE =~ s/\/\*.*?\*\///;
+	}
+
+	# find starts of multi-line-comments
+	if ($LINE =~ /^(.*)\/\*/) {
+		$in_comment = 1;
+		$LINE = $1;
+	}
+
+	# skip empty lines
+	next if $LINE =~ /^\s*$/;
+
+	# remove leading spaces
+	$LINE =~ s/^\s*(.*)$/$1/;
+
+	# concatenate lines split with "\" (usually macro defines)
+	while ($LINE =~ /^(.*?)\s+\\$/) {
+		my $LINE2 = <>;
+		$LINE = $1;
+		$LINE2 =~ s/^\s*(.*)$/$1/;
+		$LINE .= " " . $LINE2;
+	}
+
+	# remove all preprocessor directives
+	next if ($LINE =~ /^#/);
+
+	if ($LINE =~ /^extern\s+"C"\s+\{/) {
+		$extern_C_block = 1;
+		next;
+	}
+
+	if (($LINE =~ /^[^\{]*\}/) and $extern_C_block) {
+		$extern_C_block = 0;
+		next;
+	}
+
+	$LINE =~ s/^extern\s//;
+
+	# concatenate braces stretched over multiple lines
+	# (from structs or enums)
+	my $REST = $LINE;
+	my $braces = 0;
+	while (($REST =~ /[\{\}]/) or ($braces)) {
+		while ($REST =~ /[\{\}]/) {
+			# collect opening
+			while ($REST =~ /^[^\{\}]*\{(.*)$/) {
+				$braces++;
+				$REST = $1;
+			}
+
+			# collect closing
+			while ($REST =~ /^[^\{\}]*\}(.*)$/) {
+				$braces--;
+				$REST = $1;
+			}
+		}
+
+		# concatenate if not balanced
+		if ($braces) {
+			if (my $LINE2 = <>) {
+				$LINE2 =~ s/^\s*(.*)$/$1/;
+				chomp($LINE);
+				$LINE .= " " . $LINE2;
+				chomp $REST;
+				$REST .= " " . $LINE2;
+			} else {
+				print "ERROR: unbalanced braces ($braces)\n";
+				last;
+			}
+		}
+	}
+
+	# concetenate function prototypes that stretch over multiple lines
+	$REST = $LINE;
+	my $parenthesis = 0;
+	while (($REST =~ /[\(\)]/) or ($parenthesis)) {
+		while ($REST =~ /[\(\)]/) {
+			# collect opening
+			while ($REST =~ /^[^\(\)]*\((.*)$/) {
+				$parenthesis++;
+				$REST = $1;
+			}
+
+			# collect closing
+			while ($REST =~ /^[^\(\)]*\)(.*)$/) {
+				$parenthesis--;
+				$REST = $1;
+			}
+		}
+
+		# concatenate if not balanced
+		if ($parenthesis) {
+			if (my $LINE2 = <>) {
+				$LINE2 =~ s/^\s*(.*)$/$1/;
+				chomp($LINE);
+				$LINE .= " " . $LINE2;
+				chomp($REST);
+				$REST .= " " . $LINE2;
+			} else {
+				print "ERROR: unbalanced parantheses ($parenthesis)\n";
+				last;
+			}
+		}
+	}
+
+	next if ($LINE =~ /^typedef\s/);
+	next if ($LINE =~ /^enum\s+[^\{\(]+\s+\{/);
+	next if ($LINE =~ /^struct\s+[^\{\(]+\s+\{.*\}\s*;/);
+	next if ($LINE =~ /^struct\s+[a-zA-Z0-9_]+\s*;/);
+
+	# remove trailing spaces
+	$LINE =~ s/(.*?)\s*$/$1/;
+
+	$LINE =~ s/^(.*\))\s+PRINTF_ATTRIBUTE\([^\)]*\)(\s*[;,])/$1$2/;
+	$LINE =~ s/^(.*\))\s*[a-zA-Z0-9_]+\s*;$/$1;/;
+
+	# remove parameter names - slightly too coarse probably
+	$LINE =~ s/([\s\(]\*?)[_0-9a-zA-Z]+\s*([,\)])/$1$2/g;
+
+	# remedy (void) from last line
+	$LINE =~ s/\(\)/(void)/g;
+
+	# normalize spaces
+	$LINE =~ s/\s*\)\s*/)/g;
+	$LINE =~ s/\s*\(\s*/ (/g;
+	$LINE =~ s/\s*,\s*/, /g;
+
+	# normalize unsigned
+	$LINE =~ s/([\s,\(])unsigned([,\)])/$1unsigned int$2/g;
+
+	# normalize bool
+	$LINE =~ s/(\b)bool(\b)/_Bool/g;
+
+	print $LINE . "\n";
+}


Property changes on: branches/ctdb/squeeze-backports/lib/tdb/script/mksigs.pl
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.awk
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.awk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.awk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,76 @@
+#
+# mksyms.awk
+#
+# Extract symbols to export from C-header files.
+# output in version-script format for linking shared libraries.
+#
+# Copyright (C) 2008 Micheal Adam <obnox at samba.org>
+#
+BEGIN {
+	inheader=0;
+	current_file="";
+	print "#"
+	print "# This file is automatically generated with \"make symbols\". DO NOT EDIT "
+	print "#"
+	print "{"
+	print "\tglobal:"
+}
+
+END {
+	print""
+	print "\tlocal: *;"
+	print "};"
+}
+
+{
+	if (FILENAME!=current_file) {
+		print "\t\t# The following definitions come from",FILENAME
+		current_file=FILENAME
+	}
+	if (inheader) {
+		if (match($0,"[)][^()]*[;][ \t]*$")) {
+			inheader = 0;
+		}
+		next;
+	}
+}
+
+/^static/ || /^[ \t]*typedef/ || !/^[a-zA-Z\_]/ {
+	next;
+}
+
+/^extern[ \t]+[^()]+[;][ \t]*$/ {
+	gsub(/[^ \t]+[ \t]+/, "");
+	sub(/[;][ \t]*$/, "");
+	printf "\t\t%s;\n", $0;
+	next;
+}
+
+# look for function headers:
+{
+	gotstart = 0;
+	if ($0 ~ /^[A-Za-z_][A-Za-z0-9_]+/) {
+	gotstart = 1;
+	}
+	if(!gotstart) {
+		next;
+	}
+}
+
+/[_A-Za-z0-9]+[ \t]*[(].*[)][^()]*;[ \t]*$/ {
+	sub(/[(].*$/, "");
+	gsub(/[^ \t]+[ \t]+/, "");
+	gsub(/^[*]+/, "");
+	printf "\t\t%s;\n",$0;
+	next;
+}
+
+/[_A-Za-z0-9]+[ \t]*[(]/ {
+	inheader=1;
+	sub(/[(].*$/, "");
+	gsub(/[^ \t]+[ \t]+/, "");
+	gsub(/^[*]/, "");
+	printf "\t\t%s;\n",$0;
+	next;
+}
+

Added: branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,45 @@
+#! /bin/sh
+
+#
+# mksyms.sh
+#
+# Extract symbols to export from C-header files.
+# output in version-script format for linking shared libraries.
+#
+# This is the shell wrapper for the mksyms.awk core script.
+#
+# Copyright (C) 2008 Micheal Adam <obnox at samba.org>
+#
+
+LANG=C; export LANG
+LC_ALL=C; export LC_ALL
+LC_COLLATE=C; export LC_COLLATE
+
+if [ $# -lt 2 ]
+then
+  echo "Usage: $0 awk output_file header_files"
+  exit 1
+fi
+
+awk="$1"
+shift
+
+symsfile="$1"
+shift
+symsfile_tmp="$symsfile.$$.tmp~"
+
+proto_src="`echo $@ | tr ' ' '\n' | sort | uniq `"
+
+echo creating $symsfile
+
+mkdir -p `dirname $symsfile`
+
+${awk} -f `dirname $0`/mksyms.awk $proto_src > $symsfile_tmp
+
+if cmp -s $symsfile $symsfile_tmp 2>/dev/null
+then
+  echo "$symsfile unchanged"
+  rm $symsfile_tmp
+else
+  mv $symsfile_tmp $symsfile
+fi


Property changes on: branches/ctdb/squeeze-backports/lib/tdb/script/mksyms.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tdb/script/release-script.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/script/release-script.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/script/release-script.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+LNAME=tdb
+LINCLUDE=include/tdb.h
+
+if [ "$1" = "" ]; then
+    echo "Please provide version string, eg: 1.2.0"
+    exit 1
+fi
+
+if [ ! -d "lib/${LNAME}" ]; then
+    echo "Run this script from the samba base directory."
+    exit 1
+fi
+
+curbranch=`git branch |grep "^*" | tr -d "* "`
+
+version=$1
+strver=`echo ${version} | tr "." "-"`
+
+# Checkout the release tag
+git branch -f ${LNAME}-release-script-${strver} ${LNAME}-${strver}
+if [ ! "$?" = "0" ];  then
+    echo "Unable to checkout ${LNAME}-${strver} release"
+    exit 1
+fi
+
+function cleanquit {
+    #Clean up
+    git checkout $curbranch
+    git branch -d ${LNAME}-release-script-${strver}
+    exit $1
+}
+
+# NOTE: use cleanquit after this point
+git checkout ${LNAME}-release-script-${strver}
+
+# Test configure agrees with us
+confver=`grep "^AC_INIT" lib/${LNAME}/configure.ac | tr -d "AC_INIT(${LNAME}, " | tr -d ")"`
+if [ ! "$confver" = "$version" ]; then
+    echo "Wrong version, requested release for ${version}, found ${confver}"
+    exit 1
+fi
+
+# Check exports and signatures are up to date
+pushd lib/${LNAME}
+./script/abi_checks.sh ${LNAME} ${LINCLUDE}
+abicheck=$?
+popd
+if [ ! "$abicheck" = "0" ]; then
+    echo "ERROR: ABI Checks produced warnings!"
+    cleanquit 1
+fi
+
+git clean -f -x -d lib/${LNAME}
+git clean -f -x -d lib/replace
+
+# Now build tarball
+cp -a lib/${LNAME} ${LNAME}-${version}
+cp -a lib/replace ${LNAME}-${version}/libreplace
+pushd ${LNAME}-${version}
+./autogen.sh
+popd
+tar cvzf ${LNAME}-${version}.tar.gz ${LNAME}-${version}
+rm -fr ${LNAME}-${version}
+
+cleanquit 0

Added: branches/ctdb/squeeze-backports/lib/tdb/tdb.exports
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tdb.exports	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tdb.exports	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,65 @@
+{
+    global:
+           tdb_add_flags;
+           tdb_append;
+           tdb_chainlock;
+           tdb_chainlock_mark;
+           tdb_chainlock_nonblock;
+           tdb_chainlock_read;
+           tdb_chainlock_unmark;
+           tdb_chainunlock;
+           tdb_chainunlock_read;
+           tdb_check;
+           tdb_close;
+           tdb_delete;
+           tdb_dump_all;
+           tdb_enable_seqnum;
+           tdb_error;
+           tdb_errorstr;
+           tdb_exists;
+           tdb_fd;
+           tdb_fetch;
+           tdb_firstkey;
+           tdb_freelist_size;
+           tdb_get_flags;
+           tdb_get_logging_private;
+           tdb_get_seqnum;
+           tdb_hash_size;
+           tdb_increment_seqnum_nonblock;
+           tdb_lockall;
+           tdb_lockall_mark;
+           tdb_lockall_nonblock;
+           tdb_lockall_read;
+           tdb_lockall_read_nonblock;
+           tdb_lockall_unmark;
+           tdb_log_fn;
+           tdb_map_size;
+           tdb_name;
+           tdb_nextkey;
+           tdb_open;
+           tdb_open_ex;
+           tdb_parse_record;
+           tdb_printfreelist;
+           tdb_remove_flags;
+           tdb_reopen;
+           tdb_reopen_all;
+           tdb_repack;
+           tdb_setalarm_sigptr;
+           tdb_set_logging_function;
+           tdb_set_max_dead;
+           tdb_store;
+           tdb_transaction_cancel;
+           tdb_transaction_commit;
+           tdb_transaction_prepare_commit;
+           tdb_transaction_start;
+           tdb_transaction_start_nonblock;
+           tdb_traverse;
+           tdb_traverse_read;
+           tdb_unlockall;
+           tdb_unlockall_read;
+           tdb_validate_freelist;
+           tdb_wipe_all;
+           tdb_null;
+
+    local: *;
+};

Added: branches/ctdb/squeeze-backports/lib/tdb/tdb.mk
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tdb.mk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tdb.mk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,92 @@
+dirs::
+	@mkdir -p bin common tools
+
+PROGS = bin/tdbtool$(EXEEXT) bin/tdbrestore$(EXEEXT) bin/tdbdump$(EXEEXT) bin/tdbbackup$(EXEEXT)
+PROGS_NOINSTALL = bin/tdbtest$(EXEEXT) bin/tdbtorture$(EXEEXT)
+ALL_PROGS = $(PROGS) $(PROGS_NOINSTALL)
+
+TDB_SONAME = libtdb.$(SHLIBEXT).1
+TDB_SOLIB = libtdb.$(SHLIBEXT).$(PACKAGE_VERSION)
+TDB_STLIB = libtdb.a
+
+TDB_LIB = $(TDB_STLIB) 
+
+bin/tdbtest$(EXEEXT): tools/tdbtest.o $(TDB_LIB)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbtest tools/tdbtest.o -L. -ltdb -lgdbm
+
+bin/tdbtool$(EXEEXT): tools/tdbtool.o $(TDB_LIB)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbtool tools/tdbtool.o -L. -ltdb
+
+bin/tdbtorture$(EXEEXT): tools/tdbtorture.o $(TDB_LIB)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbtorture tools/tdbtorture.o -L. -ltdb
+
+bin/tdbdump$(EXEEXT): tools/tdbdump.o $(TDB_LIB)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbdump tools/tdbdump.o -L. -ltdb
+
+bin/tdbrestore$(EXEEXT): tools/tdbrestore.o $(TDB_LIB)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbrestore tools/tdbrestore.o -L. -ltdb $(TDB_DEPS)
+
+bin/tdbbackup$(EXEEXT): tools/tdbbackup.o $(TDB_LIB)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o bin/tdbbackup tools/tdbbackup.o -L. -ltdb
+
+test:: abi_checks
+
+test:: bin/tdbtorture$(EXEEXT) $(TDB_SONAME)
+	$(LIB_PATH_VAR)=. bin/tdbtorture$(EXEEXT)
+
+abi_checks::
+	@echo ABI checks:
+	@./script/abi_checks.sh tdb include/tdb.h
+
+clean:: 
+	rm -f test.db test.tdb torture.tdb test.gdbm
+	rm -f $(TDB_SONAME) $(TDB_SOLIB) $(TDB_STLIB) libtdb.$(SHLIBEXT)
+	rm -f $(ALL_PROGS) tdb.pc
+	rm -f tdb.exports.sort tdb.exports.check tdb.exports.check.sort
+	rm -f tdb.signatures.sort tdb.signatures.check tdb.signatures.check.sort
+
+build-python:: tdb.$(SHLIBEXT) 
+
+pytdb.o: $(tdbdir)/pytdb.c
+	$(CC) $(PICFLAG) -c $(tdbdir)/pytdb.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags`
+
+tdb.$(SHLIBEXT): libtdb.$(SHLIBEXT) pytdb.o
+	$(SHLD) $(SHLD_FLAGS) -o $@ pytdb.o -L. -ltdb `$(PYTHON_CONFIG) --ldflags`
+
+install:: installdirs installbin installheaders installlibs \
+		  $(PYTHON_INSTALL_TARGET)
+
+install-python:: build-python
+	mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"`
+	cp tdb.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"`
+
+check-python:: build-python $(TDB_SONAME)
+	$(LIB_PATH_VAR)=. PYTHONPATH=".:$(tdbdir)" $(PYTHON) $(tdbdir)/python/tests/simple.py
+
+clean::
+	rm -f tdb.$(SHLIBEXT)
+
+installdirs::
+	mkdir -p $(DESTDIR)$(bindir)
+	mkdir -p $(DESTDIR)$(includedir)
+	mkdir -p $(DESTDIR)$(libdir) 
+	mkdir -p $(DESTDIR)$(libdir)/pkgconfig
+
+installbin:: all installdirs
+	cp $(PROGS) $(DESTDIR)$(bindir)
+
+installheaders:: installdirs
+	cp $(srcdir)/include/tdb.h $(DESTDIR)$(includedir)
+
+installlibs:: all installdirs
+	cp tdb.pc $(DESTDIR)$(libdir)/pkgconfig
+	cp $(TDB_STLIB) $(TDB_SOLIB) $(DESTDIR)$(libdir)
+
+$(TDB_STLIB): $(TDB_OBJ)
+	ar -rv $(TDB_STLIB) $(TDB_OBJ)
+
+libtdb.$(SHLIBEXT): $(TDB_SOLIB)
+	ln -fs $< $@
+
+$(TDB_SONAME): $(TDB_SOLIB)
+	ln -fs $< $@

Added: branches/ctdb/squeeze-backports/lib/tdb/tdb.pc.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tdb.pc.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tdb.pc.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: tdb
+Description: A trivial database
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -ltdb
+Cflags: -I${includedir} 
+URL: http://tdb.samba.org/

Added: branches/ctdb/squeeze-backports/lib/tdb/tdb.signatures
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tdb.signatures	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tdb.signatures	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,61 @@
+const char *tdb_errorstr (struct tdb_context *);
+const char *tdb_name (struct tdb_context *);
+enum TDB_ERROR tdb_error (struct tdb_context *);
+int tdb_append (struct tdb_context *, TDB_DATA, TDB_DATA);
+int tdb_chainlock_mark (struct tdb_context *, TDB_DATA);
+int tdb_chainlock_nonblock (struct tdb_context *, TDB_DATA);
+int tdb_chainlock_read (struct tdb_context *, TDB_DATA);
+int tdb_chainlock (struct tdb_context *, TDB_DATA);
+int tdb_chainlock_unmark (struct tdb_context *, TDB_DATA);
+int tdb_chainunlock_read (struct tdb_context *, TDB_DATA);
+int tdb_chainunlock (struct tdb_context *, TDB_DATA);
+int tdb_close (struct tdb_context *);
+int tdb_delete (struct tdb_context *, TDB_DATA);
+int tdb_exists (struct tdb_context *, TDB_DATA);
+int tdb_fd (struct tdb_context *);
+int tdb_freelist_size (struct tdb_context *);
+int tdb_get_flags (struct tdb_context *);
+int tdb_get_seqnum (struct tdb_context *);
+int tdb_hash_size (struct tdb_context *);
+int tdb_lockall_mark (struct tdb_context *);
+int tdb_lockall_nonblock (struct tdb_context *);
+int tdb_lockall_read_nonblock (struct tdb_context *);
+int tdb_lockall_read (struct tdb_context *);
+int tdb_lockall (struct tdb_context *);
+int tdb_lockall_unmark (struct tdb_context *);
+int tdb_parse_record (struct tdb_context *, TDB_DATA, int (*) (TDB_DATA, TDB_DATA, void *), void *);
+int tdb_printfreelist (struct tdb_context *);
+int tdb_reopen_all (int);
+int tdb_reopen (struct tdb_context *);
+int tdb_repack (struct tdb_context *);
+int tdb_store (struct tdb_context *, TDB_DATA, TDB_DATA, int);
+int tdb_transaction_cancel (struct tdb_context *);
+int tdb_transaction_commit (struct tdb_context *);
+int tdb_transaction_prepare_commit (struct tdb_context *);
+int tdb_transaction_recover (struct tdb_context *);
+int tdb_transaction_start (struct tdb_context *);
+int tdb_transaction_start_nonblock (struct tdb_context *);
+int tdb_traverse_read (struct tdb_context *, tdb_traverse_func, void *);
+int tdb_traverse (struct tdb_context *, tdb_traverse_func, void *);
+int tdb_unlockall_read (struct tdb_context *);
+int tdb_unlockall (struct tdb_context *);
+int tdb_validate_freelist (struct tdb_context *, int *);
+int tdb_wipe_all (struct tdb_context *);
+size_t tdb_map_size (struct tdb_context *);
+struct tdb_context *tdb_open (const char *, int, int, int, mode_t);
+struct tdb_context *tdb_open_ex (const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func);
+TDB_DATA tdb_fetch (struct tdb_context *, TDB_DATA);
+TDB_DATA tdb_firstkey (struct tdb_context *);
+TDB_DATA tdb_nextkey (struct tdb_context *, TDB_DATA);
+tdb_log_func tdb_log_fn (struct tdb_context *);
+void tdb_add_flags (struct tdb_context *, unsigned int);
+void tdb_dump_all (struct tdb_context *);
+void tdb_enable_seqnum (struct tdb_context *);
+void *tdb_get_logging_private (struct tdb_context *);
+void tdb_increment_seqnum_nonblock (struct tdb_context *);
+void tdb_remove_flags (struct tdb_context *, unsigned int);
+void tdb_setalarm_sigptr (struct tdb_context *, volatile sig_atomic_t *);
+void tdb_set_logging_function (struct tdb_context *, const struct tdb_logging_context *);
+void tdb_set_max_dead (struct tdb_context *, int);
+int tdb_check (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *);
+TDB_DATA tdb_null;

Added: branches/ctdb/squeeze-backports/lib/tdb/tools/tdbbackup.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tools/tdbbackup.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tools/tdbbackup.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,337 @@
+/* 
+   Unix SMB/CIFS implementation.
+   low level tdb backup and restore utility
+   Copyright (C) Andrew Tridgell              2002
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+
+  This program is meant for backup/restore of tdb databases. Typical usage would be:
+     tdbbackup *.tdb
+  when Samba shuts down cleanly, which will make a backup of all the local databases
+  to *.bak files. Then on Samba startup you would use:
+     tdbbackup -v *.tdb
+  and this will check the databases for corruption and if corruption is detected then
+  the backup will be restored.
+
+  You may also like to do a backup on a regular basis while Samba is
+  running, perhaps using cron.
+
+  The reason this program is needed is to cope with power failures
+  while Samba is running. A power failure could lead to database
+  corruption and Samba will then not start correctly.
+
+  Note that many of the databases in Samba are transient and thus
+  don't need to be backed up, so you can optimise the above a little
+  by only running the backup on the critical databases.
+
+ */
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+static int failed;
+
+static struct tdb_logging_context log_ctx;
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+	va_list ap;
+    
+	va_start(ap, format);
+	vfprintf(stdout, format, ap);
+	va_end(ap);
+	fflush(stdout);
+}
+
+static char *add_suffix(const char *name, const char *suffix)
+{
+	char *ret;
+	int len = strlen(name) + strlen(suffix) + 1;
+	ret = (char *)malloc(len);
+	if (!ret) {
+		fprintf(stderr,"Out of memory!\n");
+		exit(1);
+	}
+	snprintf(ret, len, "%s%s", name, suffix);
+	return ret;
+}
+
+static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+	TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
+
+	if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
+		fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb_new));
+		failed = 1;
+		return 1;
+	}
+	return 0;
+}
+
+
+static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+	return 0;
+}
+
+/*
+  carefully backup a tdb, validating the contents and
+  only doing the backup if its OK
+  this function is also used for restore
+*/
+static int backup_tdb(const char *old_name, const char *new_name, int hash_size)
+{
+	TDB_CONTEXT *tdb;
+	TDB_CONTEXT *tdb_new;
+	char *tmp_name;
+	struct stat st;
+	int count1, count2;
+
+	tmp_name = add_suffix(new_name, ".tmp");
+
+	/* stat the old tdb to find its permissions */
+	if (stat(old_name, &st) != 0) {
+		perror(old_name);
+		free(tmp_name);
+		return 1;
+	}
+
+	/* open the old tdb */
+	tdb = tdb_open_ex(old_name, 0, 0, 
+			  O_RDWR, 0, &log_ctx, NULL);
+	if (!tdb) {
+		printf("Failed to open %s\n", old_name);
+		free(tmp_name);
+		return 1;
+	}
+
+	/* create the new tdb */
+	unlink(tmp_name);
+	tdb_new = tdb_open_ex(tmp_name, 
+			      hash_size ? hash_size : tdb_hash_size(tdb), 
+			      TDB_DEFAULT, 
+			      O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777, 
+			      &log_ctx, NULL);
+	if (!tdb_new) {
+		perror(tmp_name);
+		free(tmp_name);
+		return 1;
+	}
+
+	if (tdb_transaction_start(tdb) != 0) {
+		printf("Failed to start transaction on old tdb\n");
+		tdb_close(tdb);
+		tdb_close(tdb_new);
+		unlink(tmp_name);
+		free(tmp_name);
+		return 1;
+	}
+
+	if (tdb_transaction_start(tdb_new) != 0) {
+		printf("Failed to start transaction on new tdb\n");
+		tdb_close(tdb);
+		tdb_close(tdb_new);
+		unlink(tmp_name);
+		free(tmp_name);
+		return 1;
+	}
+
+	failed = 0;
+
+	/* traverse and copy */
+	count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
+	if (count1 < 0 || failed) {
+		fprintf(stderr,"failed to copy %s\n", old_name);
+		tdb_close(tdb);
+		tdb_close(tdb_new);
+		unlink(tmp_name);
+		free(tmp_name);
+		return 1;
+	}
+
+	/* close the old tdb */
+	tdb_close(tdb);
+
+	if (tdb_transaction_commit(tdb_new) != 0) {
+		fprintf(stderr, "Failed to commit new tdb\n");
+		tdb_close(tdb_new);
+		unlink(tmp_name);
+		free(tmp_name);		
+		return 1;
+	}
+
+	/* close the new tdb and re-open read-only */
+	tdb_close(tdb_new);
+	tdb_new = tdb_open_ex(tmp_name, 
+			      0,
+			      TDB_DEFAULT, 
+			      O_RDONLY, 0,
+			      &log_ctx, NULL);
+	if (!tdb_new) {
+		fprintf(stderr,"failed to reopen %s\n", tmp_name);
+		unlink(tmp_name);
+		perror(tmp_name);
+		free(tmp_name);
+		return 1;
+	}
+	
+	/* traverse the new tdb to confirm */
+	count2 = tdb_traverse(tdb_new, test_fn, NULL);
+	if (count2 != count1) {
+		fprintf(stderr,"failed to copy %s\n", old_name);
+		tdb_close(tdb_new);
+		unlink(tmp_name);
+		free(tmp_name);
+		return 1;
+	}
+
+	/* close the new tdb and rename it to .bak */
+	tdb_close(tdb_new);
+	if (rename(tmp_name, new_name) != 0) {
+		perror(new_name);
+		free(tmp_name);
+		return 1;
+	}
+
+	free(tmp_name);
+
+	return 0;
+}
+
+/*
+  verify a tdb and if it is corrupt then restore from *.bak
+*/
+static int verify_tdb(const char *fname, const char *bak_name)
+{
+	TDB_CONTEXT *tdb;
+	int count = -1;
+
+	/* open the tdb */
+	tdb = tdb_open_ex(fname, 0, 0, 
+			  O_RDONLY, 0, &log_ctx, NULL);
+
+	/* traverse the tdb, then close it */
+	if (tdb) {
+		count = tdb_traverse(tdb, test_fn, NULL);
+		tdb_close(tdb);
+	}
+
+	/* count is < 0 means an error */
+	if (count < 0) {
+		printf("restoring %s\n", fname);
+		return backup_tdb(bak_name, fname, 0);
+	}
+
+	printf("%s : %d records\n", fname, count);
+
+	return 0;
+}
+
+/*
+  see if one file is newer than another
+*/
+static int file_newer(const char *fname1, const char *fname2)
+{
+	struct stat st1, st2;
+	if (stat(fname1, &st1) != 0) {
+		return 0;
+	}
+	if (stat(fname2, &st2) != 0) {
+		return 1;
+	}
+	return (st1.st_mtime > st2.st_mtime);
+}
+
+static void usage(void)
+{
+	printf("Usage: tdbbackup [options] <fname...>\n\n");
+	printf("   -h            this help message\n");
+	printf("   -s suffix     set the backup suffix\n");
+	printf("   -v            verify mode (restore if corrupt)\n");
+	printf("   -n hashsize   set the new hash size for the backup\n");
+}
+		
+
+ int main(int argc, char *argv[])
+{
+	int i;
+	int ret = 0;
+	int c;
+	int verify = 0;
+	int hashsize = 0;
+	const char *suffix = ".bak";
+
+	log_ctx.log_fn = tdb_log;
+
+	while ((c = getopt(argc, argv, "vhs:n:")) != -1) {
+		switch (c) {
+		case 'h':
+			usage();
+			exit(0);
+		case 'v':
+			verify = 1;
+			break;
+		case 's':
+			suffix = optarg;
+			break;
+		case 'n':
+			hashsize = atoi(optarg);
+			break;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1) {
+		usage();
+		exit(1);
+	}
+
+	for (i=0; i<argc; i++) {
+		const char *fname = argv[i];
+		char *bak_name;
+
+		bak_name = add_suffix(fname, suffix);
+
+		if (verify) {
+			if (verify_tdb(fname, bak_name) != 0) {
+				ret = 1;
+			}
+		} else {
+			if (file_newer(fname, bak_name) &&
+			    backup_tdb(fname, bak_name, hashsize) != 0) {
+				ret = 1;
+			}
+		}
+
+		free(bak_name);
+	}
+
+	return ret;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/tools/tdbdump.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tools/tdbdump.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tools/tdbdump.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,116 @@
+/* 
+   Unix SMB/CIFS implementation.
+   simple tdb dump util
+   Copyright (C) Andrew Tridgell              2001
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+static void print_data(TDB_DATA d)
+{
+	unsigned char *p = (unsigned char *)d.dptr;
+	int len = d.dsize;
+	while (len--) {
+		if (isprint(*p) && !strchr("\"\\", *p)) {
+			fputc(*p, stdout);
+		} else {
+			printf("\\%02X", *p);
+		}
+		p++;
+	}
+}
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+	printf("{\n");
+	printf("key(%d) = \"", (int)key.dsize);
+	print_data(key);
+	printf("\"\n");
+	printf("data(%d) = \"", (int)dbuf.dsize);
+	print_data(dbuf);
+	printf("\"\n");
+	printf("}\n");
+	return 0;
+}
+
+static int dump_tdb(const char *fname, const char *keyname)
+{
+	TDB_CONTEXT *tdb;
+	TDB_DATA key, value;
+	
+	tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
+	if (!tdb) {
+		printf("Failed to open %s\n", fname);
+		return 1;
+	}
+
+	if (!keyname) {
+		tdb_traverse(tdb, traverse_fn, NULL);
+	} else {
+		key.dptr = discard_const_p(uint8_t, keyname);
+		key.dsize = strlen(keyname);
+		value = tdb_fetch(tdb, key);
+		if (!value.dptr) {
+			return 1;
+		} else {
+			print_data(value);
+			free(value.dptr);
+		}
+	}
+
+	return 0;
+}
+
+static void usage( void)
+{
+	printf( "Usage: tdbdump [options] <filename>\n\n");
+	printf( "   -h          this help message\n");
+	printf( "   -k keyname  dumps value of keyname\n");
+}
+
+ int main(int argc, char *argv[])
+{
+	char *fname, *keyname=NULL;
+	int c;
+
+	if (argc < 2) {
+		printf("Usage: tdbdump <fname>\n");
+		exit(1);
+	}
+
+	while ((c = getopt( argc, argv, "hk:")) != -1) {
+		switch (c) {
+		case 'h':
+			usage();
+			exit( 0);
+		case 'k':
+			keyname = optarg;
+			break;
+		default:
+			usage();
+			exit( 1);
+		}
+	}
+
+	fname = argv[optind];
+
+	return dump_tdb(fname, keyname);
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/tools/tdbrestore.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tools/tdbrestore.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tools/tdbrestore.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,226 @@
+/*
+   tdbrestore -- construct a tdb from tdbdump output.
+   Copyright (C) Volker Lendecke		2010
+   Copyright (C) Simon McVittie			2005
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <assert.h>
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+#define debug_fprintf(file, fmt, ...) do {/*nothing*/} while (0)
+
+static int read_linehead(FILE *f)
+{
+	int i, c;
+	int num_bytes;
+	char prefix[128];
+
+	while (1) {
+		c = getc(f);
+		if (c == EOF) {
+			return -1;
+		}
+		if (c == '\(') {
+			break;
+		}
+	}
+	for (i=0; i<sizeof(prefix); i++) {
+		c = getc(f);
+		if (c == EOF) {
+			return -1;
+		}
+		prefix[i] = c;
+		if (c == '"') {
+			break;
+		}
+	}
+	if (i == sizeof(prefix)) {
+		return -1;
+	}
+	prefix[i] = '\0';
+
+	if (sscanf(prefix, "%d) = ", &num_bytes) != 1) {
+		return -1;
+	}
+	return num_bytes;
+}
+
+static int read_hex(void) {
+	int c;
+	c = getchar();
+	if (c == EOF) {
+		fprintf(stderr, "Unexpected EOF in data\n");
+		return -1;
+	} else if (c == '"') {
+		fprintf(stderr, "Unexpected \\\" sequence\n");
+		return -1;
+	} else if ('0' <= c && c <= '9')  {
+		return c - '0';
+	} else if ('A' <= c && c <= 'F')  {
+		return c - 'A' + 10;
+	} else if ('a' <= c && c <= 'f')  {
+		return c - 'a' + 10;
+	} else {
+		fprintf(stderr, "Invalid hex: %c\n", c);
+		return -1;
+	}
+}
+
+static int read_data(FILE *f, TDB_DATA *d, size_t size) {
+	int c, low, high;
+	int i;
+
+	d->dptr = (unsigned char *)malloc(size);
+	if (d->dptr == NULL) {
+		return -1;
+	}
+	d->dsize = size;
+
+	for (i=0; i<size; i++) {
+		c = getc(f);
+		if (c == EOF) {
+			fprintf(stderr, "Unexpected EOF in data\n");
+			return 1;
+		} else if (c == '"') {
+			return 0;
+		} else if (c == '\\') {
+			high = read_hex();
+			if (high < 0) {
+				return -1;
+			}
+			high = high << 4;
+			assert(high == (high & 0xf0));
+			low = read_hex();
+			if (low < 0) {
+				return -1;
+			}
+			assert(low == (low & 0x0f));
+			d->dptr[i] = (low|high);
+		} else {
+			d->dptr[i] = c;
+		}
+	}
+	return 0;
+}
+
+static int swallow(FILE *f, const char *s, int *eof)
+{
+	char line[128];
+
+	if (fgets(line, sizeof(line), f) == NULL) {
+		if (eof != NULL) {
+			*eof = 1;
+		}
+		return -1;
+	}
+	if (strcmp(line, s) != 0) {
+		return -1;
+	}
+	return 0;
+}
+
+static int read_rec(FILE *f, TDB_CONTEXT *tdb, int *eof)
+{
+	int length;
+	TDB_DATA key, data;
+	int ret = -1;
+
+	key.dptr = NULL;
+	data.dptr = NULL;
+
+	if (swallow(f, "{\n", eof) == -1) {
+		goto fail;
+	}
+	length = read_linehead(f);
+	if (length == -1) {
+		goto fail;
+	}
+	if (read_data(f, &key, length) == -1) {
+		goto fail;
+	}
+	if (swallow(f, "\"\n", NULL) == -1) {
+		goto fail;
+	}
+	length = read_linehead(f);
+	if (length == -1) {
+		goto fail;
+	}
+	if (read_data(f, &data, length) == -1) {
+		goto fail;
+	}
+	if ((swallow(f, "\"\n", NULL) == -1)
+	    || (swallow(f, "}\n", NULL) == -1)) {
+		goto fail;
+	}
+	if (tdb_store(tdb, key, data, TDB_INSERT) == -1) {
+		fprintf(stderr, "TDB error: %s\n", tdb_errorstr(tdb));
+		goto fail;
+	}
+
+	ret = 0;
+fail:
+	free(key.dptr);
+	free(data.dptr);
+	return ret;
+}
+
+static int restore_tdb(const char *fname)
+{
+	TDB_CONTEXT *tdb;
+
+	tdb = tdb_open(fname, 0, 0, O_RDWR|O_CREAT|O_EXCL, 0666);
+	if (!tdb) {
+		perror("tdb_open");
+		fprintf(stderr, "Failed to open %s\n", fname);
+		return 1;
+	}
+
+	while (1) {
+		int eof = 0;
+		if (read_rec(stdin, tdb, &eof) == -1) {
+			if (eof) {
+				break;
+			}
+			return 1;
+		}
+	}
+	if (tdb_close(tdb)) {
+		fprintf(stderr, "Error closing tdb\n");
+		return 1;
+	}
+	fprintf(stderr, "EOF\n");
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	char *fname;
+
+	if (argc < 2) {
+		printf("Usage: %s dbname < tdbdump_output\n", argv[0]);
+		exit(1);
+	}
+
+	fname = argv[1];
+
+	return restore_tdb(fname);
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtest.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtest.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtest.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,265 @@
+/* a test program for tdb - the trivial database */
+
+#include "replace.h"
+#include "tdb.h"
+#include "system/filesys.h"
+#include "system/time.h"
+
+#include <gdbm.h>
+
+
+#define DELETE_PROB 7
+#define STORE_PROB 5
+
+static struct tdb_context *db;
+static GDBM_FILE gdbm;
+
+struct timeval tp1,tp2;
+
+static void _start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double _end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return((tp2.tv_sec - tp1.tv_sec) + 
+	       (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+static void fatal(const char *why)
+{
+	perror(why);
+	exit(1);
+}
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...)
+{
+	va_list ap;
+    
+	va_start(ap, format);
+	vfprintf(stdout, format, ap);
+	va_end(ap);
+	fflush(stdout);
+}
+
+static void compare_db(void)
+{
+	TDB_DATA d, key, nextkey;
+	datum gd, gkey, gnextkey;
+
+	key = tdb_firstkey(db);
+	while (key.dptr) {
+		d = tdb_fetch(db, key);
+		gkey.dptr = key.dptr;
+		gkey.dsize = key.dsize;
+
+		gd = gdbm_fetch(gdbm, gkey);
+
+		if (!gd.dptr) fatal("key not in gdbm");
+		if (gd.dsize != d.dsize) fatal("data sizes differ");
+		if (memcmp(gd.dptr, d.dptr, d.dsize)) {
+			fatal("data differs");
+		}
+
+		nextkey = tdb_nextkey(db, key);
+		free(key.dptr);
+		free(d.dptr);
+		free(gd.dptr);
+		key = nextkey;
+	}
+
+	gkey = gdbm_firstkey(gdbm);
+	while (gkey.dptr) {
+		gd = gdbm_fetch(gdbm, gkey);
+		key.dptr = gkey.dptr;
+		key.dsize = gkey.dsize;
+
+		d = tdb_fetch(db, key);
+
+		if (!d.dptr) fatal("key not in db");
+		if (d.dsize != gd.dsize) fatal("data sizes differ");
+		if (memcmp(d.dptr, gd.dptr, gd.dsize)) {
+			fatal("data differs");
+		}
+
+		gnextkey = gdbm_nextkey(gdbm, gkey);
+		free(gkey.dptr);
+		free(gd.dptr);
+		free(d.dptr);
+		gkey = gnextkey;
+	}
+}
+
+static char *randbuf(int len)
+{
+	char *buf;
+	int i;
+	buf = (char *)malloc(len+1);
+
+	for (i=0;i<len;i++) {
+		buf[i] = 'a' + (rand() % 26);
+	}
+	buf[i] = 0;
+	return buf;
+}
+
+static void addrec_db(void)
+{
+	int klen, dlen;
+	char *k, *d;
+	TDB_DATA key, data;
+
+	klen = 1 + (rand() % 4);
+	dlen = 1 + (rand() % 100);
+
+	k = randbuf(klen);
+	d = randbuf(dlen);
+
+	key.dptr = k;
+	key.dsize = klen+1;
+
+	data.dptr = d;
+	data.dsize = dlen+1;
+
+	if (rand() % DELETE_PROB == 0) {
+		tdb_delete(db, key);
+	} else if (rand() % STORE_PROB == 0) {
+		if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+			fatal("tdb_store failed");
+		}
+	} else {
+		data = tdb_fetch(db, key);
+		if (data.dptr) free(data.dptr);
+	}
+
+	free(k);
+	free(d);
+}
+
+static void addrec_gdbm(void)
+{
+	int klen, dlen;
+	char *k, *d;
+	datum key, data;
+
+	klen = 1 + (rand() % 4);
+	dlen = 1 + (rand() % 100);
+
+	k = randbuf(klen);
+	d = randbuf(dlen);
+
+	key.dptr = k;
+	key.dsize = klen+1;
+
+	data.dptr = d;
+	data.dsize = dlen+1;
+
+	if (rand() % DELETE_PROB == 0) {
+		gdbm_delete(gdbm, key);
+	} else if (rand() % STORE_PROB == 0) {
+		if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) {
+			fatal("gdbm_store failed");
+		}
+	} else {
+		data = gdbm_fetch(gdbm, key);
+		if (data.dptr) free(data.dptr);
+	}
+
+	free(k);
+	free(d);
+}
+
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+#if 0
+	printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
+#endif
+	tdb_delete(tdb, key);
+	return 0;
+}
+
+static void merge_test(void)
+{
+	int i;
+	char keys[5][2];
+	char tdata[] = "test";
+	TDB_DATA key, data;
+	
+	for (i = 0; i < 5; i++) {
+		snprintf(keys[i],2, "%d", i);
+		key.dptr = keys[i];
+		key.dsize = 2;
+		
+		data.dptr = tdata;
+		data.dsize = 4;
+		
+		if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+			fatal("tdb_store failed");
+		}
+	}
+
+	key.dptr = keys[0];
+	tdb_delete(db, key);
+	key.dptr = keys[4];
+	tdb_delete(db, key);
+	key.dptr = keys[2];
+	tdb_delete(db, key);
+	key.dptr = keys[1];
+	tdb_delete(db, key);
+	key.dptr = keys[3];
+	tdb_delete(db, key);
+}
+
+ int main(int argc, const char *argv[])
+{
+	int i, seed=0;
+	int loops = 10000;
+	int num_entries;
+	char test_gdbm[] = "test.gdbm";
+
+	unlink("test.gdbm");
+
+	db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST, 
+		      O_RDWR | O_CREAT | O_TRUNC, 0600);
+	gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, 
+			 0600, NULL);
+
+	if (!db || !gdbm) {
+		fatal("db open failed");
+	}
+
+#if 1
+	srand(seed);
+	_start_timer();
+	for (i=0;i<loops;i++) addrec_gdbm();
+	printf("gdbm got %.2f ops/sec\n", i/_end_timer());
+#endif
+
+	merge_test();
+
+	srand(seed);
+	_start_timer();
+	for (i=0;i<loops;i++) addrec_db();
+	printf("tdb got %.2f ops/sec\n", i/_end_timer());
+
+	if (tdb_validate_freelist(db, &num_entries) == -1) {
+		printf("tdb freelist is corrupt\n");
+	} else {
+		printf("tdb freelist is good (%d entries)\n", num_entries);
+	}
+
+	compare_db();
+
+	printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
+	printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
+
+	tdb_close(db);
+	gdbm_close(gdbm);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtool.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtool.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtool.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,779 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Samba database functions
+   Copyright (C) Andrew Tridgell              1999-2000
+   Copyright (C) Paul `Rusty' Russell		   2000
+   Copyright (C) Jeremy Allison			   2000
+   Copyright (C) Andrew Esh                        2001
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+static int do_command(void);
+const char *cmdname;
+char *arg1, *arg2;
+size_t arg1len, arg2len;
+int bIterate = 0;
+char *line;
+TDB_DATA iterate_kbuf;
+char cmdline[1024];
+static int disable_mmap;
+
+enum commands {
+	CMD_CREATE_TDB,
+	CMD_OPEN_TDB,
+	CMD_TRANSACTION_START,
+	CMD_TRANSACTION_COMMIT,
+	CMD_TRANSACTION_CANCEL,
+	CMD_ERASE,
+	CMD_DUMP,
+	CMD_INSERT,
+	CMD_MOVE,
+	CMD_STORE,
+	CMD_SHOW,
+	CMD_KEYS,
+	CMD_HEXKEYS,
+	CMD_DELETE,
+	CMD_LIST_HASH_FREE,
+	CMD_LIST_FREE,
+	CMD_INFO,
+	CMD_MMAP,
+	CMD_SPEED,
+	CMD_FIRST,
+	CMD_NEXT,
+	CMD_SYSTEM,
+	CMD_CHECK,
+	CMD_QUIT,
+	CMD_HELP
+};
+
+typedef struct {
+	const char *name;
+	enum commands cmd;
+} COMMAND_TABLE;
+
+COMMAND_TABLE cmd_table[] = {
+	{"create",	CMD_CREATE_TDB},
+	{"open",	CMD_OPEN_TDB},
+	{"transaction_start",	CMD_TRANSACTION_START},
+	{"transaction_commit",	CMD_TRANSACTION_COMMIT},
+	{"transaction_cancel",	CMD_TRANSACTION_CANCEL},
+	{"erase",	CMD_ERASE},
+	{"dump",	CMD_DUMP},
+	{"insert",	CMD_INSERT},
+	{"move",	CMD_MOVE},
+	{"store",	CMD_STORE},
+	{"show",	CMD_SHOW},
+	{"keys",	CMD_KEYS},
+	{"hexkeys",	CMD_HEXKEYS},
+	{"delete",	CMD_DELETE},
+	{"list",	CMD_LIST_HASH_FREE},
+	{"free",	CMD_LIST_FREE},
+	{"info",	CMD_INFO},
+	{"speed",	CMD_SPEED},
+	{"mmap",	CMD_MMAP},
+	{"first",	CMD_FIRST},
+	{"1",		CMD_FIRST},
+	{"next",	CMD_NEXT},
+	{"n",		CMD_NEXT},
+	{"check",	CMD_CHECK},
+	{"quit",	CMD_QUIT},
+	{"q",		CMD_QUIT},
+	{"!",		CMD_SYSTEM},
+	{NULL,		CMD_HELP}
+};
+
+struct timeval tp1,tp2;
+
+static void _start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double _end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return((tp2.tv_sec - tp1.tv_sec) + 
+	       (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	vfprintf(stderr, format, ap);
+	va_end(ap);
+}
+
+/* a tdb tool for manipulating a tdb database */
+
+static TDB_CONTEXT *tdb;
+
+static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+
+static void print_asc(const char *buf,int len)
+{
+	int i;
+
+	/* We're probably printing ASCII strings so don't try to display
+	   the trailing NULL character. */
+
+	if (buf[len - 1] == 0)
+	        len--;
+
+	for (i=0;i<len;i++)
+		printf("%c",isprint(buf[i])?buf[i]:'.');
+}
+
+static void print_data(const char *buf,int len)
+{
+	int i=0;
+	if (len<=0) return;
+	printf("[%03X] ",i);
+	for (i=0;i<len;) {
+		printf("%02X ",(int)((unsigned char)buf[i]));
+		i++;
+		if (i%8 == 0) printf(" ");
+		if (i%16 == 0) {      
+			print_asc(&buf[i-16],8); printf(" ");
+			print_asc(&buf[i-8],8); printf("\n");
+			if (i<len) printf("[%03X] ",i);
+		}
+	}
+	if (i%16) {
+		int n;
+		
+		n = 16 - (i%16);
+		printf(" ");
+		if (n>8) printf(" ");
+		while (n--) printf("   ");
+		
+		n = i%16;
+		if (n > 8) n = 8;
+		print_asc(&buf[i-(i%16)],n); printf(" ");
+		n = (i%16) - n;
+		if (n>0) print_asc(&buf[i-n],n); 
+		printf("\n");    
+	}
+}
+
+static void help(void)
+{
+	printf("\n"
+"tdbtool: \n"
+"  create    dbname     : create a database\n"
+"  open      dbname     : open an existing database\n"
+"  transaction_start    : start a transaction\n"
+"  transaction_commit   : commit a transaction\n"
+"  transaction_cancel   : cancel a transaction\n"
+"  erase                : erase the database\n"
+"  dump                 : dump the database as strings\n"
+"  keys                 : dump the database keys as strings\n"
+"  hexkeys              : dump the database keys as hex values\n"
+"  info                 : print summary info about the database\n"
+"  insert    key  data  : insert a record\n"
+"  move      key  file  : move a record to a destination tdb\n"
+"  store     key  data  : store a record (replace)\n"
+"  show      key        : show a record by key\n"
+"  delete    key        : delete a record by key\n"
+"  list                 : print the database hash table and freelist\n"
+"  free                 : print the database freelist\n"
+"  check                : check the integrity of an opened database\n"
+"  speed                : perform speed tests on the database\n"
+"  ! command            : execute system command\n"
+"  1 | first            : print the first record\n"
+"  n | next             : print the next record\n"
+"  q | quit             : terminate\n"
+"  \\n                   : repeat 'next' command\n"
+"\n");
+}
+
+static void terror(const char *why)
+{
+	printf("%s\n", why);
+}
+
+static void create_tdb(const char *tdbname)
+{
+	struct tdb_logging_context log_ctx;
+	log_ctx.log_fn = tdb_log;
+
+	if (tdb) tdb_close(tdb);
+	tdb = tdb_open_ex(tdbname, 0, TDB_CLEAR_IF_FIRST | (disable_mmap?TDB_NOMMAP:0),
+			  O_RDWR | O_CREAT | O_TRUNC, 0600, &log_ctx, NULL);
+	if (!tdb) {
+		printf("Could not create %s: %s\n", tdbname, strerror(errno));
+	}
+}
+
+static void open_tdb(const char *tdbname)
+{
+	struct tdb_logging_context log_ctx;
+	log_ctx.log_fn = tdb_log;
+
+	if (tdb) tdb_close(tdb);
+	tdb = tdb_open_ex(tdbname, 0, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600,
+			  &log_ctx, NULL);
+	if (!tdb) {
+		printf("Could not open %s: %s\n", tdbname, strerror(errno));
+	}
+}
+
+static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+{
+	TDB_DATA key, dbuf;
+
+	if ((keyname == NULL) || (keylen == 0)) {
+		terror("need key");
+		return;
+	}
+
+	key.dptr = (unsigned char *)keyname;
+	key.dsize = keylen;
+	dbuf.dptr = (unsigned char *)data;
+	dbuf.dsize = datalen;
+
+	if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
+		terror("insert failed");
+	}
+}
+
+static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+{
+	TDB_DATA key, dbuf;
+
+	if ((keyname == NULL) || (keylen == 0)) {
+		terror("need key");
+		return;
+	}
+
+	if ((data == NULL) || (datalen == 0)) {
+		terror("need data");
+		return;
+	}
+
+	key.dptr = (unsigned char *)keyname;
+	key.dsize = keylen;
+	dbuf.dptr = (unsigned char *)data;
+	dbuf.dsize = datalen;
+
+	printf("Storing key:\n");
+	print_rec(tdb, key, dbuf, NULL);
+
+	if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
+		terror("store failed");
+	}
+}
+
+static void show_tdb(char *keyname, size_t keylen)
+{
+	TDB_DATA key, dbuf;
+
+	if ((keyname == NULL) || (keylen == 0)) {
+		terror("need key");
+		return;
+	}
+
+	key.dptr = (unsigned char *)keyname;
+	key.dsize = keylen;
+
+	dbuf = tdb_fetch(tdb, key);
+	if (!dbuf.dptr) {
+	    terror("fetch failed");
+	    return;
+	}
+	
+	print_rec(tdb, key, dbuf, NULL);
+	
+	free( dbuf.dptr );
+	
+	return;
+}
+
+static void delete_tdb(char *keyname, size_t keylen)
+{
+	TDB_DATA key;
+
+	if ((keyname == NULL) || (keylen == 0)) {
+		terror("need key");
+		return;
+	}
+
+	key.dptr = (unsigned char *)keyname;
+	key.dsize = keylen;
+
+	if (tdb_delete(tdb, key) != 0) {
+		terror("delete failed");
+	}
+}
+
+static void move_rec(char *keyname, size_t keylen, char* tdbname)
+{
+	TDB_DATA key, dbuf;
+	TDB_CONTEXT *dst_tdb;
+
+	if ((keyname == NULL) || (keylen == 0)) {
+		terror("need key");
+		return;
+	}
+
+	if ( !tdbname ) {
+		terror("need destination tdb name");
+		return;
+	}
+
+	key.dptr = (unsigned char *)keyname;
+	key.dsize = keylen;
+
+	dbuf = tdb_fetch(tdb, key);
+	if (!dbuf.dptr) {
+		terror("fetch failed");
+		return;
+	}
+	
+	print_rec(tdb, key, dbuf, NULL);
+	
+	dst_tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600);
+	if ( !dst_tdb ) {
+		terror("unable to open destination tdb");
+		return;
+	}
+	
+	if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) {
+		terror("failed to move record");
+	}
+	else
+		printf("record moved\n");
+	
+	tdb_close( dst_tdb );
+	
+	return;
+}
+
+static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+	printf("\nkey %d bytes\n", (int)key.dsize);
+	print_asc((const char *)key.dptr, key.dsize);
+	printf("\ndata %d bytes\n", (int)dbuf.dsize);
+	print_data((const char *)dbuf.dptr, dbuf.dsize);
+	return 0;
+}
+
+static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+	printf("key %d bytes: ", (int)key.dsize);
+	print_asc((const char *)key.dptr, key.dsize);
+	printf("\n");
+	return 0;
+}
+
+static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+	printf("key %d bytes\n", (int)key.dsize);
+	print_data((const char *)key.dptr, key.dsize);
+	printf("\n");
+	return 0;
+}
+
+static int total_bytes;
+
+static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+	total_bytes += dbuf.dsize;
+	return 0;
+}
+
+static void info_tdb(void)
+{
+	int count;
+	total_bytes = 0;
+	if ((count = tdb_traverse(tdb, traverse_fn, NULL)) == -1)
+		printf("Error = %s\n", tdb_errorstr(tdb));
+	else
+		printf("%d records totalling %d bytes\n", count, total_bytes);
+}
+
+static void speed_tdb(const char *tlimit)
+{
+	const char *str = "store test", *str2 = "transaction test";
+	unsigned timelimit = tlimit?atoi(tlimit):0;
+	double t;
+	int ops;
+	if (timelimit == 0) timelimit = 5;
+
+	ops = 0;
+	printf("Testing store speed for %u seconds\n", timelimit);
+	_start_timer();
+	do {
+		long int r = random();
+		TDB_DATA key, dbuf;
+		key.dptr = discard_const_p(uint8_t, str);
+		key.dsize = strlen((char *)key.dptr);
+		dbuf.dptr = (uint8_t *) &r;
+		dbuf.dsize = sizeof(r);
+		tdb_store(tdb, key, dbuf, TDB_REPLACE);
+		t = _end_timer();
+		ops++;
+	} while (t < timelimit);
+	printf("%10.3f ops/sec\n", ops/t);
+
+	ops = 0;
+	printf("Testing fetch speed for %u seconds\n", timelimit);
+	_start_timer();
+	do {
+		long int r = random();
+		TDB_DATA key, dbuf;
+		key.dptr = discard_const_p(uint8_t, str);
+		key.dsize = strlen((char *)key.dptr);
+		dbuf.dptr = (uint8_t *) &r;
+		dbuf.dsize = sizeof(r);
+		tdb_fetch(tdb, key);
+		t = _end_timer();
+		ops++;
+	} while (t < timelimit);
+	printf("%10.3f ops/sec\n", ops/t);
+
+	ops = 0;
+	printf("Testing transaction speed for %u seconds\n", timelimit);
+	_start_timer();
+	do {
+		long int r = random();
+		TDB_DATA key, dbuf;
+		key.dptr = discard_const_p(uint8_t, str2);
+		key.dsize = strlen((char *)key.dptr);
+		dbuf.dptr = (uint8_t *) &r;
+		dbuf.dsize = sizeof(r);
+		tdb_transaction_start(tdb);
+		tdb_store(tdb, key, dbuf, TDB_REPLACE);
+		tdb_transaction_commit(tdb);
+		t = _end_timer();
+		ops++;
+	} while (t < timelimit);
+	printf("%10.3f ops/sec\n", ops/t);
+
+	ops = 0;
+	printf("Testing traverse speed for %u seconds\n", timelimit);
+	_start_timer();
+	do {
+		tdb_traverse(tdb, traverse_fn, NULL);
+		t = _end_timer();
+		ops++;
+	} while (t < timelimit);
+	printf("%10.3f ops/sec\n", ops/t);
+}
+
+static void toggle_mmap(void)
+{
+	disable_mmap = !disable_mmap;
+	if (disable_mmap) {
+		printf("mmap is disabled\n");
+	} else {
+		printf("mmap is enabled\n");
+	}
+}
+
+static char *tdb_getline(const char *prompt)
+{
+	static char thisline[1024];
+	char *p;
+	fputs(prompt, stdout);
+	thisline[0] = 0;
+	p = fgets(thisline, sizeof(thisline)-1, stdin);
+	if (p) p = strchr(p, '\n');
+	if (p) *p = 0;
+	return p?thisline:NULL;
+}
+
+static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
+                     void *state)
+{
+    return tdb_delete(the_tdb, key);
+}
+
+static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
+{
+	TDB_DATA dbuf;
+	*pkey = tdb_firstkey(the_tdb);
+	
+	dbuf = tdb_fetch(the_tdb, *pkey);
+	if (!dbuf.dptr) terror("fetch failed");
+	else {
+		print_rec(the_tdb, *pkey, dbuf, NULL);
+	}
+}
+
+static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
+{
+	TDB_DATA dbuf;
+	*pkey = tdb_nextkey(the_tdb, *pkey);
+	
+	dbuf = tdb_fetch(the_tdb, *pkey);
+	if (!dbuf.dptr) 
+		terror("fetch failed");
+	else
+		print_rec(the_tdb, *pkey, dbuf, NULL);
+}
+
+static int count(TDB_DATA key, TDB_DATA data, void *private)
+{
+	(*(unsigned int *)private)++;
+	return 0;
+}
+
+static void check_db(TDB_CONTEXT *the_tdb)
+{
+	int tdbcount = 0;
+	if (!the_tdb)
+		printf("Error: No database opened!\n");
+	else if (tdb_check(the_tdb, count, &tdbcount) == -1)
+		printf("Integrity check for the opened database failed.\n");
+	else
+		printf("Database integrity is OK and has %d records.\n",
+		       tdbcount);
+}
+
+static int do_command(void)
+{
+	COMMAND_TABLE *ctp = cmd_table;
+	enum commands mycmd = CMD_HELP;
+	int cmd_len;
+
+	if (cmdname && strlen(cmdname) == 0) {
+		mycmd = CMD_NEXT;
+	} else {
+		while (ctp->name) {
+			cmd_len = strlen(ctp->name);
+			if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
+				mycmd = ctp->cmd;
+				break;
+			}
+			ctp++;
+		}
+	}
+
+	switch (mycmd) {
+	case CMD_CREATE_TDB:
+		bIterate = 0;
+		create_tdb(arg1);
+		return 0;
+	case CMD_OPEN_TDB:
+		bIterate = 0;
+		open_tdb(arg1);
+		return 0;
+	case CMD_SYSTEM:
+		/* Shell command */
+		if (system(arg1) == -1) {
+			terror("system() call failed\n");
+		}
+		return 0;
+	case CMD_QUIT:
+		return 1;
+	default:
+		/* all the rest require a open database */
+		if (!tdb) {
+			bIterate = 0;
+			terror("database not open");
+			help();
+			return 0;
+		}
+		switch (mycmd) {
+		case CMD_TRANSACTION_START:
+			bIterate = 0;
+			tdb_transaction_start(tdb);
+			return 0;
+		case CMD_TRANSACTION_COMMIT:
+			bIterate = 0;
+			tdb_transaction_commit(tdb);
+			return 0;
+		case CMD_TRANSACTION_CANCEL:
+			bIterate = 0;
+			tdb_transaction_cancel(tdb);
+			return 0;
+		case CMD_ERASE:
+			bIterate = 0;
+			tdb_traverse(tdb, do_delete_fn, NULL);
+			return 0;
+		case CMD_DUMP:
+			bIterate = 0;
+			tdb_traverse(tdb, print_rec, NULL);
+			return 0;
+		case CMD_INSERT:
+			bIterate = 0;
+			insert_tdb(arg1, arg1len,arg2,arg2len);
+			return 0;
+		case CMD_MOVE:
+			bIterate = 0;
+			move_rec(arg1,arg1len,arg2);
+			return 0;
+		case CMD_STORE:
+			bIterate = 0;
+			store_tdb(arg1,arg1len,arg2,arg2len);
+			return 0;
+		case CMD_SHOW:
+			bIterate = 0;
+			show_tdb(arg1, arg1len);
+			return 0;
+		case CMD_KEYS:
+			tdb_traverse(tdb, print_key, NULL);
+			return 0;
+		case CMD_HEXKEYS:
+			tdb_traverse(tdb, print_hexkey, NULL);
+			return 0;
+		case CMD_DELETE:
+			bIterate = 0;
+			delete_tdb(arg1,arg1len);
+			return 0;
+		case CMD_LIST_HASH_FREE:
+			tdb_dump_all(tdb);
+			return 0;
+		case CMD_LIST_FREE:
+			tdb_printfreelist(tdb);
+			return 0;
+		case CMD_INFO:
+			info_tdb();
+			return 0;
+		case CMD_SPEED:
+			speed_tdb(arg1);
+			return 0;
+		case CMD_MMAP:
+			toggle_mmap();
+			return 0;
+		case CMD_FIRST:
+			bIterate = 1;
+			first_record(tdb, &iterate_kbuf);
+			return 0;
+		case CMD_NEXT:
+			if (bIterate)
+				next_record(tdb, &iterate_kbuf);
+			return 0;
+		case CMD_CHECK:
+			check_db(tdb);
+			return 0;
+		case CMD_HELP:
+			help();
+			return 0;
+		case CMD_CREATE_TDB:
+		case CMD_OPEN_TDB:
+		case CMD_SYSTEM:
+		case CMD_QUIT:
+			/*
+			 * unhandled commands.  cases included here to avoid compiler
+			 * warnings.
+			 */
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static char *convert_string(char *instring, size_t *sizep)
+{
+	size_t length = 0;
+	char *outp, *inp;
+	char temp[3];
+
+	outp = inp = instring;
+
+	while (*inp) {
+		if (*inp == '\\') {
+			inp++;
+			if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
+				temp[0] = *inp++;
+				temp[1] = '\0';
+				if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
+					temp[1] = *inp++;
+					temp[2] = '\0';
+				}
+				*outp++ = (char)strtol((const char *)temp,NULL,16);
+			} else {
+				*outp++ = *inp++;
+			}
+		} else {
+			*outp++ = *inp++;
+		}
+		length++;
+	}
+	*sizep = length;
+	return instring;
+}
+
+int main(int argc, char *argv[])
+{
+	cmdname = "";
+	arg1 = NULL;
+	arg1len = 0;
+	arg2 = NULL;
+	arg2len = 0;
+
+	if (argv[1]) {
+		cmdname = "open";
+		arg1 = argv[1];
+		do_command();
+		cmdname =  "";
+		arg1 = NULL;
+	}
+
+	switch (argc) {
+	case 1:
+	case 2:
+		/* Interactive mode */
+		while ((cmdname = tdb_getline("tdb> "))) {
+			arg2 = arg1 = NULL;
+			if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
+				arg1++;
+				arg2 = arg1;
+				while (*arg2) {
+					if (*arg2 == ' ') {
+						*arg2++ = '\0';
+						break;
+					}
+					if ((*arg2++ == '\\') && (*arg2 == ' ')) {
+						arg2++;
+					}
+				}
+			}
+			if (arg1) arg1 = convert_string(arg1,&arg1len);
+			if (arg2) arg2 = convert_string(arg2,&arg2len);
+			if (do_command()) break;
+		}
+		break;
+	case 5:
+		arg2 = convert_string(argv[4],&arg2len);
+	case 4:
+		arg1 = convert_string(argv[3],&arg1len);
+	case 3:
+		cmdname = argv[2];
+	default:
+		do_command();
+		break;
+	}
+
+	if (tdb) tdb_close(tdb);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtorture.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtorture.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/tools/tdbtorture.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,431 @@
+/* this tests tdb by doing lots of ops from several simultaneous
+   writers - that stresses the locking code. 
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+#include "tdb.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+
+#define REOPEN_PROB 30
+#define DELETE_PROB 8
+#define STORE_PROB 4
+#define APPEND_PROB 6
+#define TRANSACTION_PROB 10
+#define TRANSACTION_PREPARE_PROB 2
+#define LOCKSTORE_PROB 5
+#define TRAVERSE_PROB 20
+#define TRAVERSE_READ_PROB 20
+#define CULL_PROB 100
+#define KEYLEN 3
+#define DATALEN 100
+
+static struct tdb_context *db;
+static int in_transaction;
+static int error_count;
+static int always_transaction = 0;
+static int hash_size = 2;
+static int loopnum;
+static int count_pipe;
+static struct tdb_logging_context log_ctx;
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+	va_list ap;
+
+	/* trace level messages do not indicate an error */
+	if (level != TDB_DEBUG_TRACE) {
+		error_count++;
+	}
+
+	va_start(ap, format);
+	vfprintf(stdout, format, ap);
+	va_end(ap);
+	fflush(stdout);
+#if 0
+	if (level != TDB_DEBUG_TRACE) {
+		char *ptr;
+		signal(SIGUSR1, SIG_IGN);
+		asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
+		system(ptr);
+		free(ptr);
+	}
+#endif	
+}
+
+static void fatal(const char *why)
+{
+	perror(why);
+	error_count++;
+}
+
+static char *randbuf(int len)
+{
+	char *buf;
+	int i;
+	buf = (char *)malloc(len+1);
+
+	for (i=0;i<len;i++) {
+		buf[i] = 'a' + (rand() % 26);
+	}
+	buf[i] = 0;
+	return buf;
+}
+
+static int cull_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+			 void *state)
+{
+#if CULL_PROB
+	if (random() % CULL_PROB == 0) {
+		tdb_delete(tdb, key);
+	}
+#endif
+	return 0;
+}
+
+static void addrec_db(void)
+{
+	int klen, dlen;
+	char *k, *d;
+	TDB_DATA key, data;
+
+	klen = 1 + (rand() % KEYLEN);
+	dlen = 1 + (rand() % DATALEN);
+
+	k = randbuf(klen);
+	d = randbuf(dlen);
+
+	key.dptr = (unsigned char *)k;
+	key.dsize = klen+1;
+
+	data.dptr = (unsigned char *)d;
+	data.dsize = dlen+1;
+
+#if REOPEN_PROB
+	if (in_transaction == 0 && random() % REOPEN_PROB == 0) {
+		tdb_reopen_all(0);
+		goto next;
+	}
+#endif
+
+#if TRANSACTION_PROB
+	if (in_transaction == 0 &&
+	    (always_transaction || random() % TRANSACTION_PROB == 0)) {
+		if (tdb_transaction_start(db) != 0) {
+			fatal("tdb_transaction_start failed");
+		}
+		in_transaction++;
+		goto next;
+	}
+	if (in_transaction && random() % TRANSACTION_PROB == 0) {
+		if (random() % TRANSACTION_PREPARE_PROB == 0) {
+			if (tdb_transaction_prepare_commit(db) != 0) {
+				fatal("tdb_transaction_prepare_commit failed");
+			}
+		}
+		if (tdb_transaction_commit(db) != 0) {
+			fatal("tdb_transaction_commit failed");
+		}
+		in_transaction--;
+		goto next;
+	}
+	if (in_transaction && random() % TRANSACTION_PROB == 0) {
+		if (tdb_transaction_cancel(db) != 0) {
+			fatal("tdb_transaction_cancel failed");
+		}
+		in_transaction--;
+		goto next;
+	}
+#endif
+
+#if DELETE_PROB
+	if (random() % DELETE_PROB == 0) {
+		tdb_delete(db, key);
+		goto next;
+	}
+#endif
+
+#if STORE_PROB
+	if (random() % STORE_PROB == 0) {
+		if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+			fatal("tdb_store failed");
+		}
+		goto next;
+	}
+#endif
+
+#if APPEND_PROB
+	if (random() % APPEND_PROB == 0) {
+		if (tdb_append(db, key, data) != 0) {
+			fatal("tdb_append failed");
+		}
+		goto next;
+	}
+#endif
+
+#if LOCKSTORE_PROB
+	if (random() % LOCKSTORE_PROB == 0) {
+		tdb_chainlock(db, key);
+		data = tdb_fetch(db, key);
+		if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+			fatal("tdb_store failed");
+		}
+		if (data.dptr) free(data.dptr);
+		tdb_chainunlock(db, key);
+		goto next;
+	} 
+#endif
+
+#if TRAVERSE_PROB
+	if (random() % TRAVERSE_PROB == 0) {
+		tdb_traverse(db, cull_traverse, NULL);
+		goto next;
+	}
+#endif
+
+#if TRAVERSE_READ_PROB
+	if (random() % TRAVERSE_READ_PROB == 0) {
+		tdb_traverse_read(db, NULL, NULL);
+		goto next;
+	}
+#endif
+
+	data = tdb_fetch(db, key);
+	if (data.dptr) free(data.dptr);
+
+next:
+	free(k);
+	free(d);
+}
+
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+                       void *state)
+{
+	tdb_delete(tdb, key);
+	return 0;
+}
+
+static void usage(void)
+{
+	printf("Usage: tdbtorture [-t] [-k] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
+	exit(0);
+}
+
+static void send_count_and_suicide(int sig)
+{
+	/* This ensures our successor can continue where we left off. */
+	write(count_pipe, &loopnum, sizeof(loopnum));
+	/* This gives a unique signature. */
+	kill(getpid(), SIGUSR2);
+}
+
+static int run_child(int i, int seed, unsigned num_loops, unsigned start)
+{
+	db = tdb_open_ex("torture.tdb", hash_size, TDB_DEFAULT,
+			 O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
+	if (!db) {
+		fatal("db open failed");
+	}
+
+	srand(seed + i);
+	srandom(seed + i);
+
+	/* Set global, then we're ready to handle being killed. */
+	loopnum = start;
+	signal(SIGUSR1, send_count_and_suicide);
+
+	for (;loopnum<num_loops && error_count == 0;loopnum++) {
+		addrec_db();
+	}
+
+	if (error_count == 0) {
+		tdb_traverse_read(db, NULL, NULL);
+		if (always_transaction) {
+			while (in_transaction) {
+				tdb_transaction_cancel(db);
+				in_transaction--;
+			}
+			if (tdb_transaction_start(db) != 0)
+				fatal("tdb_transaction_start failed");
+		}
+		tdb_traverse(db, traverse_fn, NULL);
+		tdb_traverse(db, traverse_fn, NULL);
+		if (always_transaction) {
+			if (tdb_transaction_commit(db) != 0)
+				fatal("tdb_transaction_commit failed");
+		}
+	}
+
+	tdb_close(db);
+
+	return (error_count < 100 ? error_count : 100);
+}
+
+int main(int argc, char * const *argv)
+{
+	int i, seed = -1;
+	int num_loops = 5000;
+	int num_procs = 3;
+	int c, pfds[2];
+	extern char *optarg;
+	pid_t *pids;
+	int kill_random = 0;
+	int *done;
+
+	log_ctx.log_fn = tdb_log;
+
+	while ((c = getopt(argc, argv, "n:l:s:H:thk")) != -1) {
+		switch (c) {
+		case 'n':
+			num_procs = strtol(optarg, NULL, 0);
+			break;
+		case 'l':
+			num_loops = strtol(optarg, NULL, 0);
+			break;
+		case 'H':
+			hash_size = strtol(optarg, NULL, 0);
+			break;
+		case 's':
+			seed = strtol(optarg, NULL, 0);
+			break;
+		case 't':
+			always_transaction = 1;
+			break;
+		case 'k':
+			kill_random = 1;
+			break;
+		default:
+			usage();
+		}
+	}
+
+	unlink("torture.tdb");
+
+	if (seed == -1) {
+		seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
+	}
+
+	if (num_procs == 1 && !kill_random) {
+		/* Don't fork for this case, makes debugging easier. */
+		error_count = run_child(0, seed, num_loops, 0);
+		goto done;
+	}
+
+	pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
+	done = (int *)calloc(sizeof(int), num_procs);
+
+	if (pipe(pfds) != 0) {
+		perror("Creating pipe");
+		exit(1);
+	}
+	count_pipe = pfds[1];
+
+	for (i=0;i<num_procs;i++) {
+		if ((pids[i]=fork()) == 0) {
+			close(pfds[0]);
+			if (i == 0) {
+				printf("Testing with %d processes, %d loops, %d hash_size, seed=%d%s\n",
+				       num_procs, num_loops, hash_size, seed, always_transaction ? " (all within transactions)" : "");
+			}
+			exit(run_child(i, seed, num_loops, 0));
+		}
+	}
+
+	while (num_procs) {
+		int status, j;
+		pid_t pid;
+
+		if (error_count != 0) {
+			/* try and stop the test on any failure */
+			for (j=0;j<num_procs;j++) {
+				if (pids[j] != 0) {
+					kill(pids[j], SIGTERM);
+				}
+			}
+		}
+
+		pid = waitpid(-1, &status, kill_random ? WNOHANG : 0);
+		if (pid == 0) {
+			struct timeval tv;
+
+			/* Sleep for 1/10 second. */
+			tv.tv_sec = 0;
+			tv.tv_usec = 100000;
+			select(0, NULL, NULL, NULL, &tv);
+
+			/* Kill someone. */
+			kill(pids[random() % num_procs], SIGUSR1);
+			continue;
+		}
+
+		if (pid == -1) {
+			perror("failed to wait for child\n");
+			exit(1);
+		}
+
+		for (j=0;j<num_procs;j++) {
+			if (pids[j] == pid) break;
+		}
+		if (j == num_procs) {
+			printf("unknown child %d exited!?\n", (int)pid);
+			exit(1);
+		}
+		if (WIFSIGNALED(status)) {
+			if (WTERMSIG(status) == SIGUSR2
+			    || WTERMSIG(status) == SIGUSR1) {
+				/* SIGUSR2 means they wrote to pipe. */
+				if (WTERMSIG(status) == SIGUSR2) {
+					read(pfds[0], &done[j],
+					     sizeof(done[j]));
+				}
+				pids[j] = fork();
+				if (pids[j] == 0)
+					exit(run_child(j, seed, num_loops,
+						       done[j]));
+				printf("Restarting child %i for %u-%u\n",
+				       j, done[j], num_loops);
+				continue;
+			}
+			printf("child %d exited with signal %d\n",
+			       (int)pid, WTERMSIG(status));
+			error_count++;
+		} else {
+			if (WEXITSTATUS(status) != 0) {
+				printf("child %d exited with status %d\n",
+				       (int)pid, WEXITSTATUS(status));
+				error_count++;
+			}
+		}
+		memmove(&pids[j], &pids[j+1],
+			(num_procs - j - 1)*sizeof(pids[0]));
+		num_procs--;
+	}
+
+	free(pids);
+
+done:
+	if (error_count == 0) {
+		db = tdb_open_ex("torture.tdb", hash_size, TDB_DEFAULT,
+				 O_RDWR, 0, &log_ctx, NULL);
+		if (!db) {
+			fatal("db open failed");
+		}
+		if (tdb_check(db, NULL, NULL) == -1) {
+			printf("db check failed");
+			exit(1);
+		}
+		tdb_close(db);
+		printf("OK\n");
+	}
+
+	return error_count;
+}

Added: branches/ctdb/squeeze-backports/lib/tdb/web/index.html
===================================================================
--- branches/ctdb/squeeze-backports/lib/tdb/web/index.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tdb/web/index.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>ldb</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
+
+<h1>tdb</h1>
+
+TDB is a Trivial Database. In concept, it is very much like GDBM, and BSD's DB 
+except that it allows multiple simultaneous writers and uses locking 
+internally to keep writers from trampling on each other. TDB is also extremely 
+small.
+
+<h2>Download</h2>
+You can download the latest releases of tdb from the <a
+href="http://samba.org/ftp/tdb">tdb directory</a> on the samba public
+source archive.
+
+
+<h2>Discussion and bug reports</h2>
+
+tdb does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+<h2>Download</h2>
+
+You can download the latest code either via git or rsync.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the master branch and cd into the source/lib/tdb directory.<br>
+<br>
+To fetch via rsync use these commands:
+
+<pre>
+  rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/tdb .
+  rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/replace .
+</pre>
+
+and build in tdb. It will find the replace library in the directory
+above automatically.
+
+</BODY>
+</HTML>

Added: branches/ctdb/squeeze-backports/lib/tevent/ABI/tevent-0.9.9.sigs
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/ABI/tevent-0.9.9.sigs	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/ABI/tevent-0.9.9.sigs	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,73 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)

Added: branches/ctdb/squeeze-backports/lib/tevent/Makefile.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/Makefile.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/Makefile.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,79 @@
+#!gmake
+#
+# Makefile for tdb directory
+#
+
+CC = @CC@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+includedir = @includedir@
+libdir = @libdir@
+VPATH = @srcdir@:@libreplacedir@
+srcdir = @srcdir@
+builddir = @builddir@
+sharedbuilddir = @sharedbuilddir@
+INSTALLCMD = @INSTALL@
+CPPFLAGS = @CPPFLAGS@ -I$(srcdir)/include -Iinclude -I.
+LDFLAGS = @LDFLAGS@
+EXEEXT = @EXEEXT@
+SHLD = @SHLD@
+SHLD_FLAGS = @SHLD_FLAGS@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PICFLAG = @PICFLAG@
+SHLIBEXT = @SHLIBEXT@
+LIB_PATH_VAR = @LIB_PATH_VAR@
+teventdir = @teventdir@
+
+TALLOC_CFLAGS = @TALLOC_CFLAGS@
+TALLOC_LDFLAGS = @TALLOC_CFLAGS@
+TALLOC_LIBS = @TALLOC_LIBS@
+
+TEVENT_CFLAGS = @TEVENT_CFLAGS@
+TEVENT_LDFLAGS = @TEVENT_CFLAGS@
+TEVENT_LIBS = @TEVENT_LIBS@
+
+CFLAGS = $(CPPFLAGS) $(TALLOC_CFLAGS) $(TEVENT_CFLAGS) @CFLAGS@
+LDFLAGS = $(TALLOC_LDFLAGS) $(TEVENT_LDFLAGS) @LDFLAGS@
+LIBS = $(TALLOC_LIBS) $(TEVENT_LIBS) @LIBS@
+
+TEVENT_OBJ = @TEVENT_OBJ@ @LIBREPLACEOBJ@
+
+SONAMEFLAG = @SONAMEFLAG@
+VERSIONSCRIPT = @VERSIONSCRIPT@
+EXPORTSFILE = @EXPORTSFILE@
+
+default: all
+
+include $(teventdir)/tevent.mk
+include $(teventdir)/rules.mk
+
+all:: showflags dirs $(PROGS) $(TEVENT_SOLIB) libtevent.a
+
+install:: all
+$(TEVENT_SOLIB): $(TEVENT_OBJ)
+	$(SHLD) $(SHLD_FLAGS) $(LDFLAGS) $(LIBS) -o $@ $(TEVENT_OBJ) $(VERSIONSCRIPT) $(EXPORTSFILE) $(SONAMEFLAG)$(TEVENT_SONAME)
+
+shared-build: all
+	${INSTALLCMD} -d $(sharedbuilddir)/lib
+	${INSTALLCMD} -m 644 libtevent.a $(sharedbuilddir)/lib
+	${INSTALLCMD} -m 755 $(TEVENT_SOLIB) $(sharedbuilddir)/lib
+	ln -sf $(TEVENT_SOLIB) $(sharedbuilddir)/lib/$(TEVENT_SONAME)
+	ln -sf $(TEVENT_SOLIB) $(sharedbuilddir)/lib/libtevent.so
+	${INSTALLCMD} -d $(sharedbuilddir)/include
+	${INSTALLCMD} -m 644 $(srcdir)/tevent.h $(sharedbuilddir)/include
+
+check: test
+
+installcheck:: test install
+
+clean::
+	rm -f *.o *.a */*.o
+	rm -fr abi
+
+distclean:: clean
+	rm -f config.log config.status config.h config.cache
+	rm -f Makefile
+
+realdistclean:: distclean
+	rm -f configure config.h.in

Added: branches/ctdb/squeeze-backports/lib/tevent/autogen-waf.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/autogen-waf.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/autogen-waf.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+link ../../buildtools/scripts/autogen-waf.sh
\ No newline at end of file


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/autogen-waf.sh
___________________________________________________________________
Added: svn:special
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/autogen.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/autogen.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/autogen.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace -I ../../../lib/replace"
+autoconf $IPATHS || exit 1
+autoheader $IPATHS || exit 1
+
+rm -rf autom4te.cache
+
+echo "Now run ./configure and then make."
+exit 0


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/autogen.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/build_macros.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/build_macros.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/build_macros.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+AC_DEFUN(BUILD_WITH_SHARED_BUILD_DIR,
+  [ AC_ARG_WITH([shared-build-dir],
+                [AC_HELP_STRING([--with-shared-build-dir=DIR],
+                                [temporary build directory where libraries are installed [$srcdir/sharedbuild]])])
+
+    sharedbuilddir="$srcdir/sharedbuild"
+    if test x"$with_shared_build_dir" != x; then
+        sharedbuilddir=$with_shared_build_dir
+        CFLAGS="$CFLAGS -I$with_shared_build_dir/include"
+        CPPFLAGS="$CPPFLAGS -I$with_shared_build_dir/include"
+        LDFLAGS="$LDFLAGS -L$with_shared_build_dir/lib"
+    fi
+    AC_SUBST(sharedbuilddir)
+  ])

Added: branches/ctdb/squeeze-backports/lib/tevent/config.guess
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/config.guess	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/config.guess	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1561 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2009-04-27'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+		{
+		case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+		case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+		case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+		    switch (bits)
+			{
+			case 64: puts ("hppa2.0w"); break;
+			case 32: puts ("hppa2.0n"); break;
+			default: puts ("hppa2.0"); break;
+			} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+		    puts ("hppa2.0"); break;
+              #endif
+		default: puts ("hppa1.0"); break;
+		}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd | genuineintel)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel at ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/config.guess
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/config.sub
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/config.sub	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/config.sub	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1686 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2009-04-17'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+	-chorusrdb)
+		os=-chorusrdb
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/config.sub
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/configure.ac
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/configure.ac	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/configure.ac	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,25 @@
+AC_PREREQ(2.50)
+AC_INIT(tevent, 0.9.9)
+AC_CONFIG_SRCDIR([tevent.c])
+AC_CONFIG_HEADER(config.h)
+
+AC_LIBREPLACE_ALL_CHECKS
+
+AC_LD_EXPORT_DYNAMIC
+AC_LD_SONAMEFLAG
+AC_LD_VERSIONSCRIPT
+AC_LD_PICFLAG
+AC_LD_SHLIBEXT
+AC_LIBREPLACE_SHLD
+AC_LIBREPLACE_SHLD_FLAGS
+AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR
+
+m4_include(build_macros.m4)
+BUILD_WITH_SHARED_BUILD_DIR
+
+m4_include(pkg.m4)
+m4_include(libtalloc.m4)
+
+m4_include(libtevent.m4)
+
+AC_OUTPUT(Makefile tevent.pc)

Added: branches/ctdb/squeeze-backports/lib/tevent/doc/mainpage.dox
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/doc/mainpage.dox	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/doc/mainpage.dox	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,42 @@
+/**
+ * @mainpage
+ *
+ * Tevent is an event system based on the talloc memory management library. It
+ * is the core event system used in Samba.
+ *
+ * The low level tevent has support for many event types, including timers,
+ * signals, and the classic file descriptor events.
+ *
+ * Tevent also provide helpers to deal with asynchronous code providing the
+ * tevent_req (tevent tequest) functions.
+ *
+ * @section tevent_download Download
+ *
+ * You can download the latest releases of tevent from the
+ * <a href="http://samba.org/ftp/tevent" target="_blank">tevent directory</a>
+ * on the samba public source archive.
+ *
+ * @section tevent_bugs Discussion and bug reports
+ *
+ * tevent does not currently have its own mailing list or bug tracking system.
+ * For now, please use the
+ * <a href="https://lists.samba.org/mailman/listinfo/samba-technical" target="_blank">samba-technical</a>
+ * mailing list, and the
+ * <a href="http://bugzilla.samba.org/" target="_blank">Samba bugzilla</a>
+ * bug tracking system.
+ *
+ * @section tevent_devel Development
+ * You can download the latest code either via git or rsync.
+ *
+ * To fetch via git see the following guide:
+ *
+ * <a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development" target="_blank">Using Git for Samba Development</a>
+ *
+ * Once you have cloned the tree switch to the master branch and cd into the
+ * lib/tevent directory.
+ *
+ * To fetch via rsync use this command:
+ *
+ *   rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/tevent .
+ *
+ */

Added: branches/ctdb/squeeze-backports/lib/tevent/doc/tutorials.dox
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/doc/tutorials.dox	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/doc/tutorials.dox	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,43 @@
+/**
+ * @page tevent_queue_tutorial The tevent_queue tutorial
+ *
+ * @section Introduction
+ *
+ * A tevent_queue is used to queue up async requests that must be
+ * serialized. For example writing buffers into a socket must be
+ * serialized. Writing a large lump of data into a socket can require
+ * multiple write(2) or send(2) system calls. If more than one async
+ * request is outstanding to write large buffers into a socket, every
+ * request must individually be completed before the next one begins,
+ * even if multiple syscalls are required.
+ *
+ * To do this, every socket gets assigned a tevent_queue struct.
+ *
+ * Creating a serialized async request follows the usual convention to
+ * return a tevent_req structure with an embedded state structure. To
+ * serialize the work the requests is about to so, instead of directly
+ * starting or doing that work, tevent_queue_add must be called. When it
+ * is time for the serialized async request to do its work, the trigger
+ * callback function tevent_queue_add was given is called. In the example
+ * of writing to a socket, the trigger is called when the write request
+ * can begin accessing the socket.
+ *
+ * How does this engine work behind the scenes? When the queue is empty,
+ * tevent_queue_add schedules an immediate call to the trigger
+ * callback. The trigger callback starts its work, likely by starting
+ * other async subrequests. While these async subrequests are working,
+ * more requests can accumulate in the queue by tevent_queue_add. While
+ * there is no function to explicitly trigger the next waiter in line, it
+ * still works: When the active request in the queue is done, it will be
+ * destroyed by talloc_free. Talloc_free of an serialized async request
+ * that had been added to a queue will trigger the next request in the
+ * queue via a talloc destructor attached to a child of the serialized
+ * request. This way the queue will be kept busy when an async request
+ * finishes.
+ *
+ * @section Example
+ *
+ * @code
+ *      Metze: Please add a code example here.
+ * @endcode
+ */

Added: branches/ctdb/squeeze-backports/lib/tevent/doxy.config
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/doxy.config	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/doxy.config	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1538 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = tevent
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 0.9.8
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = . doc
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.cpp \
+                         *.cc \
+                         *.c \
+                         *.h \
+                         *.hh \
+                         *.hpp \
+                         *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = */.git/* \
+                         */.svn/* \
+                         */cmake/* \
+                         */build/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# If the HTML_FOOTER_DESCRIPTION tag is set to YES, Doxygen will
+# add generated date, project name and doxygen version to HTML footer.
+
+HTML_FOOTER_DESCRIPTION= NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NONE
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = DOXYGEN PRINTF_ATTRIBUTE(x,y)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES

Added: branches/ctdb/squeeze-backports/lib/tevent/install-sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/install-sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/install-sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ]
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename |
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ]
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/install-sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/libtalloc.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/libtalloc.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/libtalloc.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+AC_SUBST(TALLOC_OBJ)
+AC_SUBST(TALLOC_CFLAGS)
+AC_SUBST(TALLOC_LIBS)
+
+AC_CHECK_HEADER(talloc.h,
+   [AC_CHECK_LIB(talloc, talloc_init, [TALLOC_LIBS="-ltalloc"]) ],
+   [PKG_CHECK_MODULES(TALLOC, talloc)])

Added: branches/ctdb/squeeze-backports/lib/tevent/libtevent.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/libtevent.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/libtevent.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,44 @@
+dnl find the tevent sources. This is meant to work both for
+dnl standalone builds, and builds of packages using libtevent
+
+AC_SUBST(teventdir)
+
+if test x"$teventdir" = "x"; then
+	teventdir=""
+	teventpaths="$srcdir $srcdir/lib/tevent $srcdir/tevent $srcdir/../tevent"
+	for d in $teventpaths; do
+		if test -f "$d/tevent.c"; then
+			teventdir="$d"
+			break;
+		fi
+	done
+	if test x"$teventdir" = "x"; then
+	   AC_MSG_ERROR([cannot find libtevent source in $teventpaths])
+	fi
+fi
+
+TEVENT_OBJ=""
+TEVENT_CFLAGS=""
+TEVENT_LIBS=""
+AC_SUBST(TEVENT_OBJ)
+AC_SUBST(TEVENT_CFLAGS)
+AC_SUBST(TEVENT_LIBS)
+
+TEVENT_CFLAGS="-I$teventdir"
+
+TEVENT_OBJ="tevent.o tevent_debug.o tevent_util.o"
+TEVENT_OBJ="$TEVENT_OBJ tevent_fd.o tevent_timed.o tevent_immediate.o tevent_signal.o"
+TEVENT_OBJ="$TEVENT_OBJ tevent_req.o tevent_wakeup.o tevent_queue.o"
+TEVENT_OBJ="$TEVENT_OBJ tevent_standard.o tevent_select.o"
+
+AC_CHECK_HEADERS(sys/epoll.h)
+AC_CHECK_FUNCS(epoll_create)
+if test x"$ac_cv_header_sys_epoll_h" = x"yes" -a x"$ac_cv_func_epoll_create" = x"yes"; then
+   TEVENT_OBJ="$TEVENT_OBJ tevent_epoll.o"
+   AC_DEFINE(HAVE_EPOLL, 1, [Whether epoll available])
+fi
+
+if test x"$VERSIONSCRIPT" != "x"; then
+    EXPORTSFILE=tevent.exports
+    AC_SUBST(EXPORTSFILE)
+fi

Added: branches/ctdb/squeeze-backports/lib/tevent/pkg.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/pkg.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/pkg.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,156 @@
+# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
+#
+# Copyright © 2004 Scott James Remnant <scott at netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=m4_default([$1], [0.9.0])
+	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		AC_MSG_RESULT([yes])
+	else
+		AC_MSG_RESULT([no])
+		PKG_CONFIG=""
+	fi
+
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists.  Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$PKG_CONFIG"; then
+    if test -n "$$1"; then
+        pkg_cv_[]$1="$$1"
+    else
+        PKG_CHECK_EXISTS([$3],
+                         [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+			 [pkg_failed=yes])
+    fi
+else
+	pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
+        else
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+	ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+		[AC_MSG_RESULT([no])
+                $4])
+elif test $pkg_failed = untried; then
+	ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])],
+		[$4])
+else
+	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+	ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES

Added: branches/ctdb/squeeze-backports/lib/tevent/release-script.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/release-script.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/release-script.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+if [ "$1" = "" ]; then
+    echo "Please provide version string, eg: 1.2.0"
+    exit 1
+fi
+
+if [ ! -d "lib/tevent" ]; then
+    echo "Run this script from the samba base directory."
+    exit 1
+fi
+
+git clean -f -x -d lib/tevent
+git clean -f -x -d lib/replace
+
+curbranch=`git-branch |grep "^*" | tr -d "* "`
+
+version=$1
+strver=`echo ${version} | tr "." "-"`
+
+# Checkout the release tag
+git branch -f tevent-release-script-${strver} tevent-${strver}
+if [ ! "$?" = "0" ];  then
+    echo "Unable to checkout tevent-${strver} release"
+    exit 1
+fi
+
+git checkout tevent-release-script-${strver}
+
+# Test configure agrees with us
+confver=`grep "^AC_INIT" lib/tevent/configure.ac | tr -d "AC_INIT(tevent, " | tr -d ")"`
+if [ ! "$confver" = "$version" ]; then
+    echo "Wrong version, requested release for ${version}, found ${confver}"
+    exit 1
+fi
+
+# Now build tarball
+cp -a lib/tevent tevent-${version}
+cp -a lib/replace tevent-${version}/libreplace
+pushd tevent-${version}
+./autogen.sh
+popd
+tar cvzf tevent-${version}.tar.gz tevent-${version}
+rm -fr tevent-${version}
+
+#Clean up
+git checkout $curbranch
+git branch -d tevent-release-script-${strver}


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/release-script.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/rules.mk
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/rules.mk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/rules.mk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,18 @@
+.SUFFIXES: .i _wrap.c
+
+showflags::
+	@echo 'libtevent will be compiled with flags:'
+	@echo '  CFLAGS = $(CFLAGS)'
+	@echo '  CPPFLAGS = $(CPPFLAGS)'
+	@echo '  LDFLAGS = $(LDFLAGS)'
+	@echo '  LIBS = $(LIBS)'
+
+.SUFFIXES: .c .o
+
+.c.o:
+	@echo Compiling $*.c
+	@mkdir -p `dirname $@`
+	@$(CC) $(PICFLAG) $(CFLAGS) $(ABI_CHECK) -c $< -o $@
+
+distclean::
+	rm -f *~ */*~

Added: branches/ctdb/squeeze-backports/lib/tevent/samba.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/samba.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/samba.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+
+teventdir="\$(libteventsrcdir)"
+m4_include(../lib/tevent/libtevent.m4)
+
+SMB_EXT_LIB(LIBTEVENT_EXT, [${TEVENT_LIBS}])
+SMB_ENABLE(LIBTEVENT_EXT)
+
+SMB_SUBSYSTEM(LIBTEVENT,
+	[\$(addprefix \$(libteventsrcdir)/, ${TEVENT_OBJ})],
+	[LIBTEVENT_EXT],
+	[${TEVENT_CFLAGS}])

Added: branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,91 @@
+#!/bin/sh
+
+#
+# abi_checks.sh - check for possible abi changes
+#
+# Copyright (C) 2009 Micheal Adam <obnox at samba.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# USAGE: abi_checks.sh LIBNAME header1 [header2 ...]
+#
+# This script creates symbol and signature lists from the provided header
+# files with the aid of the mksyms.sh and mksigs.pl scripts (saved as
+# $LIBNAME.exports.check and $LIBNAME.sigatures.check). It then compares
+# the resulting files with the files $LIBNAME.exports and $LIBNME.signatures
+# which it expects to find in the current directory.
+#
+
+LANG=C; export LANG
+LC_ALL=C; export LC_ALL
+LC_COLLATE=C; export LC_COLLATE
+
+script=$0
+dir_name=$(dirname ${script})
+
+if test x"$1" = "x" ; then
+	echo "USAGE: ${script} libname header [header ...]"
+	exit 1
+fi
+
+libname="$1"
+shift
+
+if test x"$1" = "x" ; then
+	echo "USAGE: ${script} libname header [header ...]"
+	exit 1
+fi
+
+headers="$*"
+
+exports_file=${libname}.exports
+exports_file_check=${exports_file}.check
+signatures_file=${libname}.signatures
+signatures_file_check=${signatures_file}.check
+
+
+${dir_name}/mksyms.sh awk ${exports_file_check} ${headers} 2>&1 > /dev/null
+
+cat ${headers} | ${dir_name}/mksigs.pl > ${signatures_file_check} 2> /dev/null
+
+normalize_exports_file() {
+	filename=$1
+	cat ${filename} \
+	| sed -e 's/^[ \t]*//g' \
+	| sed -e 's/^$//g' \
+	| sed -e 's/^#.*$//g' \
+	| sort | uniq > ${filename}.sort
+}
+
+normalize_exports_file ${exports_file}
+normalize_exports_file ${exports_file_check}
+
+normalize_exports_file ${signatures_file}
+normalize_exports_file ${signatures_file_check}
+
+diff -u ${exports_file}.sort ${exports_file_check}.sort
+if test "x$?" != "x0" ; then
+	echo "WARNING: possible ABI change detected in exports!"
+else
+	echo "exports check: OK"
+fi
+
+diff -u ${signatures_file}.sort ${signatures_file_check}.sort
+if test "x$?" != "x0" ; then
+	echo "WARNING: possible ABI change detected in signatures!"
+else
+	echo "signatures check: OK"
+fi


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks_gcc.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks_gcc.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks_gcc.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/bash
+make clean
+
+mkdir abi
+ABI_CHECKS="-aux-info abi/\$@.X"
+make ABI_CHECK="$ABI_CHECKS" CC="/usr/bin/gcc"
+
+for i in abi/*.X; do cat $i | grep 'tevent\.h'; done | sort | uniq | awk -F "extern " '{ print $2 }' | sort> abi/signatures
+
+cat > abi/exports << EOF
+{
+    global:
+EOF
+cat abi/signatures | awk -F '(' '{ print $1 }' | awk -F ' ' '{ print "           "$NF";" }' | tr -d '*' | sort >> abi/exports
+cat >> abi/exports << EOF
+
+    local: *;
+};
+EOF
+
+rm -fr abi/*.X
+
+diff -u tevent.signatures abi/signatures
+if [ "$?" != "0" ]; then
+    echo "WARNING: Possible ABI Change!!"
+fi
+
+diff -u tevent.exports abi/exports
+if [ "$?" != "0" ]; then
+    echo "WARNING: Export file may be outdated!!"
+fi


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/script/abi_checks_gcc.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/script/mksigs.pl
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/script/mksigs.pl	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/script/mksigs.pl	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,183 @@
+#!/usr/bin/perl
+
+# mksigs.pl - extract signatures from C headers
+#
+# Copyright (C) Michael Adam 2009
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, see <http://www.gnu.org/licenses/>.
+
+# USAGE:  cat $header_files | mksigs.pl > $signature_file
+#
+# The header files to parse are read from stdin.
+# The output is in a form as produced by gcc with the -aux-info switch
+# and printed to stdout.
+
+use strict;
+use warnings;
+
+my $in_comment = 0;
+my $extern_C_block = 0;
+
+while (my $LINE = <>) {
+	# find end of started multi-line-comment
+	if ($in_comment) {
+		if ($LINE =~ /^.*?\*\/(.*)$/) {
+			$LINE = $1;
+			$in_comment = 0;
+		} else {
+			# whole line within comment
+			next;
+		}
+	}
+
+	# strip C++-style comments
+	$LINE =~ s/^(.*?)\/\/.*$/$1/;
+
+	# strip in-line-comments:
+	while ($LINE =~ /\/\*.*?\*\//) {
+		$LINE =~ s/\/\*.*?\*\///;
+	}
+
+	# find starts of multi-line-comments
+	if ($LINE =~ /^(.*)\/\*/) {
+		$in_comment = 1;
+		$LINE = $1;
+	}
+
+	# skip empty lines
+	next if $LINE =~ /^\s*$/;
+
+	# remove leading spaces
+	$LINE =~ s/^\s*(.*)$/$1/;
+
+	# concatenate lines split with "\" (usually macro defines)
+	while ($LINE =~ /^(.*?)\s+\\$/) {
+		my $LINE2 = <>;
+		$LINE = $1;
+		$LINE2 =~ s/^\s*(.*)$/$1/;
+		$LINE .= " " . $LINE2;
+	}
+
+	# remove all preprocessor directives
+	next if ($LINE =~ /^#/);
+
+	if ($LINE =~ /^extern\s+"C"\s+\{/) {
+		$extern_C_block = 1;
+		next;
+	}
+
+	if (($LINE =~ /^[^\{]*\}/) and $extern_C_block) {
+		$extern_C_block = 0;
+		next;
+	}
+
+	$LINE =~ s/^extern\s//;
+
+	# concatenate braces stretched over multiple lines
+	# (from structs or enums)
+	my $REST = $LINE;
+	my $braces = 0;
+	while (($REST =~ /[\{\}]/) or ($braces)) {
+		while ($REST =~ /[\{\}]/) {
+			# collect opening
+			while ($REST =~ /^[^\{\}]*\{(.*)$/) {
+				$braces++;
+				$REST = $1;
+			}
+
+			# collect closing
+			while ($REST =~ /^[^\{\}]*\}(.*)$/) {
+				$braces--;
+				$REST = $1;
+			}
+		}
+
+		# concatenate if not balanced
+		if ($braces) {
+			if (my $LINE2 = <>) {
+				$LINE2 =~ s/^\s*(.*)$/$1/;
+				chomp($LINE);
+				$LINE .= " " . $LINE2;
+				chomp $REST;
+				$REST .= " " . $LINE2;
+			} else {
+				print "ERROR: unbalanced braces ($braces)\n";
+				last;
+			}
+		}
+	}
+
+	# concetenate function prototypes that stretch over multiple lines
+	$REST = $LINE;
+	my $parenthesis = 0;
+	while (($REST =~ /[\(\)]/) or ($parenthesis)) {
+		while ($REST =~ /[\(\)]/) {
+			# collect opening
+			while ($REST =~ /^[^\(\)]*\((.*)$/) {
+				$parenthesis++;
+				$REST = $1;
+			}
+
+			# collect closing
+			while ($REST =~ /^[^\(\)]*\)(.*)$/) {
+				$parenthesis--;
+				$REST = $1;
+			}
+		}
+
+		# concatenate if not balanced
+		if ($parenthesis) {
+			if (my $LINE2 = <>) {
+				$LINE2 =~ s/^\s*(.*)$/$1/;
+				chomp($LINE);
+				$LINE .= " " . $LINE2;
+				chomp($REST);
+				$REST .= " " . $LINE2;
+			} else {
+				print "ERROR: unbalanced parantheses ($parenthesis)\n";
+				last;
+			}
+		}
+	}
+
+	next if ($LINE =~ /^typedef\s/);
+	next if ($LINE =~ /^enum\s+[^\{\(]+\s+\{/);
+	next if ($LINE =~ /^struct\s+[^\{\(]+\s+\{.*\}\s*;/);
+	next if ($LINE =~ /^struct\s+[a-zA-Z0-9_]+\s*;/);
+
+	# remove trailing spaces
+	$LINE =~ s/(.*?)\s*$/$1/;
+
+	$LINE =~ s/^(.*\))\s+PRINTF_ATTRIBUTE\([^\)]*\)(\s*[;,])/$1$2/;
+	$LINE =~ s/^(.*\))\s*[a-zA-Z0-9_]+\s*;$/$1;/;
+
+	# remove parameter names - slightly too coarse probably
+	$LINE =~ s/([\s\(]\*?)[_0-9a-zA-Z]+\s*([,\)])/$1$2/g;
+
+	# remedy (void) from last line
+	$LINE =~ s/\(\)/(void)/g;
+
+	# normalize spaces
+	$LINE =~ s/\s*\)\s*/)/g;
+	$LINE =~ s/\s*\(\s*/ (/g;
+	$LINE =~ s/\s*,\s*/, /g;
+
+	# normalize unsigned
+	$LINE =~ s/([\s,\(])unsigned([,\)])/$1unsigned int$2/g;
+
+	# normalize bool
+	$LINE =~ s/(\b)bool(\b)/_Bool/g;
+
+	print $LINE . "\n";
+}


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/script/mksigs.pl
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.awk
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.awk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.awk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,75 @@
+#
+# mksyms.awk
+#
+# Extract symbols to export from C-header files.
+# output in version-script format for linking shared libraries.
+#
+# Copyright (C) 2008 Michael Adam <obnox at samba.org>
+#
+BEGIN {
+	inheader=0;
+	current_file="";
+	print "#"
+	print "# This file is automatically generated with \"make symbols\". DO NOT EDIT "
+	print "#"
+	print "{"
+	print "\tglobal:"
+}
+
+END {
+	print""
+	print "\tlocal: *;"
+	print "};"
+}
+
+{
+	if (FILENAME!=current_file) {
+		print "\t\t# The following definitions come from",FILENAME
+		current_file=FILENAME
+	}
+	if (inheader) {
+		if (match($0,"[)][^()]*[;][ \t]*$")) {
+			inheader = 0;
+		}
+		next;
+	}
+}
+
+/^static/ || /^[ \t]*typedef/ || !/^[a-zA-Z\_]/ {
+	next;
+}
+
+/^extern[ \t]+[^()]+[;][ \t]*$/ {
+	gsub(/[^ \t]+[ \t]+/, "");
+	sub(/[;][ \t]*$/, "");
+	printf "\t\t%s;\n", $0;
+	next;
+}
+
+# look for function headers:
+{
+	gotstart = 0;
+	if ($0 ~ /^[A-Za-z_][A-Za-z0-9_]+/) {
+	gotstart = 1;
+	}
+	if(!gotstart) {
+		next;
+	}
+}
+
+/[_A-Za-z0-9]+[ \t]*[(].*[)][^()]*;[ \t]*$/ {
+	sub(/[(].*$/, "");
+	gsub(/[^ \t]+[ \t]+/, "");
+	gsub(/^[*]+/, "");
+	printf "\t\t%s;\n",$0;
+	next;
+}
+
+/[_A-Za-z0-9]+[ \t]*[(]/ {
+	inheader=1;
+	sub(/[(].*$/, "");
+	gsub(/[^ \t]+[ \t]+/, "");
+	gsub(/^[*]/, "");
+	printf "\t\t%s;\n",$0;
+	next;
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.sh
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,45 @@
+#! /bin/sh
+
+#
+# mksyms.sh
+#
+# Extract symbols to export from C-header files.
+# output in version-script format for linking shared libraries.
+#
+# This is the shell wrapper for the mksyms.awk core script.
+#
+# Copyright (C) 2008 Michael Adam <obnox at samba.org>
+#
+
+LANG=C; export LANG
+LC_ALL=C; export LC_ALL
+LC_COLLATE=C; export LC_COLLATE
+
+if [ $# -lt 2 ]
+then
+  echo "Usage: $0 awk output_file header_files"
+  exit 1
+fi
+
+awk="$1"
+shift
+
+symsfile="$1"
+shift
+symsfile_tmp="$symsfile.$$.tmp~"
+
+proto_src="`echo $@ | tr ' ' '\n' | sort | uniq `"
+
+echo creating $symsfile
+
+mkdir -p `dirname $symsfile`
+
+${awk} -f `dirname $0`/mksyms.awk $proto_src > $symsfile_tmp
+
+if cmp -s $symsfile $symsfile_tmp 2>/dev/null
+then
+  echo "$symsfile unchanged"
+  rm $symsfile_tmp
+else
+  mv $symsfile_tmp $symsfile
+fi


Property changes on: branches/ctdb/squeeze-backports/lib/tevent/script/mksyms.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/lib/tevent/testsuite.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/testsuite.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/testsuite.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,160 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   testing of the events subsystem
+
+   Copyright (C) Stefan Metzmacher 2006-2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "system/filesys.h"
+#include "torture/torture.h"
+
+static int fde_count;
+
+static void fde_handler(struct tevent_context *ev_ctx, struct tevent_fd *f,
+			uint16_t flags, void *private_data)
+{
+	int *fd = (int *)private_data;
+	char c;
+#ifdef SA_SIGINFO
+	kill(getpid(), SIGUSR1);
+#endif
+	kill(getpid(), SIGALRM);
+	read(fd[0], &c, 1);
+	write(fd[1], &c, 1);
+	fde_count++;
+}
+
+static void finished_handler(struct tevent_context *ev_ctx, struct tevent_timer *te,
+			     struct timeval tval, void *private_data)
+{
+	int *finished = (int *)private_data;
+	(*finished) = 1;
+}
+
+static void count_handler(struct tevent_context *ev_ctx, struct signal_event *te,
+			  int signum, int count, void *info, void *private_data)
+{
+	int *countp = (int *)private_data;
+	(*countp) += count;
+}
+
+static bool test_event_context(struct torture_context *test,
+			       const void *test_data)
+{
+	struct tevent_context *ev_ctx;
+	int fd[2] = { -1, -1 };
+	const char *backend = (const char *)test_data;
+	int alarm_count=0, info_count=0;
+	struct tevent_fd *fde;
+#ifdef SA_RESTART
+	struct tevent_signal *se1 = NULL;
+#endif
+	struct tevent_signal *se2 = NULL;
+#ifdef SA_SIGINFO
+	struct tevent_signal *se3 = NULL;
+#endif
+	int finished=0;
+	struct timeval t;
+	char c = 0;
+
+	ev_ctx = event_context_init_byname(test, backend);
+	if (ev_ctx == NULL) {
+		torture_comment(test, "event backend '%s' not supported\n", backend);
+		return true;
+	}
+
+	torture_comment(test, "Testing event backend '%s'\n", backend);
+
+	/* reset globals */
+	fde_count = 0;
+
+	/* create a pipe */
+	pipe(fd);
+
+	fde = event_add_fd(ev_ctx, ev_ctx, fd[0], EVENT_FD_READ,
+			   fde_handler, fd);
+	tevent_fd_set_auto_close(fde);
+
+	event_add_timed(ev_ctx, ev_ctx, timeval_current_ofs(2,0),
+			finished_handler, &finished);
+
+#ifdef SA_RESTART
+	se1 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count);
+#endif
+	se2 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count);
+#ifdef SA_SIGINFO
+	se3 = event_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count);
+#endif
+
+	write(fd[1], &c, 1);
+
+	t = timeval_current();
+	while (!finished) {
+		errno = 0;
+		if (event_loop_once(ev_ctx) == -1) {
+			talloc_free(ev_ctx);
+			torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno)));
+		}
+	}
+
+	talloc_free(fde);
+	close(fd[1]);
+
+	while (alarm_count < fde_count+1) {
+		if (event_loop_once(ev_ctx) == -1) {
+			break;
+		}
+	}
+
+	torture_comment(test, "Got %.2f pipe events/sec\n", fde_count/timeval_elapsed(&t));
+
+#ifdef SA_RESTART
+	talloc_free(se1);
+#endif
+
+	torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch");
+
+#ifdef SA_SIGINFO
+	talloc_free(se3);
+	torture_assert_int_equal(test, info_count, fde_count, "info count mismatch");
+#endif
+
+	talloc_free(ev_ctx);
+
+	return true;
+}
+
+struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
+{
+	struct torture_suite *suite = torture_suite_create(mem_ctx, "EVENT");
+	const char **list = event_backend_list(suite);
+	int i;
+
+	for (i=0;list && list[i];i++) {
+		torture_suite_add_simple_tcase_const(suite, list[i],
+					       test_event_context,
+					       (const void *)list[i]);
+	}
+
+	return suite;
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,635 @@
+/*
+   Unix SMB/CIFS implementation.
+   main select loop and event handling
+   Copyright (C) Andrew Tridgell 2003
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  PLEASE READ THIS BEFORE MODIFYING!
+
+  This module is a general abstraction for the main select loop and
+  event handling. Do not ever put any localised hacks in here, instead
+  register one of the possible event types and implement that event
+  somewhere else.
+
+  There are 2 types of event handling that are handled in this module:
+
+  1) a file descriptor becoming readable or writeable. This is mostly
+     used for network sockets, but can be used for any type of file
+     descriptor. You may only register one handler for each file
+     descriptor/io combination or you will get unpredictable results
+     (this means that you can have a handler for read events, and a
+     separate handler for write events, but not two handlers that are
+     both handling read events)
+
+  2) a timed event. You can register an event that happens at a
+     specific time.  You can register as many of these as you
+     like. They are single shot - add a new timed event in the event
+     handler to get another event.
+
+  To setup a set of events you first need to create a event_context
+  structure using the function tevent_context_init(); This returns a
+  'struct tevent_context' that you use in all subsequent calls.
+
+  After that you can add/remove events that you are interested in
+  using tevent_add_*() and talloc_free()
+
+  Finally, you call tevent_loop_wait_once() to block waiting for one of the
+  events to occor or tevent_loop_wait() which will loop
+  forever.
+
+*/
+#include "replace.h"
+#include "system/filesys.h"
+#define TEVENT_DEPRECATED 1
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+/* needed for the special ctdbd "track if time jumps unexpectedly */
+#include <time.h>
+
+struct tevent_ops_list {
+	struct tevent_ops_list *next, *prev;
+	const char *name;
+	const struct tevent_ops *ops;
+};
+
+/* list of registered event backends */
+static struct tevent_ops_list *tevent_backends = NULL;
+static char *tevent_default_backend = NULL;
+
+/*
+  register an events backend
+*/
+bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
+{
+	struct tevent_ops_list *e;
+
+	for (e = tevent_backends; e != NULL; e = e->next) {
+		if (0 == strcmp(e->name, name)) {
+			/* already registered, skip it */
+			return true;
+		}
+	}
+
+	e = talloc(talloc_autofree_context(), struct tevent_ops_list);
+	if (e == NULL) return false;
+
+	e->name = name;
+	e->ops = ops;
+	DLIST_ADD(tevent_backends, e);
+
+	return true;
+}
+
+/*
+  set the default event backend
+ */
+void tevent_set_default_backend(const char *backend)
+{
+	talloc_free(tevent_default_backend);
+	tevent_default_backend = talloc_strdup(talloc_autofree_context(),
+					       backend);
+}
+
+/*
+  initialise backends if not already done
+*/
+static void tevent_backend_init(void)
+{
+	tevent_select_init();
+	tevent_standard_init();
+#ifdef HAVE_EPOLL
+	tevent_epoll_init();
+#endif
+}
+
+/*
+  list available backends
+*/
+const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
+{
+	const char **list = NULL;
+	struct tevent_ops_list *e;
+
+	tevent_backend_init();
+
+	for (e=tevent_backends;e;e=e->next) {
+		list = ev_str_list_add(list, e->name);
+	}
+
+	talloc_steal(mem_ctx, list);
+
+	return list;
+}
+
+int tevent_common_context_destructor(struct tevent_context *ev)
+{
+	struct tevent_fd *fd, *fn;
+	struct tevent_timer *te, *tn;
+	struct tevent_immediate *ie, *in;
+	struct tevent_signal *se, *sn;
+
+	if (ev->pipe_fde) {
+		talloc_free(ev->pipe_fde);
+		close(ev->pipe_fds[0]);
+		close(ev->pipe_fds[1]);
+		ev->pipe_fde = NULL;
+	}
+
+	for (fd = ev->fd_events; fd; fd = fn) {
+		fn = fd->next;
+		fd->event_ctx = NULL;
+		DLIST_REMOVE(ev->fd_events, fd);
+	}
+
+	for (te = ev->timer_events; te; te = tn) {
+		tn = te->next;
+		te->event_ctx = NULL;
+		DLIST_REMOVE(ev->timer_events, te);
+	}
+
+	for (ie = ev->immediate_events; ie; ie = in) {
+		in = ie->next;
+		ie->event_ctx = NULL;
+		ie->cancel_fn = NULL;
+		DLIST_REMOVE(ev->immediate_events, ie);
+	}
+
+	for (se = ev->signal_events; se; se = sn) {
+		sn = se->next;
+		se->event_ctx = NULL;
+		DLIST_REMOVE(ev->signal_events, se);
+		/*
+		 * This is important, Otherwise signals
+		 * are handled twice in child. eg, SIGHUP.
+		 * one added in parent, and another one in
+		 * the child. -- BoYang
+		 */
+		tevent_cleanup_pending_signal_handlers(se);
+	}
+
+	return 0;
+}
+
+/*
+  create a event_context structure for a specific implemementation.
+  This must be the first events call, and all subsequent calls pass
+  this event_context as the first element. Event handlers also
+  receive this as their first argument.
+
+  This function is for allowing third-party-applications to hook in gluecode
+  to their own event loop code, so that they can make async usage of our client libs
+
+  NOTE: use tevent_context_init() inside of samba!
+*/
+static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
+						      const struct tevent_ops *ops)
+{
+	struct tevent_context *ev;
+	int ret;
+
+	ev = talloc_zero(mem_ctx, struct tevent_context);
+	if (!ev) return NULL;
+
+	talloc_set_destructor(ev, tevent_common_context_destructor);
+
+	ev->ops = ops;
+
+	ret = ev->ops->context_init(ev);
+	if (ret != 0) {
+		talloc_free(ev);
+		return NULL;
+	}
+
+	return ev;
+}
+
+/*
+  create a event_context structure. This must be the first events
+  call, and all subsequent calls pass this event_context as the first
+  element. Event handlers also receive this as their first argument.
+*/
+struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
+						  const char *name)
+{
+	struct tevent_ops_list *e;
+
+	tevent_backend_init();
+
+	if (name == NULL) {
+		name = tevent_default_backend;
+	}
+	if (name == NULL) {
+		name = "standard";
+	}
+
+	for (e=tevent_backends;e;e=e->next) {
+		if (strcmp(name, e->name) == 0) {
+			return tevent_context_init_ops(mem_ctx, e->ops);
+		}
+	}
+	return NULL;
+}
+
+
+/*
+  create a event_context structure. This must be the first events
+  call, and all subsequent calls pass this event_context as the first
+  element. Event handlers also receive this as their first argument.
+*/
+struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
+{
+	return tevent_context_init_byname(mem_ctx, NULL);
+}
+
+/*
+  add a fd based event
+  return NULL on failure (memory allocation error)
+*/
+struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
+				 TALLOC_CTX *mem_ctx,
+				 int fd,
+				 uint16_t flags,
+				 tevent_fd_handler_t handler,
+				 void *private_data,
+				 const char *handler_name,
+				 const char *location)
+{
+	return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
+			       handler_name, location);
+}
+
+/*
+  set a close function on the fd event
+*/
+void tevent_fd_set_close_fn(struct tevent_fd *fde,
+			    tevent_fd_close_fn_t close_fn)
+{
+	if (!fde) return;
+	if (!fde->event_ctx) return;
+	fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
+}
+
+static void tevent_fd_auto_close_fn(struct tevent_context *ev,
+				    struct tevent_fd *fde,
+				    int fd,
+				    void *private_data)
+{
+	close(fd);
+}
+
+void tevent_fd_set_auto_close(struct tevent_fd *fde)
+{
+	tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
+}
+
+/*
+  return the fd event flags
+*/
+uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
+{
+	if (!fde) return 0;
+	if (!fde->event_ctx) return 0;
+	return fde->event_ctx->ops->get_fd_flags(fde);
+}
+
+/*
+  set the fd event flags
+*/
+void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
+{
+	if (!fde) return;
+	if (!fde->event_ctx) return;
+	fde->event_ctx->ops->set_fd_flags(fde, flags);
+}
+
+bool tevent_signal_support(struct tevent_context *ev)
+{
+	if (ev->ops->add_signal) {
+		return true;
+	}
+	return false;
+}
+
+static void (*tevent_abort_fn)(const char *reason);
+
+void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+	tevent_abort_fn = abort_fn;
+}
+
+static void tevent_abort(struct tevent_context *ev, const char *reason)
+{
+	tevent_debug(ev, TEVENT_DEBUG_FATAL,
+		     "abort: %s\n", reason);
+
+	if (!tevent_abort_fn) {
+		abort();
+	}
+
+	tevent_abort_fn(reason);
+}
+
+/*
+  add a timer event
+  return NULL on failure
+*/
+struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
+				       TALLOC_CTX *mem_ctx,
+				       struct timeval next_event,
+				       tevent_timer_handler_t handler,
+				       void *private_data,
+				       const char *handler_name,
+				       const char *location)
+{
+	return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
+				  handler_name, location);
+}
+
+/*
+  allocate an immediate event
+  return NULL on failure (memory allocation error)
+*/
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+						  const char *location)
+{
+	struct tevent_immediate *im;
+
+	im = talloc(mem_ctx, struct tevent_immediate);
+	if (im == NULL) return NULL;
+
+	im->prev		= NULL;
+	im->next		= NULL;
+	im->event_ctx		= NULL;
+	im->create_location	= location;
+	im->handler		= NULL;
+	im->private_data	= NULL;
+	im->handler_name	= NULL;
+	im->schedule_location	= NULL;
+	im->cancel_fn		= NULL;
+	im->additional_data	= NULL;
+
+	return im;
+}
+
+/*
+  schedule an immediate event
+  return NULL on failure
+*/
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+				struct tevent_context *ev,
+				tevent_immediate_handler_t handler,
+				void *private_data,
+				const char *handler_name,
+				const char *location)
+{
+	ev->ops->schedule_immediate(im, ev, handler, private_data,
+				    handler_name, location);
+}
+
+/*
+  add a signal event
+
+  sa_flags are flags to sigaction(2)
+
+  return NULL on failure
+*/
+struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
+					 TALLOC_CTX *mem_ctx,
+					 int signum,
+					 int sa_flags,
+					 tevent_signal_handler_t handler,
+					 void *private_data,
+					 const char *handler_name,
+					 const char *location)
+{
+	return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
+				   handler_name, location);
+}
+
+void tevent_loop_allow_nesting(struct tevent_context *ev)
+{
+	ev->nesting.allowed = true;
+}
+
+void tevent_loop_set_nesting_hook(struct tevent_context *ev,
+				  tevent_nesting_hook hook,
+				  void *private_data)
+{
+	if (ev->nesting.hook_fn &&
+	    (ev->nesting.hook_fn != hook ||
+	     ev->nesting.hook_private != private_data)) {
+		/* the way the nesting hook code is currently written
+		   we cannot support two different nesting hooks at the
+		   same time. */
+		tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
+	}
+	ev->nesting.hook_fn = hook;
+	ev->nesting.hook_private = private_data;
+}
+
+static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
+{
+	const char *reason;
+
+	reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
+				 location);
+	if (!reason) {
+		reason = "tevent_loop_once() nesting";
+	}
+
+	tevent_abort(ev, reason);
+}
+
+/*
+  do a single event loop using the events defined in ev
+*/
+int _tevent_loop_once(struct tevent_context *ev, const char *location)
+{
+	int ret;
+	void *nesting_stack_ptr = NULL;
+
+	ev->nesting.level++;
+
+	if (ev->nesting.level > 1) {
+		if (!ev->nesting.allowed) {
+			tevent_abort_nesting(ev, location);
+			errno = ELOOP;
+			return -1;
+		}
+	}
+	if (ev->nesting.level > 0) {
+		if (ev->nesting.hook_fn) {
+			int ret2;
+			ret2 = ev->nesting.hook_fn(ev,
+						   ev->nesting.hook_private,
+						   ev->nesting.level,
+						   true,
+						   (void *)&nesting_stack_ptr,
+						   location);
+			if (ret2 != 0) {
+				ret = ret2;
+				goto done;
+			}
+		}
+	}
+
+	ret = ev->ops->loop_once(ev, location);
+
+	if (ev->nesting.level > 0) {
+		if (ev->nesting.hook_fn) {
+			int ret2;
+			ret2 = ev->nesting.hook_fn(ev,
+						   ev->nesting.hook_private,
+						   ev->nesting.level,
+						   false,
+						   (void *)&nesting_stack_ptr,
+						   location);
+			if (ret2 != 0) {
+				ret = ret2;
+				goto done;
+			}
+		}
+	}
+
+done:
+	ev->nesting.level--;
+	return ret;
+}
+
+/*
+  this is a performance optimization for the samba4 nested event loop problems
+*/
+int _tevent_loop_until(struct tevent_context *ev,
+		       bool (*finished)(void *private_data),
+		       void *private_data,
+		       const char *location)
+{
+	int ret = 0;
+	void *nesting_stack_ptr = NULL;
+
+	ev->nesting.level++;
+
+	if (ev->nesting.level > 1) {
+		if (!ev->nesting.allowed) {
+			tevent_abort_nesting(ev, location);
+			errno = ELOOP;
+			return -1;
+		}
+	}
+	if (ev->nesting.level > 0) {
+		if (ev->nesting.hook_fn) {
+			int ret2;
+			ret2 = ev->nesting.hook_fn(ev,
+						   ev->nesting.hook_private,
+						   ev->nesting.level,
+						   true,
+						   (void *)&nesting_stack_ptr,
+						   location);
+			if (ret2 != 0) {
+				ret = ret2;
+				goto done;
+			}
+		}
+	}
+
+	while (!finished(private_data)) {
+		ret = ev->ops->loop_once(ev, location);
+		if (ret != 0) {
+			break;
+		}
+	}
+
+	if (ev->nesting.level > 0) {
+		if (ev->nesting.hook_fn) {
+			int ret2;
+			ret2 = ev->nesting.hook_fn(ev,
+						   ev->nesting.hook_private,
+						   ev->nesting.level,
+						   false,
+						   (void *)&nesting_stack_ptr,
+						   location);
+			if (ret2 != 0) {
+				ret = ret2;
+				goto done;
+			}
+		}
+	}
+
+done:
+	ev->nesting.level--;
+	return ret;
+}
+
+
+/*
+  return on failure or (with 0) if all fd events are removed
+*/
+int tevent_common_loop_wait(struct tevent_context *ev,
+			    const char *location)
+{
+
+	/*
+	 * loop as long as we have events pending
+	 */
+	while (ev->fd_events ||
+	       ev->timer_events ||
+	       ev->immediate_events ||
+	       ev->signal_events) {
+		int ret;
+		ret = _tevent_loop_once(ev, location);
+		if (ret != 0) {
+			tevent_debug(ev, TEVENT_DEBUG_FATAL,
+				     "_tevent_loop_once() failed: %d - %s\n",
+				     ret, strerror(errno));
+			return ret;
+		}
+	}
+
+	tevent_debug(ev, TEVENT_DEBUG_WARNING,
+		     "tevent_common_loop_wait() out of events\n");
+	return 0;
+}
+
+/*
+  return on failure or (with 0) if all fd events are removed
+*/
+int _tevent_loop_wait(struct tevent_context *ev, const char *location)
+{
+	return ev->ops->loop_wait(ev, location);
+}
+
+
+/*
+  re-initialise a tevent context. This leaves you with the same
+  event context, but all events are wiped and the structure is
+  re-initialised. This is most useful after a fork()
+
+  zero is returned on success, non-zero on failure
+*/
+int tevent_re_initialise(struct tevent_context *ev)
+{
+	tevent_common_context_destructor(ev);
+
+	return ev->ops->context_init(ev);
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent.exports
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent.exports	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent.exports	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,62 @@
+{
+    global:
+           _tevent_add_fd;
+           _tevent_add_signal;
+           _tevent_add_timer;
+           tevent_backend_list;
+           tevent_context_init;
+           tevent_context_init_byname;
+           _tevent_create_immediate;
+           tevent_fd_get_flags;
+           tevent_fd_set_auto_close;
+           tevent_fd_set_close_fn;
+           tevent_fd_set_flags;
+           tevent_loop_allow_nesting;
+           _tevent_loop_once;
+           tevent_loop_set_nesting_hook;
+           _tevent_loop_until;
+           _tevent_loop_wait;
+           tevent_queue_add;
+           _tevent_queue_create;
+           tevent_queue_length;
+           tevent_queue_start;
+           tevent_queue_stop;
+           tevent_register_backend;
+           _tevent_req_callback_data;
+           _tevent_req_create;
+           _tevent_req_data;
+           tevent_req_default_print;
+           _tevent_req_done;
+           _tevent_req_error;
+           tevent_req_is_error;
+           tevent_req_is_in_progress;
+           _tevent_req_nomem;
+           _tevent_req_notify_callback;
+           tevent_req_poll;
+           tevent_req_post;
+           tevent_req_print;
+           tevent_req_received;
+           tevent_req_set_callback;
+           tevent_req_set_endtime;
+           tevent_req_set_print_fn;
+           _tevent_schedule_immediate;
+           tevent_set_abort_fn;
+           tevent_set_debug;
+           tevent_set_debug_stderr;
+           tevent_set_default_backend;
+           tevent_signal_support;
+           tevent_timeval_add;
+           tevent_timeval_compare;
+           tevent_timeval_current;
+           tevent_timeval_current_ofs;
+           tevent_timeval_is_zero;
+           tevent_timeval_set;
+           tevent_timeval_until;
+           tevent_timeval_zero;
+           tevent_wakeup_recv;
+           tevent_wakeup_send;
+           _tevent_req_cancel;
+           tevent_req_set_cancel_fn;
+
+    local: *;
+};

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1441 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   generalised event loop handling
+
+   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Stefan Metzmacher 2005-2009
+   Copyright (C) Volker Lendecke 2008
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TEVENT_H__
+#define __TEVENT_H__
+
+#define TEVENT_DEPRECATED
+
+#include <stdint.h>
+#include <talloc.h>
+#include <sys/time.h>
+#include <stdbool.h>
+
+struct tevent_context;
+struct tevent_ops;
+struct tevent_fd;
+struct tevent_timer;
+struct tevent_immediate;
+struct tevent_signal;
+
+/**
+ * @defgroup tevent The tevent API
+ *
+ * The tevent low-level API
+ *
+ * This API provides the public interface to manage events in the tevent
+ * mainloop. Functions are provided for managing low-level events such
+ * as timer events, fd events and signal handling.
+ *
+ * @{
+ */
+
+/* event handler types */
+/**
+ * Called when a file descriptor monitored by tevent has
+ * data to be read or written on it.
+ */
+typedef void (*tevent_fd_handler_t)(struct tevent_context *ev,
+				    struct tevent_fd *fde,
+				    uint16_t flags,
+				    void *private_data);
+
+/**
+ * Called when tevent is ceasing the monitoring of a file descriptor.
+ */
+typedef void (*tevent_fd_close_fn_t)(struct tevent_context *ev,
+				     struct tevent_fd *fde,
+				     int fd,
+				     void *private_data);
+
+/**
+ * Called when a tevent timer has fired.
+ */
+typedef void (*tevent_timer_handler_t)(struct tevent_context *ev,
+				       struct tevent_timer *te,
+				       struct timeval current_time,
+				       void *private_data);
+
+/**
+ * Called when a tevent immediate event is invoked.
+ */
+typedef void (*tevent_immediate_handler_t)(struct tevent_context *ctx,
+					   struct tevent_immediate *im,
+					   void *private_data);
+
+/**
+ * Called after tevent detects the specified signal.
+ */
+typedef void (*tevent_signal_handler_t)(struct tevent_context *ev,
+					struct tevent_signal *se,
+					int signum,
+					int count,
+					void *siginfo,
+					void *private_data);
+
+/**
+ * @brief Create a event_context structure.
+ *
+ * This must be the first events call, and all subsequent calls pass this
+ * event_context as the first element. Event handlers also receive this as
+ * their first argument.
+ *
+ * @param[in]  mem_ctx  The memory context to use.
+ *
+ * @return              An allocated tevent context, NULL on error.
+ *
+ * @see tevent_context_init()
+ */
+struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Create a event_context structure and name it.
+ *
+ * This must be the first events call, and all subsequent calls pass this
+ * event_context as the first element. Event handlers also receive this as
+ * their first argument.
+ *
+ * @param[in]  mem_ctx  The memory context to use.
+ *
+ * @param[in]  name     The name for the tevent context.
+ *
+ * @return              An allocated tevent context, NULL on error.
+ */
+struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx, const char *name);
+
+/**
+ * @brief List available backends.
+ *
+ * @param[in]  mem_ctx  The memory context to use.
+ *
+ * @return              A string vector with a terminating NULL element, NULL
+ *                      on error.
+ */
+const char **tevent_backend_list(TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Set the default tevent backent.
+ *
+ * @param[in]  backend  The name of the backend to set.
+ */
+void tevent_set_default_backend(const char *backend);
+
+#ifdef DOXYGEN
+/**
+ * @brief Add a file descriptor based event.
+ *
+ * @param[in]  ev       The event context to work on.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to use.
+ *
+ * @param[in]  fd       The file descriptor to base the event on.
+ *
+ * @param[in]  flags    #TEVENT_FD_READ or #TEVENT_FD_WRITE
+ *
+ * @param[in]  handler  The callback handler for the event.
+ *
+ * @param[in]  private_data  The private data passed to the callback handler.
+ *
+ * @return              The file descriptor based event, NULL on error.
+ *
+ * @note To cancel the monitoring of a file descriptor, call talloc_free()
+ * on the object returned by this function.
+ */
+struct tevent_fd *tevent_add_fd(struct tevent_context *ev,
+				TALLOC_CTX *mem_ctx,
+				int fd,
+				uint16_t flags,
+				tevent_fd_handler_t handler,
+				void *private_data);
+#else
+struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
+				 TALLOC_CTX *mem_ctx,
+				 int fd,
+				 uint16_t flags,
+				 tevent_fd_handler_t handler,
+				 void *private_data,
+				 const char *handler_name,
+				 const char *location);
+#define tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data) \
+	_tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data, \
+		       #handler, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Add a timed event
+ *
+ * @param[in]  ev       The event context to work on.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to use.
+ *
+ * @param[in]  next_event  Timeval specifying the absolute time to fire this
+ * event. This is not an offset.
+ *
+ * @param[in]  handler  The callback handler for the event.
+ *
+ * @param[in]  private_data  The private data passed to the callback handler.
+ *
+ * @return The newly-created timer event, or NULL on error.
+ *
+ * @note To cancel a timer event before it fires, call talloc_free() on the
+ * event returned from this function. This event is automatically
+ * talloc_free()-ed after its event handler files, if it hasn't been freed yet.
+ *
+ * @note Unlike some mainloops, tevent timers are one-time events. To set up
+ * a recurring event, it is necessary to call tevent_add_timer() again during
+ * the handler processing.
+ *
+ * @note Due to the internal mainloop processing, a timer set to run
+ * immediately will do so after any other pending timers fire, but before
+ * any further file descriptor or signal handling events fire. Callers should
+ * not rely on this behavior!
+ */
+struct tevent_timer *tevent_add_timer(struct tevent_context *ev,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct timeval next_event,
+                                      tevent_timer_handler_t handler,
+                                      void *private_data);
+#else
+struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
+				       TALLOC_CTX *mem_ctx,
+				       struct timeval next_event,
+				       tevent_timer_handler_t handler,
+				       void *private_data,
+				       const char *handler_name,
+				       const char *location);
+#define tevent_add_timer(ev, mem_ctx, next_event, handler, private_data) \
+	_tevent_add_timer(ev, mem_ctx, next_event, handler, private_data, \
+			  #handler, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * Initialize an immediate event object
+ *
+ * This object can be used to trigger an event to occur immediately after
+ * returning from the current event (before any other event occurs)
+ *
+ * @param[in] mem_ctx  The talloc memory context to use as the parent
+ *
+ * @return An empty tevent_immediate object. Use tevent_schedule_immediate
+ * to populate and use it.
+ *
+ * @note Available as of tevent 0.9.8
+ */
+struct tevent_immediate *tevent_create_immediate(TALLOC_CTX *mem_ctx);
+#else
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+						  const char *location);
+#define tevent_create_immediate(mem_ctx) \
+	_tevent_create_immediate(mem_ctx, __location__)
+#endif
+
+#ifdef DOXYGEN
+
+/**
+ * Schedule an event for immediate execution. This event will occur
+ * immediately after returning from the current event (before any other
+ * event occurs)
+ *
+ * @param[in] im       The tevent_immediate object to populate and use
+ * @param[in] ctx      The tevent_context to run this event
+ * @param[in] handler  The event handler to run when this event fires
+ * @param[in] private_data  Data to pass to the event handler
+ */
+void tevent_schedule_immediate(struct tevent_immediate *im,
+                struct tevent_context *ctx,
+                tevent_immediate_handler_t handler,
+                void *private_data);
+#else
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+				struct tevent_context *ctx,
+				tevent_immediate_handler_t handler,
+				void *private_data,
+				const char *handler_name,
+				const char *location);
+#define tevent_schedule_immediate(im, ctx, handler, private_data) \
+	_tevent_schedule_immediate(im, ctx, handler, private_data, \
+				   #handler, __location__);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Add a tevent signal handler
+ *
+ * tevent_add_signal() creates a new event for handling a signal the next
+ * time through the mainloop. It implements a very simple traditional signal
+ * handler whose only purpose is to add the handler event into the mainloop.
+ *
+ * @param[in]  ev       The event context to work on.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to use.
+ *
+ * @param[in]  signum   The signal to trap
+ *
+ * @param[in]  handler  The callback handler for the signal.
+ *
+ * @param[in]  sa_flags sigaction flags for this signal handler.
+ *
+ * @param[in]  private_data  The private data passed to the callback handler.
+ *
+ * @return The newly-created signal handler event, or NULL on error.
+ *
+ * @note To cancel a signal handler, call talloc_free() on the event returned
+ * from this function.
+ */
+struct tevent_signal *tevent_add_signal(struct tevent_context *ev,
+                     TALLOC_CTX *mem_ctx,
+                     int signum,
+                     int sa_flags,
+                     tevent_signal_handler_t handler,
+                     void *private_data);
+#else
+struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
+					 TALLOC_CTX *mem_ctx,
+					 int signum,
+					 int sa_flags,
+					 tevent_signal_handler_t handler,
+					 void *private_data,
+					 const char *handler_name,
+					 const char *location);
+#define tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data) \
+	_tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data, \
+			   #handler, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Pass a single time through the mainloop
+ *
+ * This will process any appropriate signal, immediate, fd and timer events
+ *
+ * @param[in]  ev The event context to process
+ *
+ * @return Zero on success, nonzero if an internal error occurred
+ */
+int tevent_loop_once(struct tevent_context *ev);
+#else
+int _tevent_loop_once(struct tevent_context *ev, const char *location);
+#define tevent_loop_once(ev) \
+	_tevent_loop_once(ev, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Run the mainloop
+ *
+ * The mainloop will run until there are no events remaining to be processed
+ *
+ * @param[in]  ev The event context to process
+ *
+ * @return Zero if all events have been processed. Nonzero if an internal
+ * error occurred.
+ */
+int tevent_loop_wait(struct tevent_context *ev);
+#else
+int _tevent_loop_wait(struct tevent_context *ev, const char *location);
+#define tevent_loop_wait(ev) \
+	_tevent_loop_wait(ev, __location__)
+#endif
+
+
+/**
+ * Assign a function to run when a tevent_fd is freed
+ *
+ * This function is a destructor for the tevent_fd. It does not automatically
+ * close the file descriptor. If this is the desired behavior, then it must be
+ * performed by the close_fn.
+ *
+ * @param[in] fde       File descriptor event on which to set the destructor
+ * @param[in] close_fn  Destructor to execute when fde is freed
+ */
+void tevent_fd_set_close_fn(struct tevent_fd *fde,
+			    tevent_fd_close_fn_t close_fn);
+
+/**
+ * Automatically close the file descriptor when the tevent_fd is freed
+ *
+ * This function calls close(fd) internally.
+ *
+ * @param[in] fde  File descriptor event to auto-close
+ */
+void tevent_fd_set_auto_close(struct tevent_fd *fde);
+
+/**
+ * Return the flags set on this file descriptor event
+ *
+ * @param[in] fde  File descriptor event to query
+ *
+ * @return The flags set on the event. See #TEVENT_FD_READ and
+ * #TEVENT_FD_WRITE
+ */
+uint16_t tevent_fd_get_flags(struct tevent_fd *fde);
+
+/**
+ * Set flags on a file descriptor event
+ *
+ * @param[in] fde    File descriptor event to set
+ * @param[in] flags  Flags to set on the event. See #TEVENT_FD_READ and
+ * #TEVENT_FD_WRITE
+ */
+void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+
+/**
+ * Query whether tevent supports signal handling
+ *
+ * @param[in] ev  An initialized tevent context
+ *
+ * @return True if this platform and tevent context support signal handling
+ */
+bool tevent_signal_support(struct tevent_context *ev);
+
+void tevent_set_abort_fn(void (*abort_fn)(const char *reason));
+
+/* bits for file descriptor event flags */
+
+/**
+ * Monitor a file descriptor for write availability
+ */
+#define TEVENT_FD_READ 1
+/**
+ * Monitor a file descriptor for data to be read
+ */
+#define TEVENT_FD_WRITE 2
+
+/**
+ * Convenience function for declaring a tevent_fd writable
+ */
+#define TEVENT_FD_WRITEABLE(fde) \
+	tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_WRITE)
+
+/**
+ * Convenience function for declaring a tevent_fd readable
+ */
+#define TEVENT_FD_READABLE(fde) \
+	tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_READ)
+
+/**
+ * Convenience function for declaring a tevent_fd non-writable
+ */
+#define TEVENT_FD_NOT_WRITEABLE(fde) \
+	tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_WRITE)
+
+/**
+ * Convenience function for declaring a tevent_fd non-readable
+ */
+#define TEVENT_FD_NOT_READABLE(fde) \
+	tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_READ)
+
+/**
+ * Debug level of tevent
+ */
+enum tevent_debug_level {
+	TEVENT_DEBUG_FATAL,
+	TEVENT_DEBUG_ERROR,
+	TEVENT_DEBUG_WARNING,
+	TEVENT_DEBUG_TRACE
+};
+
+/**
+ * @brief The tevent debug callbac.
+ *
+ * @param[in]  context  The memory context to use.
+ *
+ * @param[in]  level    The debug level.
+ *
+ * @param[in]  fmt      The format string.
+ *
+ * @param[in]  ap       The arguments for the format string.
+ */
+typedef void (*tevent_debug_fn)(void *context,
+				enum tevent_debug_level level,
+				const char *fmt,
+				va_list ap) PRINTF_ATTRIBUTE(3,0);
+
+/**
+ * Set destination for tevent debug messages
+ *
+ * @param[in] ev        Event context to debug
+ * @param[in] debug     Function to handle output printing
+ * @param[in] context   The context to pass to the debug function.
+ *
+ * @return Always returns 0 as of version 0.9.8
+ *
+ * @note Default is to emit no debug messages
+ */
+int tevent_set_debug(struct tevent_context *ev,
+		     tevent_debug_fn debug,
+		     void *context);
+
+/**
+ * Designate stderr for debug message output
+ *
+ * @param[in] ev     Event context to debug
+ *
+ * @note This function will only output TEVENT_DEBUG_FATAL, TEVENT_DEBUG_ERROR
+ * and TEVENT_DEBUG_WARNING messages. For TEVENT_DEBUG_TRACE, please define a
+ * function for tevent_set_debug()
+ */
+int tevent_set_debug_stderr(struct tevent_context *ev);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup tevent_request The tevent request functions.
+ * @ingroup tevent
+ *
+ * This represents an async request being processed by callbacks via an event
+ * context. A user can issue for example a write request to a socket, giving
+ * an implementation function the fd, the buffer and the number of bytes to
+ * transfer. The function issuing the request will immediately return without
+ * blocking most likely without having sent anything. The API user then fills
+ * in req->async.fn and req->async.private_data, functions that are called
+ * when the request is finished.
+ *
+ * It is up to the user of the async request to talloc_free it after it has
+ * finished. This can happen while the completion function is called.
+ *
+ * @{
+ */
+
+/**
+ * An async request moves between the following 4 states:
+ */
+enum tevent_req_state {
+	/**
+	 * we are creating the request
+	 */
+	TEVENT_REQ_INIT,
+	/**
+	 * we are waiting the request to complete
+	 */
+	TEVENT_REQ_IN_PROGRESS,
+	/**
+	 * the request is finished
+	 */
+	TEVENT_REQ_DONE,
+	/**
+	 * A user error has occurred
+	 */
+	TEVENT_REQ_USER_ERROR,
+	/**
+	 * Request timed out
+	 */
+	TEVENT_REQ_TIMED_OUT,
+	/**
+	 * No memory in between
+	 */
+	TEVENT_REQ_NO_MEMORY,
+	/**
+	 * the request is already received by the caller
+	 */
+	TEVENT_REQ_RECEIVED
+};
+
+/**
+ * @brief An async request
+ */
+struct tevent_req;
+
+/**
+ * @brief A tevent request callback function.
+ *
+ * @param[in]  req      The tevent async request which executed this callback.
+ */
+typedef void (*tevent_req_fn)(struct tevent_req *req);
+
+/**
+ * @brief Set an async request callback.
+ *
+ * @param[in]  req      The async request to set the callback.
+ *
+ * @param[in]  fn       The callback function to set.
+ *
+ * @param[in]  pvt      A pointer to private data to pass to the async request
+ *                      callback.
+ */
+void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt);
+
+#ifdef DOXYGEN
+/**
+ * @brief Get the private data casted to the given type for a callback from
+ *        a tevent request structure.
+ *
+ * @param[in]  req      The structure to get the callback data from.
+ *
+ * @param[in]  type     The type of the private callback data to get.
+ *
+ * @return              The type casted private data set NULL if not set.
+ */
+void *tevent_req_callback_data(struct tevent_req *req, #type);
+#else
+void *_tevent_req_callback_data(struct tevent_req *req);
+#define tevent_req_callback_data(_req, _type) \
+	talloc_get_type_abort(_tevent_req_callback_data(_req), _type)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Get the private data for a callback from a tevent request structure.
+ *
+ * @param[in]  req      The structure to get the callback data from.
+ *
+ * @param[in]  req      The structure to get the data from.
+ *
+ * @return              The private data or NULL if not set.
+ */
+void *tevent_req_callback_data_void(struct tevent_req *req);
+#else
+#define tevent_req_callback_data_void(_req) \
+	_tevent_req_callback_data(_req)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Get the private data from a tevent request structure.
+ *
+ * @param[in]  req      The structure to get the private data from.
+ *
+ * @return              The private data or NULL if not set.
+ */
+void *tevent_req_data(struct tevent_req *req);
+#else
+void *_tevent_req_data(struct tevent_req *req);
+#define tevent_req_data(_req, _type) \
+	talloc_get_type_abort(_tevent_req_data(_req), _type)
+#endif
+
+/**
+ * @brief The print function which can be set for a tevent async request.
+ *
+ * @param[in]  req      The tevent async request.
+ *
+ * @param[in]  ctx      A talloc memory context which can be uses to allocate
+ *                      memory.
+ *
+ * @return              An allocated string buffer to print.
+ *
+ * Example:
+ * @code
+ *   static char *my_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
+ *   {
+ *     struct my_data *data = tevent_req_data(req, struct my_data);
+ *     char *result;
+ *
+ *     result = tevent_req_default_print(mem_ctx, req);
+ *     if (result == NULL) {
+ *       return NULL;
+ *     }
+ *
+ *     return talloc_asprintf_append_buffer(result, "foo=%d, bar=%d",
+ *       data->foo, data->bar);
+ *   }
+ * @endcode
+ */
+typedef char *(*tevent_req_print_fn)(struct tevent_req *req, TALLOC_CTX *ctx);
+
+/**
+ * @brief This function sets a print function for the given request.
+ *
+ * This function can be used to setup a print function for the given request.
+ * This will be triggered if the tevent_req_print() function was
+ * called on the given request.
+ *
+ * @param[in]  req      The request to use.
+ *
+ * @param[in]  fn       A pointer to the print function
+ *
+ * @note This function should only be used for debugging.
+ */
+void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn);
+
+/**
+ * @brief The default print function for creating debug messages.
+ *
+ * The function should not be used by users of the async API,
+ * but custom print function can use it and append custom text
+ * to the string.
+ *
+ * @param[in]  req      The request to be printed.
+ *
+ * @param[in]  mem_ctx  The memory context for the result.
+ *
+ * @return              Text representation of request.
+ *
+ */
+char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Print an tevent_req structure in debug messages.
+ *
+ * This function should be used by callers of the async API.
+ *
+ * @param[in]  mem_ctx  The memory context for the result.
+ *
+ * @param[in] req       The request to be printed.
+ *
+ * @return              Text representation of request.
+ */
+char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req);
+
+/**
+ * @brief A typedef for a cancel function for a tevent request.
+ *
+ * @param[in]  req      The tevent request calling this function.
+ *
+ * @return              True if the request could be canceled, false if not.
+ */
+typedef bool (*tevent_req_cancel_fn)(struct tevent_req *req);
+
+/**
+ * @brief This function sets a cancel function for the given tevent request.
+ *
+ * This function can be used to setup a cancel function for the given request.
+ * This will be triggered if the tevent_req_cancel() function was
+ * called on the given request.
+ *
+ * @param[in]  req      The request to use.
+ *
+ * @param[in]  fn       A pointer to the cancel function.
+ */
+void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn);
+
+#ifdef DOXYGEN
+/**
+ * @brief Try to cancel the given tevent request.
+ *
+ * This function can be used to cancel the given request.
+ *
+ * It is only possible to cancel a request when the implementation
+ * has registered a cancel function via the tevent_req_set_cancel_fn().
+ *
+ * @param[in]  req      The request to use.
+ *
+ * @return              This function returns true is the request is cancelable,
+ *                      othererwise false is returned.
+ *
+ * @note Even if the function returns true, the caller need to wait
+ *       for the function to complete normally.
+ *       Only the _recv() function of the given request indicates
+ *       if the request was really canceled.
+ */
+bool tevent_req_cancel(struct tevent_req *req);
+#else
+bool _tevent_req_cancel(struct tevent_req *req, const char *location);
+#define tevent_req_cancel(req) \
+	_tevent_req_cancel(req, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Create an async tevent request.
+ *
+ * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS.
+ *
+ * @param[in] mem_ctx   The memory context for the result.
+ *
+ * @param[in] pstate    The private state of the request.
+ *
+ * @param[in] state_size  The size of the private state of the request.
+ *
+ * @param[in] type      The name of the request.
+ *
+ * @return              A new async request. NULL on error.
+ */
+struct tevent_req *tevent_req_create(TALLOC_CTX *mem_ctx,
+				      void *pstate,
+				      size_t state_size,
+				      const char *type);
+#else
+struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
+				      void *pstate,
+				      size_t state_size,
+				      const char *type,
+				      const char *location);
+
+#define tevent_req_create(_mem_ctx, _pstate, _type) \
+	_tevent_req_create((_mem_ctx), (_pstate), sizeof(_type), \
+			   #_type, __location__)
+#endif
+
+/**
+ * @brief Set a timeout for an async request.
+ *
+ * @param[in]  req      The request to set the timeout for.
+ *
+ * @param[in]  ev       The event context to use for the timer.
+ *
+ * @param[in]  endtime  The endtime of the request.
+ *
+ * @return              True if succeeded, false if not.
+ */
+bool tevent_req_set_endtime(struct tevent_req *req,
+			    struct tevent_context *ev,
+			    struct timeval endtime);
+
+#ifdef DOXYGEN
+/**
+ * @brief Call the notify callback of the given tevent request manually.
+ *
+ * @param[in]  req      The tevent request to call the notify function from.
+ *
+ * @see tevent_req_set_callback()
+ */
+void tevent_req_notify_callback(struct tevent_req *req);
+#else
+void _tevent_req_notify_callback(struct tevent_req *req, const char *location);
+#define tevent_req_notify_callback(req)		\
+	_tevent_req_notify_callback(req, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief An async request has successfully finished.
+ *
+ * This function is to be used by implementors of async requests. When a
+ * request is successfully finished, this function calls the user's completion
+ * function.
+ *
+ * @param[in]  req       The finished request.
+ */
+void tevent_req_done(struct tevent_req *req);
+#else
+void _tevent_req_done(struct tevent_req *req,
+		      const char *location);
+#define tevent_req_done(req) \
+	_tevent_req_done(req, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief An async request has seen an error.
+ *
+ * This function is to be used by implementors of async requests. When a
+ * request can not successfully completed, the implementation should call this
+ * function with the appropriate status code.
+ *
+ * If error is 0 the function returns false and does nothing more.
+ *
+ * @param[in]  req      The request with an error.
+ *
+ * @param[in]  error    The error code.
+ *
+ * @return              On success true is returned, false if error is 0.
+ *
+ * @code
+ * int error = first_function();
+ * if (tevent_req_error(req, error)) {
+ *      return;
+ * }
+ *
+ * error = second_function();
+ * if (tevent_req_error(req, error)) {
+ *      return;
+ * }
+ *
+ * tevent_req_done(req);
+ * return;
+ * @endcode
+ */
+bool tevent_req_error(struct tevent_req *req,
+		      uint64_t error);
+#else
+bool _tevent_req_error(struct tevent_req *req,
+		       uint64_t error,
+		       const char *location);
+#define tevent_req_error(req, error) \
+	_tevent_req_error(req, error, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Helper function for nomem check.
+ *
+ * Convenience helper to easily check alloc failure within a callback
+ * implementing the next step of an async request.
+ *
+ * @param[in]  p        The pointer to be checked.
+ *
+ * @param[in]  req      The request being processed.
+ *
+ * @code
+ * p = talloc(mem_ctx, bla);
+ * if (tevent_req_nomem(p, req)) {
+ *      return;
+ * }
+ * @endcode
+ */
+bool tevent_req_nomem(const void *p,
+		      struct tevent_req *req);
+#else
+bool _tevent_req_nomem(const void *p,
+		       struct tevent_req *req,
+		       const char *location);
+#define tevent_req_nomem(p, req) \
+	_tevent_req_nomem(p, req, __location__)
+#endif
+
+/**
+ * @brief Finish a request before the caller had the change to set the callback.
+ *
+ * An implementation of an async request might find that it can either finish
+ * the request without waiting for an external event, or it can't even start
+ * the engine. To present the illusion of a callback to the user of the API,
+ * the implementation can call this helper function which triggers an
+ * immediate timed event. This way the caller can use the same calling
+ * conventions, independent of whether the request was actually deferred.
+ *
+ * @param[in]  req      The finished request.
+ *
+ * @param[in]  ev       The tevent_context for the timed event.
+ *
+ * @return              The given request will be returned.
+ */
+struct tevent_req *tevent_req_post(struct tevent_req *req,
+				   struct tevent_context *ev);
+
+/**
+ * @brief Check if the given request is still in progress.
+ *
+ * It is typically used by sync wrapper functions.
+ *
+ * This function destroys the attached private data.
+ *
+ * @param[in]  req      The request to poll.
+ *
+ * @return              The boolean form of "is in progress".
+ */
+bool tevent_req_is_in_progress(struct tevent_req *req);
+
+/**
+ * @brief Actively poll for the given request to finish.
+ *
+ * This function is typically used by sync wrapper functions.
+ *
+ * @param[in]  req      The request to poll.
+ *
+ * @param[in]  ev       The tevent_context to be used.
+ *
+ * @return              On success true is returned. If a critical error has
+ *                      happened in the tevent loop layer false is returned.
+ *                      This is not the return value of the given request!
+ *
+ * @note This should only be used if the given tevent context was created by the
+ * caller, to avoid event loop nesting.
+ *
+ * @code
+ * req = tstream_writev_queue_send(mem_ctx,
+ *                                 ev_ctx,
+ *                                 tstream,
+ *                                 send_queue,
+ *                                 iov, 2);
+ * ok = tevent_req_poll(req, tctx->ev);
+ * rc = tstream_writev_queue_recv(req, &sys_errno);
+ * TALLOC_FREE(req);
+ * @endcode
+ */
+bool tevent_req_poll(struct tevent_req *req,
+		     struct tevent_context *ev);
+
+/**
+ * @brief Get the tevent request and the actual error code you've set.
+ *
+ * @param[in]  req      The tevent request to get the error from.
+ *
+ * @param[out] state    A pointer to store the tevent request error state.
+ *
+ * @param[out] error    A pointer to store the error set by tevent_req_error().
+ *
+ * @return              True if the function could set error and state, false
+ *                      otherwise.
+ *
+ * @see tevent_req_error()
+ */
+bool tevent_req_is_error(struct tevent_req *req,
+			 enum tevent_req_state *state,
+			 uint64_t *error);
+
+/**
+ * @brief Use as the last action of a _recv() function.
+ *
+ * This function destroys the attached private data.
+ *
+ * @param[in]  req      The finished request.
+ */
+void tevent_req_received(struct tevent_req *req);
+
+/**
+ * @brief Create a tevent subrequest at a given time.
+ *
+ * The idea is that always the same syntax for tevent requests.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to use.
+ *
+ * @param[in]  ev       The event handle to setup the request.
+ *
+ * @param[in]  wakeup_time The time to wakeup and execute the request.
+ *
+ * @return              The new subrequest, NULL on error.
+ *
+ * Example:
+ * @code
+ *   static my_callback_wakeup_done(tevent_req *req)
+ *   {
+ *     struct tevent_req *req = tevent_req_callback_data(subreq,
+ *                              struct tevent_req);
+ *     bool ok;
+ *
+ *     ok = tevent_wakeup_recv(subreq);
+ *     TALLOC_FREE(subreq);
+ *     if (!ok) {
+ *         tevent_req_error(req, -1);
+ *         return;
+ *     }
+ *     ...
+ *   }
+ * @endcode
+ *
+ * @code
+ *   subreq = tevent_wakeup_send(mem_ctx, ev, wakeup_time);
+ *   if (tevent_req_nomem(subreq, req)) {
+ *     return false;
+ *   }
+ *   tevent_set_callback(subreq, my_callback_wakeup_done, req);
+ * @endcode
+ *
+ * @see tevent_wakeup_recv()
+ */
+struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      struct timeval wakeup_time);
+
+/**
+ * @brief Check if the wakeup has been correctly executed.
+ *
+ * This function needs to be called in the callback function set after calling
+ * tevent_wakeup_send().
+ *
+ * @param[in]  req      The tevent request to check.
+ *
+ * @return              True on success, false otherwise.
+ *
+ * @see tevent_wakeup_recv()
+ */
+bool tevent_wakeup_recv(struct tevent_req *req);
+
+/* @} */
+
+/**
+ * @defgroup tevent_helpers The tevent helper functiions
+ * @ingroup tevent
+ *
+ * @todo description
+ *
+ * @{
+ */
+
+/**
+ * @brief Compare two timeval values.
+ *
+ * @param[in]  tv1      The first timeval value to compare.
+ *
+ * @param[in]  tv2      The second timeval value to compare.
+ *
+ * @return              0 if they are equal.
+ *                      1 if the first time is greater than the second.
+ *                      -1 if the first time is smaller than the second.
+ */
+int tevent_timeval_compare(const struct timeval *tv1,
+			   const struct timeval *tv2);
+
+/**
+ * @brief Get a zero timval value.
+ *
+ * @return              A zero timval value.
+ */
+struct timeval tevent_timeval_zero(void);
+
+/**
+ * @brief Get a timeval value for the current time.
+ *
+ * @return              A timval value with the current time.
+ */
+struct timeval tevent_timeval_current(void);
+
+/**
+ * @brief Get a timeval structure with the given values.
+ *
+ * @param[in]  secs     The seconds to set.
+ *
+ * @param[in]  usecs    The milliseconds to set.
+ *
+ * @return              A timeval structure with the given values.
+ */
+struct timeval tevent_timeval_set(uint32_t secs, uint32_t usecs);
+
+/**
+ * @brief Get the difference between two timeval values.
+ *
+ * @param[in]  tv1      The first timeval.
+ *
+ * @param[in]  tv2      The second timeval.
+ *
+ * @return              A timeval structure with the difference between the
+ *                      first and the second value.
+ */
+struct timeval tevent_timeval_until(const struct timeval *tv1,
+				    const struct timeval *tv2);
+
+/**
+ * @brief Check if a given timeval structure is zero.
+ *
+ * @param[in]  tv       The timeval to check if it is zero.
+ *
+ * @return              True if it is zero, false otherwise.
+ */
+bool tevent_timeval_is_zero(const struct timeval *tv);
+
+/**
+ * @brief Add the given amount of time to a timeval structure.
+ *
+ * @param[in]  tv        The timeval structure to add the time.
+ *
+ * @param[in]  secs      The seconds to add to the timeval.
+ *
+ * @param[in]  usecs     The milliseconds to add to the timeval.
+ *
+ * @return               The timeval structure with the new time.
+ */
+struct timeval tevent_timeval_add(const struct timeval *tv, uint32_t secs,
+				  uint32_t usecs);
+
+/**
+ * @brief Get a timeval in the future with a specified offset from now.
+ *
+ * @param[in]  secs     The seconds of the offset from now.
+ *
+ * @param[in]  usecs    The milliseconds of the offset from now.
+ *
+ * @return              A timval with the given offset in the future.
+ */
+struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs);
+
+/* @} */
+
+
+/**
+ * @defgroup tevent_queue The tevent queue functions
+ * @ingroup tevent
+ *
+ * A tevent_queue is used to queue up async requests that must be
+ * serialized. For example writing buffers into a socket must be
+ * serialized. Writing a large lump of data into a socket can require
+ * multiple write(2) or send(2) system calls. If more than one async
+ * request is outstanding to write large buffers into a socket, every
+ * request must individually be completed before the next one begins,
+ * even if multiple syscalls are required.
+ *
+ * Take a look at @ref tevent_queue_tutorial for more details.
+ * @{
+ */
+
+struct tevent_queue;
+
+#ifdef DOXYGEN
+/**
+ * @brief Create and start a tevent queue.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to allocate the queue.
+ *
+ * @param[in]  name     The name to use to identify the queue.
+ *
+ * @return              An allocated tevent queue on success, NULL on error.
+ *
+ * @see tevent_start()
+ * @see tevent_stop()
+ */
+struct tevent_queue *tevent_queue_create(TALLOC_CTX *mem_ctx,
+					 const char *name);
+#else
+struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
+					  const char *name,
+					  const char *location);
+
+#define tevent_queue_create(_mem_ctx, _name) \
+	_tevent_queue_create((_mem_ctx), (_name), __location__)
+#endif
+
+/**
+ * @brief A callback trigger function run by the queue.
+ *
+ * @param[in]  req      The tevent request the trigger function is executed on.
+ *
+ * @param[in]  private_data The private data pointer specified by
+ *                          tevent_queue_add().
+ *
+ * @see tevent_queue_add()
+ */
+typedef void (*tevent_queue_trigger_fn_t)(struct tevent_req *req,
+					  void *private_data);
+
+/**
+ * @brief Add a tevent request to the queue.
+ *
+ * @param[in]  queue    The queue to add the request.
+ *
+ * @param[in]  ev       The event handle to use for the request.
+ *
+ * @param[in]  req      The tevent request to add to the queue.
+ *
+ * @param[in]  trigger  The function triggered by the queue when the request
+ *                      is called.
+ *
+ * @param[in]  private_data The private data passed to the trigger function.
+ *
+ * @return              True if the request has been successfully added, false
+ *                      otherwise.
+ */
+bool tevent_queue_add(struct tevent_queue *queue,
+		      struct tevent_context *ev,
+		      struct tevent_req *req,
+		      tevent_queue_trigger_fn_t trigger,
+		      void *private_data);
+
+/**
+ * @brief Start a tevent queue.
+ *
+ * The queue is started by default.
+ *
+ * @param[in]  queue    The queue to start.
+ */
+void tevent_queue_start(struct tevent_queue *queue);
+
+/**
+ * @brief Stop a tevent queue.
+ *
+ * The queue is started by default.
+ *
+ * @param[in]  queue    The queue to stop.
+ */
+void tevent_queue_stop(struct tevent_queue *queue);
+
+/**
+ * @brief Get the length of the queue.
+ *
+ * @param[in]  queue    The queue to get the length from.
+ *
+ * @return              The number of elements.
+ */
+size_t tevent_queue_length(struct tevent_queue *queue);
+
+typedef int (*tevent_nesting_hook)(struct tevent_context *ev,
+				   void *private_data,
+				   uint32_t level,
+				   bool begin,
+				   void *stack_ptr,
+				   const char *location);
+#ifdef TEVENT_DEPRECATED
+#ifndef _DEPRECATED_
+#if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 )
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+void tevent_loop_allow_nesting(struct tevent_context *ev) _DEPRECATED_;
+void tevent_loop_set_nesting_hook(struct tevent_context *ev,
+				  tevent_nesting_hook hook,
+				  void *private_data) _DEPRECATED_;
+int _tevent_loop_until(struct tevent_context *ev,
+		       bool (*finished)(void *private_data),
+		       void *private_data,
+		       const char *location) _DEPRECATED_;
+#define tevent_loop_until(ev, finished, private_data) \
+	_tevent_loop_until(ev, finished, private_data, __location__)
+#endif
+
+int tevent_re_initialise(struct tevent_context *ev);
+
+/* @} */
+
+/**
+ * @defgroup tevent_ops The tevent operation functions
+ * @ingroup tevent
+ *
+ * The following structure and registration functions are exclusively
+ * needed for people writing and pluggin a different event engine.
+ * There is nothing useful for normal tevent user in here.
+ * @{
+ */
+
+struct tevent_ops {
+	/* context init */
+	int (*context_init)(struct tevent_context *ev);
+
+	/* fd_event functions */
+	struct tevent_fd *(*add_fd)(struct tevent_context *ev,
+				    TALLOC_CTX *mem_ctx,
+				    int fd, uint16_t flags,
+				    tevent_fd_handler_t handler,
+				    void *private_data,
+				    const char *handler_name,
+				    const char *location);
+	void (*set_fd_close_fn)(struct tevent_fd *fde,
+				tevent_fd_close_fn_t close_fn);
+	uint16_t (*get_fd_flags)(struct tevent_fd *fde);
+	void (*set_fd_flags)(struct tevent_fd *fde, uint16_t flags);
+
+	/* timed_event functions */
+	struct tevent_timer *(*add_timer)(struct tevent_context *ev,
+					  TALLOC_CTX *mem_ctx,
+					  struct timeval next_event,
+					  tevent_timer_handler_t handler,
+					  void *private_data,
+					  const char *handler_name,
+					  const char *location);
+
+	/* immediate event functions */
+	void (*schedule_immediate)(struct tevent_immediate *im,
+				   struct tevent_context *ev,
+				   tevent_immediate_handler_t handler,
+				   void *private_data,
+				   const char *handler_name,
+				   const char *location);
+
+	/* signal functions */
+	struct tevent_signal *(*add_signal)(struct tevent_context *ev,
+					    TALLOC_CTX *mem_ctx,
+					    int signum, int sa_flags,
+					    tevent_signal_handler_t handler,
+					    void *private_data,
+					    const char *handler_name,
+					    const char *location);
+
+	/* loop functions */
+	int (*loop_once)(struct tevent_context *ev, const char *location);
+	int (*loop_wait)(struct tevent_context *ev, const char *location);
+};
+
+bool tevent_register_backend(const char *name, const struct tevent_ops *ops);
+
+/* @} */
+
+/**
+ * @defgroup tevent_compat The tevent compatibility functions
+ * @ingroup tevent
+ *
+ * The following definitions are usueful only for compatibility with the
+ * implementation originally developed within the samba4 code and will be
+ * soon removed. Please NEVER use in new code.
+ *
+ * @todo Ignore it?
+ *
+ * @{
+ */
+
+/* Saves ctdb from massive churn. */
+#define TEVENT_COMPAT_DEFINES 1
+#ifdef TEVENT_COMPAT_DEFINES
+
+#define event_context	tevent_context
+#define event_ops	tevent_ops
+#define fd_event	tevent_fd
+#define timed_event	tevent_timer
+#define signal_event	tevent_signal
+
+#define event_fd_handler_t	tevent_fd_handler_t
+#define event_timed_handler_t	tevent_timer_handler_t
+#define event_signal_handler_t	tevent_signal_handler_t
+
+#define event_context_init(mem_ctx) \
+	tevent_context_init(mem_ctx)
+
+#define event_context_init_byname(mem_ctx, name) \
+	tevent_context_init_byname(mem_ctx, name)
+
+#define event_backend_list(mem_ctx) \
+	tevent_backend_list(mem_ctx)
+
+#define event_set_default_backend(backend) \
+	tevent_set_default_backend(backend)
+
+#define event_add_fd(ev, mem_ctx, fd, flags, handler, private_data) \
+	tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data)
+
+#define event_add_timed(ev, mem_ctx, next_event, handler, private_data) \
+	tevent_add_timer(ev, mem_ctx, next_event, handler, private_data)
+
+#define event_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data) \
+	tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data)
+
+#define event_loop_once(ev) \
+	tevent_loop_once(ev)
+
+#define event_loop_wait(ev) \
+	tevent_loop_wait(ev)
+
+#define event_get_fd_flags(fde) \
+	tevent_fd_get_flags(fde)
+
+#define event_set_fd_flags(fde, flags) \
+	tevent_fd_set_flags(fde, flags)
+
+#define EVENT_FD_READ		TEVENT_FD_READ
+#define EVENT_FD_WRITE		TEVENT_FD_WRITE
+
+#define EVENT_FD_WRITEABLE(fde) \
+	TEVENT_FD_WRITEABLE(fde)
+
+#define EVENT_FD_READABLE(fde) \
+	TEVENT_FD_READABLE(fde)
+
+#define EVENT_FD_NOT_WRITEABLE(fde) \
+	TEVENT_FD_NOT_WRITEABLE(fde)
+
+#define EVENT_FD_NOT_READABLE(fde) \
+	TEVENT_FD_NOT_READABLE(fde)
+
+#define ev_debug_level		tevent_debug_level
+
+#define EV_DEBUG_FATAL		TEVENT_DEBUG_FATAL
+#define EV_DEBUG_ERROR		TEVENT_DEBUG_ERROR
+#define EV_DEBUG_WARNING	TEVENT_DEBUG_WARNING
+#define EV_DEBUG_TRACE		TEVENT_DEBUG_TRACE
+
+#define ev_set_debug(ev, debug, context) \
+	tevent_set_debug(ev, debug, context)
+
+#define ev_set_debug_stderr(_ev) tevent_set_debug_stderr(ev)
+
+#endif /* TEVENT_COMPAT_DEFINES */
+
+/* @} */
+
+#endif /* __TEVENT_H__ */

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent.mk
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent.mk	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent.mk	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,46 @@
+TEVENT_SOBASE = libtevent.$(SHLIBEXT)
+TEVENT_SONAME = $(TEVENT_SOBASE).0
+TEVENT_SOLIB = $(TEVENT_SOBASE).$(PACKAGE_VERSION)
+TEVENT_STLIB = libtevent.a
+
+$(TEVENT_STLIB): $(TEVENT_OBJ)
+	ar -rv $(TEVENT_STLIB) $(TEVENT_OBJ)
+
+$(TEVENT_SOBASE): $(TEVENT_SOLIB)
+	ln -fs $< $@
+
+$(TEVENT_SONAME): $(TEVENT_SOLIB)
+	ln -fs $< $@
+
+dirs::
+	@mkdir -p lib
+
+installdirs::
+	mkdir -p $(DESTDIR)$(includedir)
+	mkdir -p $(DESTDIR)$(libdir)
+	mkdir -p $(DESTDIR)$(libdir)/pkgconfig
+
+installheaders:: installdirs
+	cp $(srcdir)/tevent.h $(DESTDIR)$(includedir)
+
+installlibs:: installdirs
+	cp tevent.pc $(DESTDIR)$(libdir)/pkgconfig
+	cp $(TEVENT_STLIB) $(TEVENT_SOLIB) $(DESTDIR)$(libdir)
+	rm -f $(DESTDIR)$(libdir)/$(TEVENT_SONAME)
+	ln -s $(TEVENT_SOLIB) $(DESTDIR)$(libdir)/$(TEVENT_SONAME)
+	rm -f $(DESTDIR)$(libdir)/$(TEVENT_SOBASE)
+	ln -s $(TEVENT_SOLIB) $(DESTDIR)$(libdir)/$(TEVENT_SOBASE)
+
+install:: all installdirs installheaders installlibs $(PYTHON_INSTALL_TARGET)
+
+abi_checks::
+	@echo ABI checks:
+	@./script/abi_checks.sh tevent tevent.h
+
+test:: abi_checks
+
+clean::
+	rm -f $(TEVENT_SOBASE) $(TEVENT_SONAME) $(TEVENT_SOLIB) $(TEVENT_STLIB)
+	rm -f tevent.pc
+	rm -f tevent.exports.sort tevent.exports.check tevent.exports.check.sort
+	rm -f tevent.signatures.sort tevent.signatures.check tevent.signatures.check.sort

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent.pc.in
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent.pc.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent.pc.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: tevent
+Description: An event system library
+Version: @PACKAGE_VERSION@
+Requires: talloc
+Libs: -L${libdir} -ltevent
+Cflags: -I${includedir}
+URL: http://samba.org/

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent.signatures
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent.signatures	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent.signatures	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,57 @@
+_Bool tevent_queue_add (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *);
+_Bool tevent_register_backend (const char *, const struct tevent_ops *);
+_Bool _tevent_req_error (struct tevent_req *, uint64_t, const char *);
+_Bool tevent_req_is_error (struct tevent_req *, enum tevent_req_state *, uint64_t *);
+_Bool tevent_req_is_in_progress (struct tevent_req *);
+_Bool _tevent_req_nomem (const void *, struct tevent_req *, const char *);
+_Bool tevent_req_poll (struct tevent_req *, struct tevent_context *);
+_Bool tevent_req_set_endtime (struct tevent_req *, struct tevent_context *, struct timeval);
+_Bool tevent_signal_support (struct tevent_context *);
+_Bool tevent_timeval_is_zero (const struct timeval *);
+_Bool tevent_wakeup_recv (struct tevent_req *);
+char *tevent_req_default_print (struct tevent_req *, TALLOC_CTX *);
+char *tevent_req_print (TALLOC_CTX *, struct tevent_req *);
+const char **tevent_backend_list (TALLOC_CTX *);
+int _tevent_loop_once (struct tevent_context *, const char *);
+int _tevent_loop_until (struct tevent_context *, _Bool (*) (void *), void *, const char *);
+int _tevent_loop_wait (struct tevent_context *, const char *);
+int tevent_set_debug_stderr (struct tevent_context *);
+int tevent_set_debug (struct tevent_context *, void (*) (void *, enum tevent_debug_level, const char *, va_list), void *);
+int tevent_timeval_compare (const struct timeval *, const struct timeval *);
+size_t tevent_queue_length (struct tevent_queue *);
+struct tevent_context *tevent_context_init_byname (TALLOC_CTX *, const char *);
+struct tevent_context *tevent_context_init (TALLOC_CTX *);
+struct tevent_fd *_tevent_add_fd (struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *);
+struct tevent_immediate *_tevent_create_immediate (TALLOC_CTX *, const char *);
+struct tevent_queue *_tevent_queue_create (TALLOC_CTX *, const char *, const char *);
+struct tevent_req *_tevent_req_create (TALLOC_CTX *, void *, size_t, const char *, const char *);
+struct tevent_req *tevent_req_post (struct tevent_req *, struct tevent_context *);
+struct tevent_req *tevent_wakeup_send (TALLOC_CTX *, struct tevent_context *, struct timeval);
+struct tevent_signal *_tevent_add_signal (struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *);
+struct tevent_timer *_tevent_add_timer (struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *);
+struct timeval tevent_timeval_add (const struct timeval *, uint32_t, uint32_t);
+struct timeval tevent_timeval_current_ofs (uint32_t, uint32_t);
+struct timeval tevent_timeval_current (void);
+struct timeval tevent_timeval_set (uint32_t, uint32_t);
+struct timeval tevent_timeval_until (const struct timeval *, const struct timeval *);
+struct timeval tevent_timeval_zero (void);
+uint16_t tevent_fd_get_flags (struct tevent_fd *);
+void tevent_fd_set_auto_close (struct tevent_fd *);
+void tevent_fd_set_close_fn (struct tevent_fd *, tevent_fd_close_fn_t);
+void tevent_fd_set_flags (struct tevent_fd *, uint16_t);
+void tevent_loop_allow_nesting (struct tevent_context *);
+void tevent_loop_set_nesting_hook (struct tevent_context *, tevent_nesting_hook, void *);
+void tevent_queue_start (struct tevent_queue *);
+void tevent_queue_stop (struct tevent_queue *);
+void *_tevent_req_callback_data (struct tevent_req *);
+void *_tevent_req_data (struct tevent_req *);
+void _tevent_req_done (struct tevent_req *, const char *);
+void _tevent_req_notify_callback (struct tevent_req *, const char *);
+void tevent_req_received (struct tevent_req *);
+void tevent_req_set_callback (struct tevent_req *, tevent_req_fn, void *);
+void tevent_req_set_print_fn (struct tevent_req *, tevent_req_print_fn);
+void _tevent_schedule_immediate (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *);
+void tevent_set_abort_fn (void (*) (const char *));
+void tevent_set_default_backend (const char *);
+_Bool _tevent_req_cancel (struct tevent_req *, const char *);
+void tevent_req_set_cancel_fn (struct tevent_req *, tevent_req_cancel_fn);

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_debug.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_debug.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_debug.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,95 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Jelmer Vernooij 2005
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+
+/********************************************************************
+ * Debug wrapper functions, modeled (with lot's of code copied as is)
+ * after the ev debug wrapper functions
+ ********************************************************************/
+
+/*
+  this allows the user to choose their own debug function
+*/
+int tevent_set_debug(struct tevent_context *ev,
+		     void (*debug)(void *context,
+				   enum tevent_debug_level level,
+				   const char *fmt,
+				   va_list ap) PRINTF_ATTRIBUTE(3,0),
+		     void *context)
+{
+	ev->debug_ops.debug = debug;
+	ev->debug_ops.context = context;
+	return 0;
+}
+
+/*
+  debug function for ev_set_debug_stderr
+*/
+static void tevent_debug_stderr(void *private_data,
+				enum tevent_debug_level level,
+				const char *fmt,
+				va_list ap) PRINTF_ATTRIBUTE(3,0);
+static void tevent_debug_stderr(void *private_data,
+				enum tevent_debug_level level,
+				const char *fmt, va_list ap)
+{
+	if (level <= TEVENT_DEBUG_WARNING) {
+		vfprintf(stderr, fmt, ap);
+	}
+}
+
+/*
+  convenience function to setup debug messages on stderr
+  messages of level TEVENT_DEBUG_WARNING and higher are printed
+*/
+int tevent_set_debug_stderr(struct tevent_context *ev)
+{
+	return tevent_set_debug(ev, tevent_debug_stderr, ev);
+}
+
+/*
+ * log a message
+ *
+ * The default debug action is to ignore debugging messages.
+ * This is the most appropriate action for a library.
+ * Applications using the library must decide where to
+ * redirect debugging messages
+*/
+void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
+		  const char *fmt, ...)
+{
+	va_list ap;
+	if (!ev) {
+		return;
+	}
+	if (ev->debug_ops.debug == NULL) {
+		return;
+	}
+	va_start(ap, fmt);
+	ev->debug_ops.debug(ev->debug_ops.context, level, fmt, ap);
+	va_end(ap);
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_epoll.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_epoll.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_epoll.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,447 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   main select loop and event handling - epoll implementation
+
+   Copyright (C) Andrew Tridgell	2003-2005
+   Copyright (C) Stefan Metzmacher	2005-2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct epoll_event_context {
+	/* a pointer back to the generic event_context */
+	struct tevent_context *ev;
+
+	/* when using epoll this is the handle from epoll_create */
+	int epoll_fd;
+
+	pid_t pid;
+};
+
+/*
+  called when a epoll call fails, and we should fallback
+  to using select
+*/
+static void epoll_panic(struct epoll_event_context *epoll_ev, const char *reason)
+{
+	tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+		 "%s (%s) - calling abort()\n", reason, strerror(errno));
+	abort();
+}
+
+/*
+  map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
+*/
+static uint32_t epoll_map_flags(uint16_t flags)
+{
+	uint32_t ret = 0;
+	if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
+	if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
+	return ret;
+}
+
+/*
+ free the epoll fd
+*/
+static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
+{
+	close(epoll_ev->epoll_fd);
+	epoll_ev->epoll_fd = -1;
+	return 0;
+}
+
+/*
+ init the epoll fd
+*/
+static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
+{
+	epoll_ev->epoll_fd = epoll_create(64);
+	epoll_ev->pid = getpid();
+	talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
+	if (epoll_ev->epoll_fd == -1) {
+		return -1;
+	}
+	return 0;
+}
+
+static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
+
+/*
+  reopen the epoll handle when our pid changes
+  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
+  demonstration of why this is needed
+ */
+static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
+{
+	struct tevent_fd *fde;
+
+	if (epoll_ev->pid == getpid()) {
+		return;
+	}
+
+	close(epoll_ev->epoll_fd);
+	epoll_ev->epoll_fd = epoll_create(64);
+	if (epoll_ev->epoll_fd == -1) {
+		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+			     "Failed to recreate epoll handle after fork\n");
+		return;
+	}
+	epoll_ev->pid = getpid();
+	for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
+		epoll_add_event(epoll_ev, fde);
+	}
+}
+
+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT	(1<<0)
+#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR	(1<<1)
+#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR	(1<<2)
+
+/*
+ add the epoll event to the given fd_event
+*/
+static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+
+	if (epoll_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* if we don't want events yet, don't add an epoll_event */
+	if (fde->flags == 0) return;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
+		epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed");
+	}
+	fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+
+	/* only if we want to read we want to tell the event handler about errors */
+	if (fde->flags & TEVENT_FD_READ) {
+		fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+	}
+}
+
+/*
+ delete the epoll event for given fd_event
+*/
+static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+
+	if (epoll_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* if there's no epoll_event, we don't need to delete it */
+	if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) {
+		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+			     "epoll_del_event failed! probable early close bug (%s)\n",
+			     strerror(errno));
+	}
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+}
+
+/*
+ change the epoll event to the given fd_event
+*/
+static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+	if (epoll_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
+		epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed");
+	}
+
+	/* only if we want to read we want to tell the event handler about errors */
+	if (fde->flags & TEVENT_FD_READ) {
+		fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+	}
+}
+
+static void epoll_change_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+	bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
+	bool want_read = (fde->flags & TEVENT_FD_READ);
+	bool want_write= (fde->flags & TEVENT_FD_WRITE);
+
+	if (epoll_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* there's already an event */
+	if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
+		if (want_read || (want_write && !got_error)) {
+			epoll_mod_event(epoll_ev, fde);
+			return;
+		}
+		/*
+		 * if we want to match the select behavior, we need to remove the epoll_event
+		 * when the caller isn't interested in events.
+		 *
+		 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
+		 */
+		epoll_del_event(epoll_ev, fde);
+		return;
+	}
+
+	/* there's no epoll_event attached to the fde */
+	if (want_read || (want_write && !got_error)) {
+		epoll_add_event(epoll_ev, fde);
+		return;
+	}
+}
+
+extern pid_t ctdbd_pid;
+
+/*
+  event loop handling using epoll
+*/
+static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
+{
+	int ret, i;
+#define MAXEVENTS 1
+	struct epoll_event events[MAXEVENTS];
+	int timeout = -1;
+
+	if (epoll_ev->epoll_fd == -1) return -1;
+
+	if (tvalp) {
+		/* it's better to trigger timed events a bit later than to early */
+		timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
+	}
+
+	if (epoll_ev->ev->signal_events &&
+	    tevent_common_check_signal(epoll_ev->ev)) {
+		return 0;
+	}
+
+	if (getpid() == ctdbd_pid) tevent_before_wait(epoll_ev->ev);
+	ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
+	if (getpid() == ctdbd_pid) tevent_after_wait(epoll_ev->ev);
+
+	if (ret == -1 && errno == EINTR && epoll_ev->ev->signal_events) {
+		if (tevent_common_check_signal(epoll_ev->ev)) {
+			return 0;
+		}
+	}
+
+	if (ret == -1 && errno != EINTR) {
+		epoll_panic(epoll_ev, "epoll_wait() failed");
+		return -1;
+	}
+
+	if (ret == 0 && tvalp) {
+		/* we don't care about a possible delay here */
+		tevent_common_loop_timer_delay(epoll_ev->ev);
+		return 0;
+	}
+
+	for (i=0;i<ret;i++) {
+		struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
+						       struct tevent_fd);
+		uint16_t flags = 0;
+
+		if (fde == NULL) {
+			epoll_panic(epoll_ev, "epoll_wait() gave bad data");
+			return -1;
+		}
+		if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+			fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+			/*
+			 * if we only wait for TEVENT_FD_WRITE, we should not tell the
+			 * event handler about it, and remove the epoll_event,
+			 * as we only report errors when waiting for read events,
+			 * to match the select() behavior
+			 */
+			if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
+				epoll_del_event(epoll_ev, fde);
+				continue;
+			}
+			flags |= TEVENT_FD_READ;
+		}
+		if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
+		if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
+		if (flags) {
+			fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+  create a epoll_event_context structure.
+*/
+static int epoll_event_context_init(struct tevent_context *ev)
+{
+	int ret;
+	struct epoll_event_context *epoll_ev;
+
+	epoll_ev = talloc_zero(ev, struct epoll_event_context);
+	if (!epoll_ev) return -1;
+	epoll_ev->ev = ev;
+	epoll_ev->epoll_fd = -1;
+
+	ret = epoll_init_ctx(epoll_ev);
+	if (ret != 0) {
+		talloc_free(epoll_ev);
+		return ret;
+	}
+
+	ev->additional_data = epoll_ev;
+	return 0;
+}
+
+/*
+  destroy an fd_event
+*/
+static int epoll_event_fd_destructor(struct tevent_fd *fde)
+{
+	struct tevent_context *ev = fde->event_ctx;
+	struct epoll_event_context *epoll_ev = NULL;
+
+	if (ev) {
+		epoll_ev = talloc_get_type(ev->additional_data,
+					   struct epoll_event_context);
+
+		epoll_check_reopen(epoll_ev);
+
+		epoll_del_event(epoll_ev, fde);
+	}
+
+	return tevent_common_fd_destructor(fde);
+}
+
+/*
+  add a fd based event
+  return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+					    int fd, uint16_t flags,
+					    tevent_fd_handler_t handler,
+					    void *private_data,
+					    const char *handler_name,
+					    const char *location)
+{
+	struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
+							   struct epoll_event_context);
+	struct tevent_fd *fde;
+
+	epoll_check_reopen(epoll_ev);
+
+	fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+				   handler, private_data,
+				   handler_name, location);
+	if (!fde) return NULL;
+
+	talloc_set_destructor(fde, epoll_event_fd_destructor);
+
+	epoll_add_event(epoll_ev, fde);
+
+	return fde;
+}
+
+/*
+  set the fd event flags
+*/
+static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+	struct tevent_context *ev;
+	struct epoll_event_context *epoll_ev;
+
+	if (fde->flags == flags) return;
+
+	ev = fde->event_ctx;
+	epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context);
+
+	fde->flags = flags;
+
+	epoll_check_reopen(epoll_ev);
+
+	epoll_change_event(epoll_ev, fde);
+}
+
+/*
+  do a single event loop using the events defined in ev
+*/
+static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
+{
+	struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
+							   struct epoll_event_context);
+	struct timeval tval;
+
+	if (ev->signal_events &&
+	    tevent_common_check_signal(ev)) {
+		return 0;
+	}
+
+	if (ev->immediate_events &&
+	    tevent_common_loop_immediate(ev)) {
+		return 0;
+	}
+
+	tval = tevent_common_loop_timer_delay(ev);
+	if (tevent_timeval_is_zero(&tval)) {
+		return 0;
+	}
+
+	epoll_check_reopen(epoll_ev);
+
+	return epoll_event_loop(epoll_ev, &tval);
+}
+
+static const struct tevent_ops epoll_event_ops = {
+	.context_init		= epoll_event_context_init,
+	.add_fd			= epoll_event_add_fd,
+	.set_fd_close_fn	= tevent_common_fd_set_close_fn,
+	.get_fd_flags		= tevent_common_fd_get_flags,
+	.set_fd_flags		= epoll_event_set_fd_flags,
+	.add_timer		= tevent_common_add_timer,
+	.schedule_immediate	= tevent_common_schedule_immediate,
+	.add_signal		= tevent_common_add_signal,
+	.loop_once		= epoll_event_loop_once,
+	.loop_wait		= tevent_common_loop_wait,
+};
+
+_PRIVATE_ bool tevent_epoll_init(void)
+{
+	return tevent_register_backend("epoll", &epoll_event_ops);
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_fd.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_fd.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_fd.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,89 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   common events code for fd events
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+int tevent_common_fd_destructor(struct tevent_fd *fde)
+{
+	if (fde->event_ctx) {
+		DLIST_REMOVE(fde->event_ctx->fd_events, fde);
+	}
+
+	if (fde->close_fn) {
+		fde->close_fn(fde->event_ctx, fde, fde->fd, fde->private_data);
+		fde->fd = -1;
+	}
+
+	return 0;
+}
+
+struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+				       int fd, uint16_t flags,
+				       tevent_fd_handler_t handler,
+				       void *private_data,
+				       const char *handler_name,
+				       const char *location)
+{
+	struct tevent_fd *fde;
+
+	fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
+	if (!fde) return NULL;
+
+	fde->event_ctx		= ev;
+	fde->fd			= fd;
+	fde->flags		= flags;
+	fde->handler		= handler;
+	fde->close_fn		= NULL;
+	fde->private_data	= private_data;
+	fde->handler_name	= handler_name;
+	fde->location		= location;
+	fde->additional_flags	= 0;
+	fde->additional_data	= NULL;
+
+	DLIST_ADD(ev->fd_events, fde);
+
+	talloc_set_destructor(fde, tevent_common_fd_destructor);
+
+	return fde;
+}
+uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde)
+{
+	return fde->flags;
+}
+
+void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
+{
+	if (fde->flags == flags) return;
+	fde->flags = flags;
+}
+
+void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
+				   tevent_fd_close_fn_t close_fn)
+{
+	fde->close_fn = close_fn;
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_immediate.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_immediate.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_immediate.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,138 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   common events code for immediate events
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static void tevent_common_immediate_cancel(struct tevent_immediate *im)
+{
+	if (!im->event_ctx) {
+		return;
+	}
+
+	tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
+		     "Cancel immediate event %p \"%s\"\n",
+		     im, im->handler_name);
+
+	/* let the backend free im->additional_data */
+	if (im->cancel_fn) {
+		im->cancel_fn(im);
+	}
+
+	DLIST_REMOVE(im->event_ctx->immediate_events, im);
+	im->event_ctx		= NULL;
+	im->handler		= NULL;
+	im->private_data	= NULL;
+	im->handler_name	= NULL;
+	im->schedule_location	= NULL;
+	im->cancel_fn		= NULL;
+	im->additional_data	= NULL;
+
+	talloc_set_destructor(im, NULL);
+}
+
+/*
+  destroy an immediate event
+*/
+static int tevent_common_immediate_destructor(struct tevent_immediate *im)
+{
+	tevent_common_immediate_cancel(im);
+	return 0;
+}
+
+/*
+ * schedule an immediate event on
+ */
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+				      struct tevent_context *ev,
+				      tevent_immediate_handler_t handler,
+				      void *private_data,
+				      const char *handler_name,
+				      const char *location)
+{
+	tevent_common_immediate_cancel(im);
+
+	if (!handler) {
+		return;
+	}
+
+	im->event_ctx		= ev;
+	im->handler		= handler;
+	im->private_data	= private_data;
+	im->handler_name	= handler_name;
+	im->schedule_location	= location;
+	im->cancel_fn		= NULL;
+	im->additional_data	= NULL;
+
+	DLIST_ADD_END(ev->immediate_events, im, struct tevent_immediate *);
+	talloc_set_destructor(im, tevent_common_immediate_destructor);
+
+	tevent_debug(ev, TEVENT_DEBUG_TRACE,
+		     "Schedule immediate event \"%s\": %p\n",
+		     handler_name, im);
+}
+
+/*
+  trigger the first immediate event and return true
+  if no event was triggered return false
+*/
+bool tevent_common_loop_immediate(struct tevent_context *ev)
+{
+	struct tevent_immediate *im = ev->immediate_events;
+	tevent_immediate_handler_t handler;
+	void *private_data;
+
+	if (!im) {
+		return false;
+	}
+
+	tevent_debug(ev, TEVENT_DEBUG_TRACE,
+		     "Run immediate event \"%s\": %p\n",
+		     im->handler_name, im);
+
+	/*
+	 * remember the handler and then clear the event
+	 * the handler might reschedule the event
+	 */
+	handler = im->handler;
+	private_data = im->private_data;
+
+	DLIST_REMOVE(im->event_ctx->immediate_events, im);
+	im->event_ctx		= NULL;
+	im->handler		= NULL;
+	im->private_data	= NULL;
+	im->handler_name	= NULL;
+	im->schedule_location	= NULL;
+	im->cancel_fn		= NULL;
+	im->additional_data	= NULL;
+
+	talloc_set_destructor(im, NULL);
+
+	handler(ev, im, private_data);
+
+	return true;
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_internal.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_internal.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_internal.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,308 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   generalised event loop handling
+
+   INTERNAL STRUCTS. THERE ARE NO API GUARANTEES.
+   External users should only ever have to include this header when
+   implementing new tevent backends.
+
+   Copyright (C) Stefan Metzmacher 2005-2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+struct tevent_req {
+	/**
+	 * @brief What to do on completion
+	 *
+	 * This is used for the user of an async request, fn is called when
+	 * the request completes, either successfully or with an error.
+	 */
+	struct {
+		/**
+		 * @brief Completion function
+		 * Completion function, to be filled by the API user
+		 */
+		tevent_req_fn fn;
+		/**
+		 * @brief Private data for the completion function
+		 */
+		void *private_data;
+	} async;
+
+	/**
+	 * @brief Private state pointer for the actual implementation
+	 *
+	 * The implementation doing the work for the async request needs to
+	 * keep around current data like for example a fd event. The user of
+	 * an async request should not touch this.
+	 */
+	void *data;
+
+	/**
+	 * @brief A function to overwrite the default print function
+	 *
+	 * The implementation doing the work may want to implement a
+	 * custom function to print the text representation of the async
+	 * request.
+	 */
+	tevent_req_print_fn private_print;
+
+	/**
+	 * @brief A function to cancel the request
+	 *
+	 * The implementation might want to set a function
+	 * that is called when the tevent_req_cancel() function
+	 * was called.
+	 */
+	tevent_req_cancel_fn private_cancel;
+
+	/**
+	 * @brief Internal state of the request
+	 *
+	 * Callers should only access this via functions and never directly.
+	 */
+	struct {
+		/**
+		 * @brief The talloc type of the data pointer
+		 *
+		 * This is filled by the tevent_req_create() macro.
+		 *
+		 * This for debugging only.
+		 */
+		const char *private_type;
+
+		/**
+		 * @brief The location where the request was created
+		 *
+		 * This uses the __location__ macro via the tevent_req_create()
+		 * macro.
+		 *
+		 * This for debugging only.
+		 */
+		const char *create_location;
+
+		/**
+		 * @brief The location where the request was finished
+		 *
+		 * This uses the __location__ macro via the tevent_req_done(),
+		 * tevent_req_error() or tevent_req_nomem() macro.
+		 *
+		 * This for debugging only.
+		 */
+		const char *finish_location;
+
+		/**
+		 * @brief The location where the request was canceled
+		 *
+		 * This uses the __location__ macro via the
+		 * tevent_req_cancel() macro.
+		 *
+		 * This for debugging only.
+		 */
+		const char *cancel_location;
+
+		/**
+		 * @brief The external state - will be queried by the caller
+		 *
+		 * While the async request is being processed, state will remain in
+		 * TEVENT_REQ_IN_PROGRESS. A request is finished if
+		 * req->state>=TEVENT_REQ_DONE.
+		 */
+		enum tevent_req_state state;
+
+		/**
+		 * @brief status code when finished
+		 *
+		 * This status can be queried in the async completion function. It
+		 * will be set to 0 when everything went fine.
+		 */
+		uint64_t error;
+
+		/**
+		 * @brief the immediate event used by tevent_req_post
+		 *
+		 */
+		struct tevent_immediate *trigger;
+
+		/**
+		 * @brief the timer event if tevent_req_set_endtime was used
+		 *
+		 */
+		struct tevent_timer *timer;
+	} internal;
+};
+
+struct tevent_fd {
+	struct tevent_fd *prev, *next;
+	struct tevent_context *event_ctx;
+	int fd;
+	uint16_t flags; /* see TEVENT_FD_* flags */
+	tevent_fd_handler_t handler;
+	tevent_fd_close_fn_t close_fn;
+	/* this is private for the specific handler */
+	void *private_data;
+	/* this is for debugging only! */
+	const char *handler_name;
+	const char *location;
+	/* this is private for the events_ops implementation */
+	uint16_t additional_flags;
+	void *additional_data;
+};
+
+struct tevent_timer {
+	struct tevent_timer *prev, *next;
+	struct tevent_context *event_ctx;
+	struct timeval next_event;
+	tevent_timer_handler_t handler;
+	/* this is private for the specific handler */
+	void *private_data;
+	/* this is for debugging only! */
+	const char *handler_name;
+	const char *location;
+	/* this is private for the events_ops implementation */
+	void *additional_data;
+};
+
+struct tevent_immediate {
+	struct tevent_immediate *prev, *next;
+	struct tevent_context *event_ctx;
+	tevent_immediate_handler_t handler;
+	/* this is private for the specific handler */
+	void *private_data;
+	/* this is for debugging only! */
+	const char *handler_name;
+	const char *create_location;
+	const char *schedule_location;
+	/* this is private for the events_ops implementation */
+	void (*cancel_fn)(struct tevent_immediate *im);
+	void *additional_data;
+};
+
+struct tevent_signal {
+	struct tevent_signal *prev, *next;
+	struct tevent_context *event_ctx;
+	int signum;
+	int sa_flags;
+	tevent_signal_handler_t handler;
+	/* this is private for the specific handler */
+	void *private_data;
+	/* this is for debugging only! */
+	const char *handler_name;
+	const char *location;
+	/* this is private for the events_ops implementation */
+	void *additional_data;
+};
+
+struct tevent_debug_ops {
+	void (*debug)(void *context, enum tevent_debug_level level,
+		      const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+	void *context;
+};
+
+void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
+		  const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+struct tevent_context {
+	/* the specific events implementation */
+	const struct tevent_ops *ops;
+
+	/* list of fd events - used by common code */
+	struct tevent_fd *fd_events;
+
+	/* list of timed events - used by common code */
+	struct tevent_timer *timer_events;
+
+	/* list of immediate events - used by common code */
+	struct tevent_immediate *immediate_events;
+
+	/* list of signal events - used by common code */
+	struct tevent_signal *signal_events;
+
+	/* this is private for the events_ops implementation */
+	void *additional_data;
+
+	/* pipe hack used with signal handlers */
+	struct tevent_fd *pipe_fde;
+	int pipe_fds[2];
+
+	/* debugging operations */
+	struct tevent_debug_ops debug_ops;
+
+	/* info about the nesting status */
+	struct {
+		bool allowed;
+		uint32_t level;
+		tevent_nesting_hook hook_fn;
+		void *hook_private;
+	} nesting;
+};
+
+
+int tevent_common_context_destructor(struct tevent_context *ev);
+int tevent_common_loop_wait(struct tevent_context *ev,
+			    const char *location);
+
+int tevent_common_fd_destructor(struct tevent_fd *fde);
+struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev,
+				       TALLOC_CTX *mem_ctx,
+				       int fd,
+				       uint16_t flags,
+				       tevent_fd_handler_t handler,
+				       void *private_data,
+				       const char *handler_name,
+				       const char *location);
+void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
+				   tevent_fd_close_fn_t close_fn);
+uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde);
+void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+
+struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
+					     TALLOC_CTX *mem_ctx,
+					     struct timeval next_event,
+					     tevent_timer_handler_t handler,
+					     void *private_data,
+					     const char *handler_name,
+					     const char *location);
+struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
+
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+				      struct tevent_context *ev,
+				      tevent_immediate_handler_t handler,
+				      void *private_data,
+				      const char *handler_name,
+				      const char *location);
+bool tevent_common_loop_immediate(struct tevent_context *ev);
+
+struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
+					       TALLOC_CTX *mem_ctx,
+					       int signum,
+					       int sa_flags,
+					       tevent_signal_handler_t handler,
+					       void *private_data,
+					       const char *handler_name,
+					       const char *location);
+int tevent_common_check_signal(struct tevent_context *ev);
+void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
+
+bool tevent_standard_init(void);
+bool tevent_select_init(void);
+#ifdef HAVE_EPOLL
+bool tevent_epoll_init(void);
+#endif

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_liboop.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_liboop.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_liboop.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,292 @@
+/*
+   Unix SMB/CIFS implementation.
+   main select loop and event handling
+   wrapper for http://liboop.org/
+
+   Copyright (C) Stefan Metzmacher 2005
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "events.h"
+#include "events_internal.h"
+
+#include <oop.h>
+
+/*
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ NOTE: this code compiles fine, but is completely *UNTESTED*
+       and is only committed as an example
+
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+*/
+
+static int oop_event_context_destructor(struct tevent_context *ev)
+{
+	oop_source_sys *oop_sys = ev->additional_data;
+
+	oop_sys_delete(oop_sys);
+
+	return 0;
+}
+
+/*
+  create a oop_event_context structure.
+*/
+static int oop_event_context_init(struct tevent_context *ev, void *private_data)
+{
+	oop_source_sys *oop_sys = private_data;
+
+	if (!oop_sys) {
+		oop_sys = oop_sys_new();
+		if (!oop_sys) {
+			return -1;
+		}
+
+		talloc_set_destructor(ev, oop_event_context_destructor);
+	}
+
+	ev->additional_data = oop_sys;
+
+	return 0;
+}
+
+static void *oop_event_fd_handler(oop_source *oop, int fd, oop_event oop_type, void *ptr)
+{
+	struct tevent_fd *fde = ptr;
+
+	if (fd != fde->fd) return OOP_ERROR;
+
+	switch(oop_type) {
+		case OOP_READ:
+			fde->handler(fde->event_ctx, fde, EVENT_FD_READ, fde->private_data);
+			return OOP_CONTINUE;
+		case OOP_WRITE:
+			fde->handler(fde->event_ctx, fde, EVENT_FD_WRITE, fde->private_data);
+			return OOP_CONTINUE;
+		case OOP_EXCEPTION:
+			return OOP_ERROR;
+		case OOP_NUM_EVENTS:
+			return OOP_ERROR;
+	}
+
+	return OOP_ERROR;
+}
+
+/*
+  destroy an fd_event
+*/
+static int oop_event_fd_destructor(struct tevent_fd *fde)
+{
+	struct tevent_context *ev = fde->event_ctx;
+	oop_source_sys *oop_sys = ev->additional_data;
+	oop_source *oop = oop_sys_source(oop_sys);
+
+	if (fde->flags & EVENT_FD_READ)
+		oop->cancel_fd(oop, fde->fd, OOP_READ);
+	if (fde->flags & EVENT_FD_WRITE)
+		oop->cancel_fd(oop, fde->fd, OOP_WRITE);
+
+	if (fde->flags & EVENT_FD_AUTOCLOSE) {
+		close(fde->fd);
+		fde->fd = -1;
+	}
+
+	return 0;
+}
+
+/*
+  add a fd based event
+  return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *oop_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+					 int fd, uint16_t flags,
+					 event_fd_handler_t handler,
+					 void *private_data)
+{
+	struct tevent_fd *fde;
+	oop_source_sys *oop_sys = ev->additional_data;
+	oop_source *oop = oop_sys_source(oop_sys);
+
+	fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
+	if (!fde) return NULL;
+
+	fde->event_ctx		= ev;
+	fde->fd			= fd;
+	fde->flags		= flags;
+	fde->handler		= handler;
+	fde->private_data	= private_data;
+	fde->additional_flags	= 0;
+	fde->additional_data	= NULL;
+
+	if (fde->flags & EVENT_FD_READ)
+		oop->on_fd(oop, fde->fd, OOP_READ, oop_event_fd_handler, fde);
+	if (fde->flags & EVENT_FD_WRITE)
+		oop->on_fd(oop, fde->fd, OOP_WRITE, oop_event_fd_handler, fde);
+
+	talloc_set_destructor(fde, oop_event_fd_destructor);
+
+	return fde;
+}
+
+/*
+  return the fd event flags
+*/
+static uint16_t oop_event_get_fd_flags(struct tevent_fd *fde)
+{
+	return fde->flags;
+}
+
+/*
+  set the fd event flags
+*/
+static void oop_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+	oop_source_sys *oop_sys;
+	oop_source *oop;
+
+	oop_sys = fde->event_ctx->additional_data;
+	oop = oop_sys_source(oop_sys);
+
+	if ((fde->flags & EVENT_FD_READ)&&(!(flags & EVENT_FD_READ)))
+		oop->cancel_fd(oop, fde->fd, OOP_READ);
+
+	if ((!(fde->flags & EVENT_FD_READ))&&(flags & EVENT_FD_READ))
+		oop->on_fd(oop, fde->fd, OOP_READ, oop_event_fd_handler, fde);
+
+	if ((fde->flags & EVENT_FD_WRITE)&&(!(flags & EVENT_FD_WRITE)))
+		oop->cancel_fd(oop, fde->fd, OOP_WRITE);
+
+	if ((!(fde->flags & EVENT_FD_WRITE))&&(flags & EVENT_FD_WRITE))
+		oop->on_fd(oop, fde->fd, OOP_WRITE, oop_event_fd_handler, fde);
+
+	fde->flags = flags;
+}
+
+static int oop_event_timed_destructor(struct tevent_timer *te);
+
+static int oop_event_timed_deny_destructor(struct tevent_timer *te)
+{
+	return -1;
+}
+
+static void *oop_event_timed_handler(oop_source *oop, struct timeval t, void *ptr)
+{
+	struct tevent_timer *te = ptr;
+
+	/* deny the handler to free the event */
+	talloc_set_destructor(te, oop_event_timed_deny_destructor);
+	te->handler(te->event_ctx, te, t, te->private_data);
+
+	talloc_set_destructor(te, oop_event_timed_destructor);
+	talloc_free(te);
+
+	return OOP_CONTINUE;
+}
+
+/*
+  destroy a timed event
+*/
+static int oop_event_timed_destructor(struct tevent_timer *te)
+{
+	struct tevent_context *ev = te->event_ctx;
+	oop_source_sys *oop_sys = ev->additional_data;
+	oop_source *oop = oop_sys_source(oop_sys);
+
+	oop->cancel_time(oop, te->next_event, oop_event_timed_handler, te);
+
+	return 0;
+}
+
+/*
+  add a timed event
+  return NULL on failure (memory allocation error)
+*/
+static struct tevent_timer *oop_event_add_timed(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+					       struct timeval next_event,
+					       event_timed_handler_t handler,
+					       void *private_data)
+{
+	oop_source_sys *oop_sys = ev->additional_data;
+	oop_source *oop = oop_sys_source(oop_sys);
+	struct tevent_timer *te;
+
+	te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
+	if (te == NULL) return NULL;
+
+	te->event_ctx		= ev;
+	te->next_event		= next_event;
+	te->handler		= handler;
+	te->private_data	= private_data;
+	te->additional_data	= NULL;
+
+	oop->on_time(oop, te->next_event, oop_event_timed_handler, te);
+
+	talloc_set_destructor(te, oop_event_timed_destructor);
+
+	return te;
+}
+
+/*
+  do a single event loop using the events defined in ev
+*/
+static int oop_event_loop_once(struct tevent_context *ev)
+{
+	void *oop_ret;
+	oop_source_sys *oop_sys = ev->additional_data;
+
+	oop_ret = oop_sys_run_once(oop_sys);
+	if (oop_ret == OOP_CONTINUE) {
+		return 0;
+	}
+
+	return -1;
+}
+
+/*
+  return on failure or (with 0) if all fd events are removed
+*/
+static int oop_event_loop_wait(struct tevent_context *ev)
+{
+	void *oop_ret;
+	oop_source_sys *oop_sys = ev->additional_data;
+
+	oop_ret = oop_sys_run(oop_sys);
+	if (oop_ret == OOP_CONTINUE) {
+		return 0;
+	}
+
+	return -1;
+}
+
+static const struct event_ops event_oop_ops = {
+	.context_init	= oop_event_context_init,
+	.add_fd		= oop_event_add_fd,
+	.get_fd_flags	= oop_event_get_fd_flags,
+	.set_fd_flags	= oop_event_set_fd_flags,
+	.add_timer	= oop_event_add_timed,
+	.add_signal	= common_event_add_signal,
+	.loop_once	= oop_event_loop_once,
+	.loop_wait	= oop_event_loop_wait,
+};
+
+const struct event_ops *event_liboop_get_ops(void)
+{
+	return &event_oop_ops;
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_queue.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_queue.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_queue.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,217 @@
+/*
+   Unix SMB/CIFS implementation.
+   Infrastructure for async requests
+   Copyright (C) Volker Lendecke 2008
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct tevent_queue_entry {
+	struct tevent_queue_entry *prev, *next;
+	struct tevent_queue *queue;
+
+	bool triggered;
+
+	struct tevent_req *req;
+	struct tevent_context *ev;
+
+	tevent_queue_trigger_fn_t trigger;
+	void *private_data;
+};
+
+struct tevent_queue {
+	const char *name;
+	const char *location;
+
+	bool running;
+	struct tevent_immediate *immediate;
+
+	size_t length;
+	struct tevent_queue_entry *list;
+};
+
+static void tevent_queue_immediate_trigger(struct tevent_context *ev,
+					   struct tevent_immediate *im,
+					   void *private_data);
+
+static int tevent_queue_entry_destructor(struct tevent_queue_entry *e)
+{
+	struct tevent_queue *q = e->queue;
+
+	if (!q) {
+		return 0;
+	}
+
+	DLIST_REMOVE(q->list, e);
+	q->length--;
+
+	if (!q->running) {
+		return 0;
+	}
+
+	if (!q->list) {
+		return 0;
+	}
+
+	if (q->list->triggered) {
+		return 0;
+	}
+
+	tevent_schedule_immediate(q->immediate,
+				  q->list->ev,
+				  tevent_queue_immediate_trigger,
+				  q);
+
+	return 0;
+}
+
+static int tevent_queue_destructor(struct tevent_queue *q)
+{
+	q->running = false;
+
+	while (q->list) {
+		struct tevent_queue_entry *e = q->list;
+		talloc_free(e);
+	}
+
+	return 0;
+}
+
+struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
+					  const char *name,
+					  const char *location)
+{
+	struct tevent_queue *queue;
+
+	queue = talloc_zero(mem_ctx, struct tevent_queue);
+	if (!queue) {
+		return NULL;
+	}
+
+	queue->name = talloc_strdup(queue, name);
+	if (!queue->name) {
+		talloc_free(queue);
+		return NULL;
+	}
+	queue->immediate = tevent_create_immediate(queue);
+	if (!queue->immediate) {
+		talloc_free(queue);
+		return NULL;
+	}
+
+	queue->location = location;
+
+	/* queue is running by default */
+	queue->running = true;
+
+	talloc_set_destructor(queue, tevent_queue_destructor);
+	return queue;
+}
+
+static void tevent_queue_immediate_trigger(struct tevent_context *ev,
+					   struct tevent_immediate *im,
+					   void *private_data)
+{
+	struct tevent_queue *q = talloc_get_type(private_data,
+				  struct tevent_queue);
+
+	if (!q->running) {
+		return;
+	}
+
+	q->list->triggered = true;
+	q->list->trigger(q->list->req, q->list->private_data);
+}
+
+bool tevent_queue_add(struct tevent_queue *queue,
+		      struct tevent_context *ev,
+		      struct tevent_req *req,
+		      tevent_queue_trigger_fn_t trigger,
+		      void *private_data)
+{
+	struct tevent_queue_entry *e;
+
+	e = talloc_zero(req, struct tevent_queue_entry);
+	if (e == NULL) {
+		return false;
+	}
+
+	e->queue = queue;
+	e->req = req;
+	e->ev = ev;
+	e->trigger = trigger;
+	e->private_data = private_data;
+
+	DLIST_ADD_END(queue->list, e, struct tevent_queue_entry *);
+	queue->length++;
+	talloc_set_destructor(e, tevent_queue_entry_destructor);
+
+	if (!queue->running) {
+		return true;
+	}
+
+	if (queue->list->triggered) {
+		return true;
+	}
+
+	tevent_schedule_immediate(queue->immediate,
+				  queue->list->ev,
+				  tevent_queue_immediate_trigger,
+				  queue);
+
+	return true;
+}
+
+void tevent_queue_start(struct tevent_queue *queue)
+{
+	if (queue->running) {
+		/* already started */
+		return;
+	}
+
+	queue->running = true;
+
+	if (!queue->list) {
+		return;
+	}
+
+	if (queue->list->triggered) {
+		return;
+	}
+
+	tevent_schedule_immediate(queue->immediate,
+				  queue->list->ev,
+				  tevent_queue_immediate_trigger,
+				  queue);
+}
+
+void tevent_queue_stop(struct tevent_queue *queue)
+{
+	queue->running = false;
+}
+
+size_t tevent_queue_length(struct tevent_queue *queue)
+{
+	return queue->length;
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_req.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_req.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_req.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,277 @@
+/*
+   Unix SMB/CIFS implementation.
+   Infrastructure for async requests
+   Copyright (C) Volker Lendecke 2008
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
+{
+	return talloc_asprintf(mem_ctx,
+			       "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
+			       " state[%s (%p)] timer[%p]",
+			       req, req->internal.create_location,
+			       req->internal.state,
+			       (unsigned long long)req->internal.error,
+			       (unsigned long long)req->internal.error,
+			       talloc_get_name(req->data),
+			       req->data,
+			       req->internal.timer
+			       );
+}
+
+char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
+{
+	if (!req->private_print) {
+		return tevent_req_default_print(req, mem_ctx);
+	}
+
+	return req->private_print(req, mem_ctx);
+}
+
+struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
+				    void *pdata,
+				    size_t data_size,
+				    const char *type,
+				    const char *location)
+{
+	struct tevent_req *req;
+	void **ppdata = (void **)pdata;
+	void *data;
+
+	req = talloc_zero(mem_ctx, struct tevent_req);
+	if (req == NULL) {
+		return NULL;
+	}
+	req->internal.private_type	= type;
+	req->internal.create_location	= location;
+	req->internal.finish_location	= NULL;
+	req->internal.state		= TEVENT_REQ_IN_PROGRESS;
+	req->internal.trigger		= tevent_create_immediate(req);
+	if (!req->internal.trigger) {
+		talloc_free(req);
+		return NULL;
+	}
+
+	data = talloc_zero_size(req, data_size);
+	if (data == NULL) {
+		talloc_free(req);
+		return NULL;
+	}
+	talloc_set_name_const(data, type);
+
+	req->data = data;
+
+	*ppdata = data;
+	return req;
+}
+
+void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
+{
+	req->internal.finish_location = location;
+	if (req->async.fn != NULL) {
+		req->async.fn(req);
+	}
+}
+
+static void tevent_req_finish(struct tevent_req *req,
+			      enum tevent_req_state state,
+			      const char *location)
+{
+	req->internal.state = state;
+	_tevent_req_notify_callback(req, location);
+}
+
+void _tevent_req_done(struct tevent_req *req,
+		      const char *location)
+{
+	tevent_req_finish(req, TEVENT_REQ_DONE, location);
+}
+
+bool _tevent_req_error(struct tevent_req *req,
+		       uint64_t error,
+		       const char *location)
+{
+	if (error == 0) {
+		return false;
+	}
+
+	req->internal.error = error;
+	tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
+	return true;
+}
+
+bool _tevent_req_nomem(const void *p,
+		       struct tevent_req *req,
+		       const char *location)
+{
+	if (p != NULL) {
+		return false;
+	}
+	tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
+	return true;
+}
+
+/**
+ * @internal
+ *
+ * @brief Immediate event callback.
+ *
+ * @param[in]  ev       The event context to use.
+ *
+ * @param[in]  im       The immediate event.
+ *
+ * @param[in]  priv     The async request to be finished.
+ */
+static void tevent_req_trigger(struct tevent_context *ev,
+			       struct tevent_immediate *im,
+			       void *private_data)
+{
+	struct tevent_req *req = talloc_get_type(private_data,
+				 struct tevent_req);
+
+	tevent_req_finish(req, req->internal.state,
+			  req->internal.finish_location);
+}
+
+struct tevent_req *tevent_req_post(struct tevent_req *req,
+				   struct tevent_context *ev)
+{
+	tevent_schedule_immediate(req->internal.trigger,
+				  ev, tevent_req_trigger, req);
+	return req;
+}
+
+bool tevent_req_is_in_progress(struct tevent_req *req)
+{
+	if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
+		return true;
+	}
+
+	return false;
+}
+
+void tevent_req_received(struct tevent_req *req)
+{
+	TALLOC_FREE(req->data);
+	req->private_print = NULL;
+
+	TALLOC_FREE(req->internal.trigger);
+	TALLOC_FREE(req->internal.timer);
+
+	req->internal.state = TEVENT_REQ_RECEIVED;
+}
+
+bool tevent_req_poll(struct tevent_req *req,
+		     struct tevent_context *ev)
+{
+	while (tevent_req_is_in_progress(req)) {
+		int ret;
+
+		ret = tevent_loop_once(ev);
+		if (ret != 0) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
+			uint64_t *error)
+{
+	if (req->internal.state == TEVENT_REQ_DONE) {
+		return false;
+	}
+	if (req->internal.state == TEVENT_REQ_USER_ERROR) {
+		*error = req->internal.error;
+	}
+	*state = req->internal.state;
+	return true;
+}
+
+static void tevent_req_timedout(struct tevent_context *ev,
+			       struct tevent_timer *te,
+			       struct timeval now,
+			       void *private_data)
+{
+	struct tevent_req *req = talloc_get_type(private_data,
+				 struct tevent_req);
+
+	TALLOC_FREE(req->internal.timer);
+
+	tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
+}
+
+bool tevent_req_set_endtime(struct tevent_req *req,
+			    struct tevent_context *ev,
+			    struct timeval endtime)
+{
+	TALLOC_FREE(req->internal.timer);
+
+	req->internal.timer = tevent_add_timer(ev, req, endtime,
+					       tevent_req_timedout,
+					       req);
+	if (tevent_req_nomem(req->internal.timer, req)) {
+		return false;
+	}
+
+	return true;
+}
+
+void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
+{
+	req->async.fn = fn;
+	req->async.private_data = pvt;
+}
+
+void *_tevent_req_callback_data(struct tevent_req *req)
+{
+	return req->async.private_data;
+}
+
+void *_tevent_req_data(struct tevent_req *req)
+{
+	return req->data;
+}
+
+void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn)
+{
+	req->private_print = fn;
+}
+
+void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn)
+{
+	req->private_cancel = fn;
+}
+
+bool _tevent_req_cancel(struct tevent_req *req, const char *location)
+{
+	if (req->private_cancel == NULL) {
+		return false;
+	}
+
+	return req->private_cancel(req);
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_select.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_select.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_select.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,252 @@
+/*
+   Unix SMB/CIFS implementation.
+   main select loop and event handling
+   Copyright (C) Andrew Tridgell	2003-2005
+   Copyright (C) Stefan Metzmacher	2005-2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "tevent.h"
+#include "tevent_util.h"
+#include "tevent_internal.h"
+
+struct select_event_context {
+	/* a pointer back to the generic event_context */
+	struct tevent_context *ev;
+
+	/* the maximum file descriptor number in fd_events */
+	int maxfd;
+
+	/* information for exiting from the event loop */
+	int exit_code;
+};
+
+/*
+  create a select_event_context structure.
+*/
+static int select_event_context_init(struct tevent_context *ev)
+{
+	struct select_event_context *select_ev;
+
+	select_ev = talloc_zero(ev, struct select_event_context);
+	if (!select_ev) return -1;
+	select_ev->ev = ev;
+
+	ev->additional_data = select_ev;
+	return 0;
+}
+
+/*
+  recalculate the maxfd
+*/
+static void calc_maxfd(struct select_event_context *select_ev)
+{
+	struct tevent_fd *fde;
+
+	select_ev->maxfd = 0;
+	for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->fd > select_ev->maxfd) {
+			select_ev->maxfd = fde->fd;
+		}
+	}
+}
+
+
+/* to mark the ev->maxfd invalid
+ * this means we need to recalculate it
+ */
+#define EVENT_INVALID_MAXFD (-1)
+
+/*
+  destroy an fd_event
+*/
+static int select_event_fd_destructor(struct tevent_fd *fde)
+{
+	struct tevent_context *ev = fde->event_ctx;
+	struct select_event_context *select_ev = NULL;
+
+	if (ev) {
+		select_ev = talloc_get_type(ev->additional_data,
+					    struct select_event_context);
+
+		if (select_ev->maxfd == fde->fd) {
+			select_ev->maxfd = EVENT_INVALID_MAXFD;
+		}
+	}
+
+	return tevent_common_fd_destructor(fde);
+}
+
+/*
+  add a fd based event
+  return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+					     int fd, uint16_t flags,
+					     tevent_fd_handler_t handler,
+					     void *private_data,
+					     const char *handler_name,
+					     const char *location)
+{
+	struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
+							   struct select_event_context);
+	struct tevent_fd *fde;
+
+	fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+				   handler, private_data,
+				   handler_name, location);
+	if (!fde) return NULL;
+
+	if ((select_ev->maxfd != EVENT_INVALID_MAXFD)
+	    && (fde->fd > select_ev->maxfd)) {
+		select_ev->maxfd = fde->fd;
+	}
+	talloc_set_destructor(fde, select_event_fd_destructor);
+
+	return fde;
+}
+
+extern pid_t ctdbd_pid;
+
+/*
+  event loop handling using select()
+*/
+static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
+{
+	fd_set r_fds, w_fds;
+	struct tevent_fd *fde;
+	int selrtn;
+
+	/* we maybe need to recalculate the maxfd */
+	if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
+		calc_maxfd(select_ev);
+	}
+
+	FD_ZERO(&r_fds);
+	FD_ZERO(&w_fds);
+
+	/* setup any fd events */
+	for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->flags & TEVENT_FD_READ) {
+			FD_SET(fde->fd, &r_fds);
+		}
+		if (fde->flags & TEVENT_FD_WRITE) {
+			FD_SET(fde->fd, &w_fds);
+		}
+	}
+
+	if (select_ev->ev->signal_events &&
+	    tevent_common_check_signal(select_ev->ev)) {
+		return 0;
+	}
+
+	if (getpid() == ctdbd_pid) tevent_before_wait(select_ev->ev);
+	selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
+	if (getpid() == ctdbd_pid) tevent_after_wait(select_ev->ev);
+
+	if (selrtn == -1 && errno == EINTR &&
+	    select_ev->ev->signal_events) {
+		tevent_common_check_signal(select_ev->ev);
+		return 0;
+	}
+
+	if (selrtn == -1 && errno == EBADF) {
+		/* the socket is dead! this should never
+		   happen as the socket should have first been
+		   made readable and that should have removed
+		   the event, so this must be a bug. This is a
+		   fatal error. */
+		tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
+			     "ERROR: EBADF on select_event_loop_once\n");
+		select_ev->exit_code = EBADF;
+		return -1;
+	}
+
+	if (selrtn == 0 && tvalp) {
+		/* we don't care about a possible delay here */
+		tevent_common_loop_timer_delay(select_ev->ev);
+		return 0;
+	}
+
+	if (selrtn > 0) {
+		/* at least one file descriptor is ready - check
+		   which ones and call the handler, being careful to allow
+		   the handler to remove itself when called */
+		for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
+			uint16_t flags = 0;
+
+			if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
+			if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
+			if (flags) {
+				fde->handler(select_ev->ev, fde, flags, fde->private_data);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+  do a single event loop using the events defined in ev
+*/
+static int select_event_loop_once(struct tevent_context *ev, const char *location)
+{
+	struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
+							   struct select_event_context);
+	struct timeval tval;
+
+	if (ev->signal_events &&
+	    tevent_common_check_signal(ev)) {
+		return 0;
+	}
+
+	if (ev->immediate_events &&
+	    tevent_common_loop_immediate(ev)) {
+		return 0;
+	}
+
+	tval = tevent_common_loop_timer_delay(ev);
+	if (tevent_timeval_is_zero(&tval)) {
+		return 0;
+	}
+
+	return select_event_loop_select(select_ev, &tval);
+}
+
+static const struct tevent_ops select_event_ops = {
+	.context_init		= select_event_context_init,
+	.add_fd			= select_event_add_fd,
+	.set_fd_close_fn	= tevent_common_fd_set_close_fn,
+	.get_fd_flags		= tevent_common_fd_get_flags,
+	.set_fd_flags		= tevent_common_fd_set_flags,
+	.add_timer		= tevent_common_add_timer,
+	.schedule_immediate	= tevent_common_schedule_immediate,
+	.add_signal		= tevent_common_add_signal,
+	.loop_once		= select_event_loop_once,
+	.loop_wait		= tevent_common_loop_wait,
+};
+
+_PRIVATE_ bool tevent_select_init(void)
+{
+	return tevent_register_backend("select", &select_event_ops);
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_signal.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_signal.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_signal.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,423 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   common events code for signal events
+
+   Copyright (C) Andrew Tridgell	2007
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+#define TEVENT_NUM_SIGNALS 64
+
+/* maximum number of SA_SIGINFO signals to hold in the queue.
+  NB. This *MUST* be a power of 2, in order for the ring buffer
+  wrap to work correctly. Thanks to Petr Vandrovec <petr at vandrovec.name>
+  for this. */
+
+#define TEVENT_SA_INFO_QUEUE_COUNT 64
+
+struct tevent_sigcounter {
+	uint32_t count;
+	uint32_t seen;
+};
+
+#define TEVENT_SIG_INCREMENT(s) (s).count++
+#define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
+#define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
+
+struct tevent_common_signal_list {
+	struct tevent_common_signal_list *prev, *next;
+	struct tevent_signal *se;
+};
+
+/*
+  the poor design of signals means that this table must be static global
+*/
+static struct tevent_sig_state {
+	struct tevent_common_signal_list *sig_handlers[TEVENT_NUM_SIGNALS+1];
+	struct sigaction *oldact[TEVENT_NUM_SIGNALS+1];
+	struct tevent_sigcounter signal_count[TEVENT_NUM_SIGNALS+1];
+	struct tevent_sigcounter got_signal;
+#ifdef SA_SIGINFO
+	/* with SA_SIGINFO we get quite a lot of info per signal */
+	siginfo_t *sig_info[TEVENT_NUM_SIGNALS+1];
+	struct tevent_sigcounter sig_blocked[TEVENT_NUM_SIGNALS+1];
+#endif
+} *sig_state;
+
+/*
+  return number of sigcounter events not processed yet
+*/
+static uint32_t tevent_sig_count(struct tevent_sigcounter s)
+{
+	return s.count - s.seen;
+}
+
+/*
+  signal handler - redirects to registered signals
+*/
+static void tevent_common_signal_handler(int signum)
+{
+	char c = 0;
+	ssize_t res;
+	struct tevent_common_signal_list *sl;
+	struct tevent_context *ev = NULL;
+	int saved_errno = errno;
+
+	TEVENT_SIG_INCREMENT(sig_state->signal_count[signum]);
+	TEVENT_SIG_INCREMENT(sig_state->got_signal);
+
+	/* Write to each unique event context. */
+	for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
+		if (sl->se->event_ctx && sl->se->event_ctx != ev) {
+			ev = sl->se->event_ctx;
+			/* doesn't matter if this pipe overflows */
+			res = write(ev->pipe_fds[1], &c, 1);
+		}
+	}
+
+	errno = saved_errno;
+}
+
+#ifdef SA_SIGINFO
+/*
+  signal handler with SA_SIGINFO - redirects to registered signals
+*/
+static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
+					      void *uctx)
+{
+	uint32_t count = tevent_sig_count(sig_state->signal_count[signum]);
+	/* sig_state->signal_count[signum].seen % TEVENT_SA_INFO_QUEUE_COUNT
+	 * is the base of the unprocessed signals in the ringbuffer. */
+	uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
+				TEVENT_SA_INFO_QUEUE_COUNT;
+	sig_state->sig_info[signum][ofs] = *info;
+
+	tevent_common_signal_handler(signum);
+
+	/* handle SA_SIGINFO */
+	if (count+1 == TEVENT_SA_INFO_QUEUE_COUNT) {
+		/* we've filled the info array - block this signal until
+		   these ones are delivered */
+		sigset_t set;
+		sigemptyset(&set);
+		sigaddset(&set, signum);
+		sigprocmask(SIG_BLOCK, &set, NULL);
+		TEVENT_SIG_INCREMENT(sig_state->sig_blocked[signum]);
+	}
+}
+#endif
+
+static int tevent_common_signal_list_destructor(struct tevent_common_signal_list *sl)
+{
+	if (sig_state->sig_handlers[sl->se->signum]) {
+		DLIST_REMOVE(sig_state->sig_handlers[sl->se->signum], sl);
+	}
+	return 0;
+}
+
+/*
+  destroy a signal event
+*/
+static int tevent_signal_destructor(struct tevent_signal *se)
+{
+	struct tevent_common_signal_list *sl;
+	sl = talloc_get_type(se->additional_data,
+			     struct tevent_common_signal_list);
+
+	if (se->event_ctx) {
+		DLIST_REMOVE(se->event_ctx->signal_events, se);
+	}
+
+	talloc_free(sl);
+
+	if (sig_state->sig_handlers[se->signum] == NULL) {
+		/* restore old handler, if any */
+		if (sig_state->oldact[se->signum]) {
+			sigaction(se->signum, sig_state->oldact[se->signum], NULL);
+			sig_state->oldact[se->signum] = NULL;
+		}
+#ifdef SA_SIGINFO
+		if (se->sa_flags & SA_SIGINFO) {
+			if (sig_state->sig_info[se->signum]) {
+				talloc_free(sig_state->sig_info[se->signum]);
+				sig_state->sig_info[se->signum] = NULL;
+			}
+		}
+#endif
+	}
+
+	return 0;
+}
+
+/*
+  this is part of the pipe hack needed to avoid the signal race condition
+*/
+static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
+				uint16_t flags, void *_private)
+{
+	char c[16];
+	ssize_t res;
+	/* its non-blocking, doesn't matter if we read too much */
+	res = read(fde->fd, c, sizeof(c));
+}
+
+/*
+  add a signal event
+  return NULL on failure (memory allocation error)
+*/
+struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
+					       TALLOC_CTX *mem_ctx,
+					       int signum,
+					       int sa_flags,
+					       tevent_signal_handler_t handler,
+					       void *private_data,
+					       const char *handler_name,
+					       const char *location)
+{
+	struct tevent_signal *se;
+	struct tevent_common_signal_list *sl;
+	sigset_t set, oldset;
+
+	if (signum >= TEVENT_NUM_SIGNALS) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/* the sig_state needs to be on a global context as it can last across
+	   multiple event contexts */
+	if (sig_state == NULL) {
+		sig_state = talloc_zero(talloc_autofree_context(), struct tevent_sig_state);
+		if (sig_state == NULL) {
+			return NULL;
+		}
+	}
+
+	se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
+	if (se == NULL) return NULL;
+
+	se->event_ctx		= ev;
+	se->signum              = signum;
+	se->sa_flags            = sa_flags;
+	se->handler		= handler;
+	se->private_data	= private_data;
+	se->handler_name	= handler_name;
+	se->location		= location;
+	se->additional_data	= NULL;
+
+	sl = talloc(se, struct tevent_common_signal_list);
+	if (!sl) {
+		talloc_free(se);
+		return NULL;
+	}
+	sl->se = se;
+	se->additional_data	= sl;
+
+	/* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
+	if (!talloc_reference(se, sig_state)) {
+		talloc_free(se);
+		return NULL;
+	}
+
+	/* we need to setup the pipe hack handler if not already
+	   setup */
+	if (ev->pipe_fde == NULL) {
+		if (pipe(ev->pipe_fds) == -1) {
+			talloc_free(se);
+			return NULL;
+		}
+		ev_set_blocking(ev->pipe_fds[0], false);
+		ev_set_blocking(ev->pipe_fds[1], false);
+		ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
+					     TEVENT_FD_READ,
+					     signal_pipe_handler, NULL);
+		if (!ev->pipe_fde) {
+			close(ev->pipe_fds[0]);
+			close(ev->pipe_fds[1]);
+			talloc_free(se);
+			return NULL;
+		}
+	}
+
+	/* only install a signal handler if not already installed */
+	if (sig_state->sig_handlers[signum] == NULL) {
+		struct sigaction act;
+		ZERO_STRUCT(act);
+		act.sa_handler = tevent_common_signal_handler;
+		act.sa_flags = sa_flags;
+#ifdef SA_SIGINFO
+		if (sa_flags & SA_SIGINFO) {
+			act.sa_handler   = NULL;
+			act.sa_sigaction = tevent_common_signal_handler_info;
+			if (sig_state->sig_info[signum] == NULL) {
+				sig_state->sig_info[signum] =
+					talloc_zero_array(sig_state, siginfo_t,
+							  TEVENT_SA_INFO_QUEUE_COUNT);
+				if (sig_state->sig_info[signum] == NULL) {
+					talloc_free(se);
+					return NULL;
+				}
+			}
+		}
+#endif
+		sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
+		if (sig_state->oldact[signum] == NULL) {
+			talloc_free(se);
+			return NULL;
+		}
+		if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
+			talloc_free(se);
+			return NULL;
+		}
+	}
+
+	DLIST_ADD(se->event_ctx->signal_events, se);
+
+	/* Make sure the signal doesn't come in while we're mangling list. */
+	sigemptyset(&set);
+	sigaddset(&set, signum);
+	sigprocmask(SIG_BLOCK, &set, &oldset);
+	DLIST_ADD(sig_state->sig_handlers[signum], sl);
+	sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+	talloc_set_destructor(se, tevent_signal_destructor);
+	talloc_set_destructor(sl, tevent_common_signal_list_destructor);
+
+	return se;
+}
+
+
+/*
+  check if a signal is pending
+  return != 0 if a signal was pending
+*/
+int tevent_common_check_signal(struct tevent_context *ev)
+{
+	int i;
+
+	if (!sig_state || !TEVENT_SIG_PENDING(sig_state->got_signal)) {
+		return 0;
+	}
+
+	for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
+		struct tevent_common_signal_list *sl, *next;
+		struct tevent_sigcounter counter = sig_state->signal_count[i];
+		uint32_t count = tevent_sig_count(counter);
+#ifdef SA_SIGINFO
+		/* Ensure we null out any stored siginfo_t entries
+		 * after processing for debugging purposes. */
+		bool clear_processed_siginfo = false;
+#endif
+
+		if (count == 0) {
+			continue;
+		}
+		for (sl=sig_state->sig_handlers[i];sl;sl=next) {
+			struct tevent_signal *se = sl->se;
+			next = sl->next;
+#ifdef SA_SIGINFO
+			if (se->sa_flags & SA_SIGINFO) {
+				uint32_t j;
+
+				clear_processed_siginfo = true;
+
+				for (j=0;j<count;j++) {
+					/* sig_state->signal_count[i].seen
+					 * % TEVENT_SA_INFO_QUEUE_COUNT is
+					 * the base position of the unprocessed
+					 * signals in the ringbuffer. */
+					uint32_t ofs = (counter.seen + j)
+						% TEVENT_SA_INFO_QUEUE_COUNT;
+					se->handler(ev, se, i, 1,
+						    (void*)&sig_state->sig_info[i][ofs],
+						    se->private_data);
+				}
+				if (se->sa_flags & SA_RESETHAND) {
+					talloc_free(se);
+				}
+				continue;
+			}
+#endif
+			se->handler(ev, se, i, count, NULL, se->private_data);
+			if (se->sa_flags & SA_RESETHAND) {
+				talloc_free(se);
+			}
+		}
+
+#ifdef SA_SIGINFO
+		if (clear_processed_siginfo) {
+			uint32_t j;
+			for (j=0;j<count;j++) {
+				uint32_t ofs = (counter.seen + j)
+					% TEVENT_SA_INFO_QUEUE_COUNT;
+				memset((void*)&sig_state->sig_info[i][ofs],
+					'\0',
+					sizeof(siginfo_t));
+			}
+		}
+#endif
+
+		TEVENT_SIG_SEEN(sig_state->signal_count[i], count);
+		TEVENT_SIG_SEEN(sig_state->got_signal, count);
+
+#ifdef SA_SIGINFO
+		if (TEVENT_SIG_PENDING(sig_state->sig_blocked[i])) {
+			/* We'd filled the queue, unblock the
+			   signal now the queue is empty again.
+			   Note we MUST do this after the
+			   TEVENT_SIG_SEEN(sig_state->signal_count[i], count)
+			   call to prevent a new signal running
+			   out of room in the sig_state->sig_info[i][]
+			   ring buffer. */
+			sigset_t set;
+			sigemptyset(&set);
+			sigaddset(&set, i);
+			TEVENT_SIG_SEEN(sig_state->sig_blocked[i],
+				 tevent_sig_count(sig_state->sig_blocked[i]));
+			sigprocmask(SIG_UNBLOCK, &set, NULL);
+		}
+#endif
+	}
+
+	return 1;
+}
+
+void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
+{
+	struct tevent_common_signal_list *sl;
+	sl = talloc_get_type(se->additional_data,
+			     struct tevent_common_signal_list);
+
+	tevent_common_signal_list_destructor(sl);
+
+	if (sig_state->sig_handlers[se->signum] == NULL) {
+		if (sig_state->oldact[se->signum]) {
+			sigaction(se->signum, sig_state->oldact[se->signum], NULL);
+			sig_state->oldact[se->signum] = NULL;
+		}
+	}
+	return;
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_standard.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_standard.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_standard.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,572 @@
+/*
+   Unix SMB/CIFS implementation.
+   main select loop and event handling
+   Copyright (C) Andrew Tridgell	2003-2005
+   Copyright (C) Stefan Metzmacher	2005-2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  This is SAMBA's default event loop code
+
+  - we try to use epoll if configure detected support for it
+    otherwise we use select()
+  - if epoll is broken on the system or the kernel doesn't support it
+    at runtime we fallback to select()
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "tevent.h"
+#include "tevent_util.h"
+#include "tevent_internal.h"
+
+struct std_event_context {
+	/* a pointer back to the generic event_context */
+	struct tevent_context *ev;
+
+	/* the maximum file descriptor number in fd_events */
+	int maxfd;
+
+	/* information for exiting from the event loop */
+	int exit_code;
+
+	/* when using epoll this is the handle from epoll_create */
+	int epoll_fd;
+
+	/* our pid at the time the epoll_fd was created */
+	pid_t pid;
+};
+
+/* use epoll if it is available */
+#if HAVE_EPOLL
+/*
+  called when a epoll call fails, and we should fallback
+  to using select
+*/
+static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason)
+{
+	tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+		     "%s (%s) - falling back to select()\n",
+		     reason, strerror(errno));
+	close(std_ev->epoll_fd);
+	std_ev->epoll_fd = -1;
+	talloc_set_destructor(std_ev, NULL);
+}
+
+/*
+  map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
+*/
+static uint32_t epoll_map_flags(uint16_t flags)
+{
+	uint32_t ret = 0;
+	if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
+	if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
+	return ret;
+}
+
+/*
+ free the epoll fd
+*/
+static int epoll_ctx_destructor(struct std_event_context *std_ev)
+{
+	if (std_ev->epoll_fd != -1) {
+		close(std_ev->epoll_fd);
+	}
+	std_ev->epoll_fd = -1;
+	return 0;
+}
+
+/*
+ init the epoll fd
+*/
+static void epoll_init_ctx(struct std_event_context *std_ev)
+{
+	std_ev->epoll_fd = epoll_create(64);
+	std_ev->pid = getpid();
+	talloc_set_destructor(std_ev, epoll_ctx_destructor);
+}
+
+static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde);
+
+/*
+  reopen the epoll handle when our pid changes
+  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
+  demonstration of why this is needed
+ */
+static void epoll_check_reopen(struct std_event_context *std_ev)
+{
+	struct tevent_fd *fde;
+
+	if (std_ev->pid == getpid()) {
+		return;
+	}
+
+	close(std_ev->epoll_fd);
+	std_ev->epoll_fd = epoll_create(64);
+	if (std_ev->epoll_fd == -1) {
+		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+			     "Failed to recreate epoll handle after fork\n");
+		return;
+	}
+	std_ev->pid = getpid();
+	for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
+		epoll_add_event(std_ev, fde);
+	}
+}
+
+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT	(1<<0)
+#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR	(1<<1)
+#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR	(1<<2)
+
+/*
+ add the epoll event to the given fd_event
+*/
+static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+	if (std_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* if we don't want events yet, don't add an epoll_event */
+	if (fde->flags == 0) return;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
+		epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed");
+	}
+	fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+
+	/* only if we want to read we want to tell the event handler about errors */
+	if (fde->flags & TEVENT_FD_READ) {
+		fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+	}
+}
+
+/*
+ delete the epoll event for given fd_event
+*/
+static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+	if (std_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* if there's no epoll_event, we don't need to delete it */
+	if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+}
+
+/*
+ change the epoll event to the given fd_event
+*/
+static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+	struct epoll_event event;
+	if (std_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	ZERO_STRUCT(event);
+	event.events = epoll_map_flags(fde->flags);
+	event.data.ptr = fde;
+	if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
+		epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed");
+	}
+
+	/* only if we want to read we want to tell the event handler about errors */
+	if (fde->flags & TEVENT_FD_READ) {
+		fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+	}
+}
+
+static void epoll_change_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+{
+	bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
+	bool want_read = (fde->flags & TEVENT_FD_READ);
+	bool want_write= (fde->flags & TEVENT_FD_WRITE);
+
+	if (std_ev->epoll_fd == -1) return;
+
+	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+
+	/* there's already an event */
+	if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
+		if (want_read || (want_write && !got_error)) {
+			epoll_mod_event(std_ev, fde);
+			return;
+		}
+		/*
+		 * if we want to match the select behavior, we need to remove the epoll_event
+		 * when the caller isn't interested in events.
+		 *
+		 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
+		 */
+		epoll_del_event(std_ev, fde);
+		return;
+	}
+
+	/* there's no epoll_event attached to the fde */
+	if (want_read || (want_write && !got_error)) {
+		epoll_add_event(std_ev, fde);
+		return;
+	}
+}
+
+extern pid_t ctdbd_pid;
+
+/*
+  event loop handling using epoll
+*/
+static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
+{
+	int ret, i;
+#define MAXEVENTS 1
+	struct epoll_event events[MAXEVENTS];
+	int timeout = -1;
+
+	if (std_ev->epoll_fd == -1) return -1;
+
+	if (tvalp) {
+		/* it's better to trigger timed events a bit later than to early */
+		timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
+	}
+
+	if (std_ev->ev->signal_events &&
+	    tevent_common_check_signal(std_ev->ev)) {
+		return 0;
+	}
+
+	if (getpid() == ctdbd_pid) tevent_before_wait(std_ev->ev);
+	ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout);
+	if (getpid() == ctdbd_pid) tevent_after_wait(std_ev->ev);
+
+	if (ret == -1 && errno == EINTR && std_ev->ev->signal_events) {
+		if (tevent_common_check_signal(std_ev->ev)) {
+			return 0;
+		}
+	}
+
+	if (ret == -1 && errno != EINTR) {
+		epoll_fallback_to_select(std_ev, "epoll_wait() failed");
+		return -1;
+	}
+
+	if (ret == 0 && tvalp) {
+		/* we don't care about a possible delay here */
+		tevent_common_loop_timer_delay(std_ev->ev);
+		return 0;
+	}
+
+	for (i=0;i<ret;i++) {
+		struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
+						       struct tevent_fd);
+		uint16_t flags = 0;
+
+		if (fde == NULL) {
+			epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data");
+			return -1;
+		}
+		if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+			fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+			/*
+			 * if we only wait for TEVENT_FD_WRITE, we should not tell the
+			 * event handler about it, and remove the epoll_event,
+			 * as we only report errors when waiting for read events,
+			 * to match the select() behavior
+			 */
+			if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
+				epoll_del_event(std_ev, fde);
+				continue;
+			}
+			flags |= TEVENT_FD_READ;
+		}
+		if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
+		if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
+		if (flags) {
+			fde->handler(std_ev->ev, fde, flags, fde->private_data);
+			break;
+		}
+	}
+
+	return 0;
+}
+#else
+#define epoll_init_ctx(std_ev)
+#define epoll_add_event(std_ev,fde)
+#define epoll_del_event(std_ev,fde)
+#define epoll_change_event(std_ev,fde)
+#define epoll_event_loop(std_ev,tvalp) (-1)
+#define epoll_check_reopen(std_ev)
+#endif
+
+/*
+  create a std_event_context structure.
+*/
+static int std_event_context_init(struct tevent_context *ev)
+{
+	struct std_event_context *std_ev;
+
+	std_ev = talloc_zero(ev, struct std_event_context);
+	if (!std_ev) return -1;
+	std_ev->ev = ev;
+	std_ev->epoll_fd = -1;
+
+	epoll_init_ctx(std_ev);
+
+	ev->additional_data = std_ev;
+	return 0;
+}
+
+/*
+  recalculate the maxfd
+*/
+static void calc_maxfd(struct std_event_context *std_ev)
+{
+	struct tevent_fd *fde;
+
+	std_ev->maxfd = 0;
+	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->fd > std_ev->maxfd) {
+			std_ev->maxfd = fde->fd;
+		}
+	}
+}
+
+
+/* to mark the ev->maxfd invalid
+ * this means we need to recalculate it
+ */
+#define EVENT_INVALID_MAXFD (-1)
+
+/*
+  destroy an fd_event
+*/
+static int std_event_fd_destructor(struct tevent_fd *fde)
+{
+	struct tevent_context *ev = fde->event_ctx;
+	struct std_event_context *std_ev = NULL;
+
+	if (ev) {
+		std_ev = talloc_get_type(ev->additional_data,
+					 struct std_event_context);
+
+		epoll_check_reopen(std_ev);
+
+		if (std_ev->maxfd == fde->fd) {
+			std_ev->maxfd = EVENT_INVALID_MAXFD;
+		}
+
+		epoll_del_event(std_ev, fde);
+	}
+
+	return tevent_common_fd_destructor(fde);
+}
+
+/*
+  add a fd based event
+  return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *std_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+					  int fd, uint16_t flags,
+					  tevent_fd_handler_t handler,
+					  void *private_data,
+					  const char *handler_name,
+					  const char *location)
+{
+	struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
+							   struct std_event_context);
+	struct tevent_fd *fde;
+
+	epoll_check_reopen(std_ev);
+
+	fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+				   handler, private_data,
+				   handler_name, location);
+	if (!fde) return NULL;
+
+	if ((std_ev->maxfd != EVENT_INVALID_MAXFD)
+	    && (fde->fd > std_ev->maxfd)) {
+		std_ev->maxfd = fde->fd;
+	}
+	talloc_set_destructor(fde, std_event_fd_destructor);
+
+	epoll_add_event(std_ev, fde);
+
+	return fde;
+}
+
+/*
+  set the fd event flags
+*/
+static void std_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+	struct tevent_context *ev;
+	struct std_event_context *std_ev;
+
+	if (fde->flags == flags) return;
+
+	ev = fde->event_ctx;
+	std_ev = talloc_get_type(ev->additional_data, struct std_event_context);
+
+	fde->flags = flags;
+
+	epoll_check_reopen(std_ev);
+
+	epoll_change_event(std_ev, fde);
+}
+
+/*
+  event loop handling using select()
+*/
+static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp)
+{
+	fd_set r_fds, w_fds;
+	struct tevent_fd *fde;
+	int selrtn;
+
+	/* we maybe need to recalculate the maxfd */
+	if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
+		calc_maxfd(std_ev);
+	}
+
+	FD_ZERO(&r_fds);
+	FD_ZERO(&w_fds);
+
+	/* setup any fd events */
+	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+		if (fde->flags & TEVENT_FD_READ) {
+			FD_SET(fde->fd, &r_fds);
+		}
+		if (fde->flags & TEVENT_FD_WRITE) {
+			FD_SET(fde->fd, &w_fds);
+		}
+	}
+
+	if (std_ev->ev->signal_events &&
+	    tevent_common_check_signal(std_ev->ev)) {
+		return 0;
+	}
+
+	selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
+
+	if (selrtn == -1 && errno == EINTR &&
+	    std_ev->ev->signal_events) {
+		tevent_common_check_signal(std_ev->ev);
+		return 0;
+	}
+
+	if (selrtn == -1 && errno == EBADF) {
+		/* the socket is dead! this should never
+		   happen as the socket should have first been
+		   made readable and that should have removed
+		   the event, so this must be a bug. This is a
+		   fatal error. */
+		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
+			     "ERROR: EBADF on std_event_loop_once\n");
+		std_ev->exit_code = EBADF;
+		return -1;
+	}
+
+	if (selrtn == 0 && tvalp) {
+		/* we don't care about a possible delay here */
+		tevent_common_loop_timer_delay(std_ev->ev);
+		return 0;
+	}
+
+	if (selrtn > 0) {
+		/* at least one file descriptor is ready - check
+		   which ones and call the handler, being careful to allow
+		   the handler to remove itself when called */
+		for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
+			uint16_t flags = 0;
+
+			if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
+			if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
+			if (flags) {
+				fde->handler(std_ev->ev, fde, flags, fde->private_data);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+  do a single event loop using the events defined in ev
+*/
+static int std_event_loop_once(struct tevent_context *ev, const char *location)
+{
+	struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
+							   struct std_event_context);
+	struct timeval tval;
+
+	if (ev->signal_events &&
+	    tevent_common_check_signal(ev)) {
+		return 0;
+	}
+
+	if (ev->immediate_events &&
+	    tevent_common_loop_immediate(ev)) {
+		return 0;
+	}
+
+	tval = tevent_common_loop_timer_delay(ev);
+	if (tevent_timeval_is_zero(&tval)) {
+		return 0;
+	}
+
+	epoll_check_reopen(std_ev);
+
+	if (epoll_event_loop(std_ev, &tval) == 0) {
+		return 0;
+	}
+
+	return std_event_loop_select(std_ev, &tval);
+}
+
+static const struct tevent_ops std_event_ops = {
+	.context_init		= std_event_context_init,
+	.add_fd			= std_event_add_fd,
+	.set_fd_close_fn	= tevent_common_fd_set_close_fn,
+	.get_fd_flags		= tevent_common_fd_get_flags,
+	.set_fd_flags		= std_event_set_fd_flags,
+	.add_timer		= tevent_common_add_timer,
+	.schedule_immediate	= tevent_common_schedule_immediate,
+	.add_signal		= tevent_common_add_signal,
+	.loop_once		= std_event_loop_once,
+	.loop_wait		= tevent_common_loop_wait,
+};
+
+
+_PRIVATE_ bool tevent_standard_init(void)
+{
+	return tevent_register_backend("standard", &std_event_ops);
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_timed.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_timed.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_timed.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,267 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   common events code for timed events
+
+   Copyright (C) Andrew Tridgell	2003-2006
+   Copyright (C) Stefan Metzmacher	2005-2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+/**
+  compare two timeval structures.
+  Return -1 if tv1 < tv2
+  Return 0 if tv1 == tv2
+  Return 1 if tv1 > tv2
+*/
+int tevent_timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
+{
+	if (tv1->tv_sec  > tv2->tv_sec)  return 1;
+	if (tv1->tv_sec  < tv2->tv_sec)  return -1;
+	if (tv1->tv_usec > tv2->tv_usec) return 1;
+	if (tv1->tv_usec < tv2->tv_usec) return -1;
+	return 0;
+}
+
+/**
+  return a zero timeval
+*/
+struct timeval tevent_timeval_zero(void)
+{
+	struct timeval tv;
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	return tv;
+}
+
+/**
+  return a timeval for the current time
+*/
+struct timeval tevent_timeval_current(void)
+{
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return tv;
+}
+
+/**
+  return a timeval struct with the given elements
+*/
+struct timeval tevent_timeval_set(uint32_t secs, uint32_t usecs)
+{
+	struct timeval tv;
+	tv.tv_sec = secs;
+	tv.tv_usec = usecs;
+	return tv;
+}
+
+/**
+  return the difference between two timevals as a timeval
+  if tv1 comes after tv2, then return a zero timeval
+  (this is *tv2 - *tv1)
+*/
+struct timeval tevent_timeval_until(const struct timeval *tv1,
+				    const struct timeval *tv2)
+{
+	struct timeval t;
+	if (tevent_timeval_compare(tv1, tv2) >= 0) {
+		return tevent_timeval_zero();
+	}
+	t.tv_sec = tv2->tv_sec - tv1->tv_sec;
+	if (tv1->tv_usec > tv2->tv_usec) {
+		t.tv_sec--;
+		t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
+	} else {
+		t.tv_usec = tv2->tv_usec - tv1->tv_usec;
+	}
+	return t;
+}
+
+/**
+  return true if a timeval is zero
+*/
+bool tevent_timeval_is_zero(const struct timeval *tv)
+{
+	return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+struct timeval tevent_timeval_add(const struct timeval *tv, uint32_t secs,
+				  uint32_t usecs)
+{
+	struct timeval tv2 = *tv;
+	tv2.tv_sec += secs;
+	tv2.tv_usec += usecs;
+	tv2.tv_sec += tv2.tv_usec / 1000000;
+	tv2.tv_usec = tv2.tv_usec % 1000000;
+
+	return tv2;
+}
+
+/**
+  return a timeval in the future with a specified offset
+*/
+struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs)
+{
+	struct timeval tv = tevent_timeval_current();
+	return tevent_timeval_add(&tv, secs, usecs);
+}
+
+/*
+  destroy a timed event
+*/
+static int tevent_common_timed_destructor(struct tevent_timer *te)
+{
+	tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+		     "Destroying timer event %p \"%s\"\n",
+		     te, te->handler_name);
+
+	if (te->event_ctx) {
+		DLIST_REMOVE(te->event_ctx->timer_events, te);
+	}
+
+	return 0;
+}
+
+static int tevent_common_timed_deny_destructor(struct tevent_timer *te)
+{
+	return -1;
+}
+
+/*
+  add a timed event
+  return NULL on failure (memory allocation error)
+*/
+struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+					     struct timeval next_event,
+					     tevent_timer_handler_t handler,
+					     void *private_data,
+					     const char *handler_name,
+					     const char *location)
+{
+	struct tevent_timer *te, *last_te, *cur_te;
+
+	te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
+	if (te == NULL) return NULL;
+
+	te->event_ctx		= ev;
+	te->next_event		= next_event;
+	te->handler		= handler;
+	te->private_data	= private_data;
+	te->handler_name	= handler_name;
+	te->location		= location;
+	te->additional_data	= NULL;
+
+	/* keep the list ordered */
+	last_te = NULL;
+	for (cur_te = ev->timer_events; cur_te; cur_te = cur_te->next) {
+		/* if the new event comes before the current one break */
+		if (tevent_timeval_compare(&te->next_event, &cur_te->next_event) < 0) {
+			break;
+		}
+
+		last_te = cur_te;
+	}
+
+	DLIST_ADD_AFTER(ev->timer_events, te, last_te);
+
+	talloc_set_destructor(te, tevent_common_timed_destructor);
+
+	tevent_debug(ev, TEVENT_DEBUG_TRACE,
+		     "Added timed event \"%s\": %p\n",
+		     handler_name, te);
+	return te;
+}
+
+/*
+  do a single event loop using the events defined in ev
+
+  return the delay untill the next timed event,
+  or zero if a timed event was triggered
+*/
+struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
+{
+	struct timeval current_time = tevent_timeval_zero();
+	struct tevent_timer *te = ev->timer_events;
+
+	if (!te) {
+		/* have a default tick time of 30 seconds. This guarantees
+		   that code that uses its own timeout checking will be
+		   able to proceeed eventually */
+		return tevent_timeval_set(30, 0);
+	}
+
+	/*
+	 * work out the right timeout for the next timed event
+	 *
+	 * avoid the syscall to gettimeofday() if the timed event should
+	 * be triggered directly
+	 *
+	 * if there's a delay till the next timed event, we're done
+	 * with just returning the delay
+	 */
+	if (!tevent_timeval_is_zero(&te->next_event)) {
+		struct timeval delay;
+
+		current_time = tevent_timeval_current();
+
+		delay = tevent_timeval_until(&current_time, &te->next_event);
+		if (!tevent_timeval_is_zero(&delay)) {
+			return delay;
+		}
+	}
+
+	/*
+	 * ok, we have a timed event that we'll process ...
+	 */
+
+	/* deny the handler to free the event */
+	talloc_set_destructor(te, tevent_common_timed_deny_destructor);
+
+	/* We need to remove the timer from the list before calling the
+	 * handler because in a semi-async inner event loop called from the
+	 * handler we don't want to come across this event again -- vl */
+	DLIST_REMOVE(ev->timer_events, te);
+
+	/*
+	 * If the timed event was registered for a zero current_time,
+	 * then we pass a zero timeval here too! To avoid the
+	 * overhead of gettimeofday() calls.
+	 *
+	 * otherwise we pass the current time
+	 */
+	te->handler(ev, te, current_time, te->private_data);
+
+	/* The destructor isn't necessary anymore, we've already removed the
+	 * event from the list. */
+	talloc_set_destructor(te, NULL);
+
+	tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+		     "Ending timer event %p \"%s\"\n",
+		     te, te->handler_name);
+
+	talloc_free(te);
+
+	return tevent_timeval_zero();
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_util.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_util.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_util.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,141 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Jelmer Vernooij 2005
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "talloc.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+#include <fcntl.h>
+
+/**
+  return the number of elements in a string list
+*/
+size_t ev_str_list_length(const char **list)
+{
+	size_t ret;
+	for (ret=0;list && list[ret];ret++) /* noop */ ;
+	return ret;
+}
+
+/**
+  add an entry to a string list
+*/
+const char **ev_str_list_add(const char **list, const char *s)
+{
+	size_t len = ev_str_list_length(list);
+	const char **ret;
+
+	ret = talloc_realloc(NULL, list, const char *, len+2);
+	if (ret == NULL) return NULL;
+
+	ret[len] = talloc_strdup(ret, s);
+	if (ret[len] == NULL) return NULL;
+
+	ret[len+1] = NULL;
+
+	return ret;
+}
+
+
+/**
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+  if SYSV use O_NDELAY
+  if BSD use FNDELAY
+**/
+
+int ev_set_blocking(int fd, bool set)
+{
+	int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+	if((val = fcntl(fd, F_GETFL, 0)) == -1)
+		return -1;
+	if(set) /* Turn blocking on - ie. clear nonblock flag */
+		val &= ~FLAG_TO_SET;
+	else
+		val |= FLAG_TO_SET;
+	return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
+
+static struct timeval tevent_before_wait_ts;
+static struct timeval tevent_after_wait_ts;
+
+/*
+ * measure the time difference between multiple arrivals
+ * to the point where we wait for new events to come in
+ *
+ * allows to measure how long it takes to work on a 
+ * event
+ */
+void tevent_before_wait(struct event_context *ev) {
+
+	struct timeval diff;
+	struct timeval now = tevent_timeval_current();
+
+	if (!tevent_timeval_is_zero(&tevent_after_wait_ts)) {
+		diff = tevent_timeval_until(&tevent_after_wait_ts, &now);
+		if (diff.tv_sec > 3) {
+			tevent_debug(ev, TEVENT_DEBUG_ERROR,  __location__ 
+				     " Handling event took %d seconds!",
+				     (int) diff.tv_sec);
+		}
+	}
+
+	tevent_before_wait_ts = tevent_timeval_current();
+
+}
+
+/*
+ * measure how long the select()/epoll() call took
+ *
+ * allows to measure how long we are waiting for new events
+ */
+void tevent_after_wait(struct event_context *ev) {
+
+	struct timeval diff;
+	struct timeval now = tevent_timeval_current();
+
+	if (!tevent_timeval_is_zero(&tevent_before_wait_ts)) {
+		diff = tevent_timeval_until(&tevent_before_wait_ts, &now);
+		if (diff.tv_sec > 3) {
+			tevent_debug(ev, TEVENT_DEBUG_FATAL,  __location__
+				     " No event for %d seconds!",
+				     (int) diff.tv_sec);
+		}
+	}
+
+	tevent_after_wait_ts = tevent_timeval_current();
+
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_util.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_util.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_util.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,195 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Andrew Tridgell 1998-2010
+   Copyright (C) Jelmer Vernooij 2005
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* To use these macros you must have a structure containing a next and
+   prev pointer */
+
+#ifndef _DLINKLIST_H
+#define _DLINKLIST_H
+
+/*
+  February 2010 - changed list format to have a prev pointer from the
+  list head. This makes DLIST_ADD_END() O(1) even though we only have
+  one list pointer.
+
+  The scheme is as follows:
+
+     1) with no entries in the list:
+          list_head == NULL
+
+     2) with 1 entry in the list:
+          list_head->next == NULL
+          list_head->prev == list_head
+
+     3) with 2 entries in the list:
+          list_head->next == element2
+          list_head->prev == element2
+	  element2->prev == list_head
+	  element2->next == NULL
+
+     4) with N entries in the list:
+          list_head->next == element2
+          list_head->prev == elementN
+	  elementN->prev == element{N-1}
+	  elementN->next == NULL
+
+  This allows us to find the tail of the list by using
+  list_head->prev, which means we can add to the end of the list in
+  O(1) time
+
+
+  Note that the 'type' arguments below are no longer needed, but
+  are kept for now to prevent an incompatible argument change
+ */
+
+
+/*
+   add an element at the front of a list
+*/
+#define DLIST_ADD(list, p) \
+do { \
+        if (!(list)) { \
+		(p)->prev = (list) = (p);  \
+		(p)->next = NULL; \
+	} else { \
+		(p)->prev = (list)->prev; \
+		(list)->prev = (p); \
+		(p)->next = (list); \
+		(list) = (p); \
+	} \
+} while (0)
+
+/*
+   remove an element from a list
+   Note that the element doesn't have to be in the list. If it
+   isn't then this is a no-op
+*/
+#define DLIST_REMOVE(list, p) \
+do { \
+	if ((p) == (list)) { \
+		if ((p)->next) (p)->next->prev = (p)->prev; \
+		(list) = (p)->next; \
+	} else if ((list) && (p) == (list)->prev) {	\
+		(p)->prev->next = NULL; \
+		(list)->prev = (p)->prev; \
+	} else { \
+		if ((p)->prev) (p)->prev->next = (p)->next; \
+		if ((p)->next) (p)->next->prev = (p)->prev; \
+	} \
+	if ((p) != (list)) (p)->next = (p)->prev = NULL;	\
+} while (0)
+
+/*
+   find the head of the list given any element in it.
+   Note that this costs O(N), so you should avoid this macro
+   if at all possible!
+*/
+#define DLIST_HEAD(p, result_head) \
+do { \
+       (result_head) = (p); \
+       while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
+} while(0)
+
+/* return the last element in the list */
+#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
+
+/* return the previous element in the list. */
+#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
+
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+   this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
+do { \
+        if (!(list) || !(el)) { \
+		DLIST_ADD(list, p); \
+	} else { \
+		(p)->prev = (el);   \
+		(p)->next = (el)->next;		\
+		(el)->next = (p);		\
+		if ((p)->next) (p)->next->prev = (p);	\
+		if ((list)->prev == (el)) (list)->prev = (p); \
+	}\
+} while (0)
+
+
+/*
+   add to the end of a list.
+   Note that 'type' is ignored
+*/
+#define DLIST_ADD_END(list, p, type)			\
+do { \
+	if (!(list)) { \
+		DLIST_ADD(list, p); \
+	} else { \
+		DLIST_ADD_AFTER(list, p, (list)->prev); \
+	} \
+} while (0)
+
+/* promote an element to the from of a list */
+#define DLIST_PROMOTE(list, p) \
+do { \
+          DLIST_REMOVE(list, p); \
+          DLIST_ADD(list, p); \
+} while (0)
+
+/*
+   demote an element to the end of a list.
+   Note that 'type' is ignored
+*/
+#define DLIST_DEMOTE(list, p, type)			\
+do { \
+	DLIST_REMOVE(list, p); \
+	DLIST_ADD_END(list, p, NULL);		\
+} while (0)
+
+/*
+   concatenate two lists - putting all elements of the 2nd list at the
+   end of the first list.
+   Note that 'type' is ignored
+*/
+#define DLIST_CONCATENATE(list1, list2, type)	\
+do { \
+	if (!(list1)) { \
+		(list1) = (list2); \
+	} else { \
+		(list1)->prev->next = (list2); \
+		if (list2) { \
+			void *_tmplist = (void *)(list1)->prev; \
+			(list1)->prev = (list2)->prev; \
+			(list2)->prev = _tmplist; \
+		} \
+	} \
+} while (0)
+
+#endif /* _DLINKLIST_H */
+
+const char **ev_str_list_add(const char **list, const char *s);
+int ev_set_blocking(int fd, bool set);
+size_t ev_str_list_length(const char **list);
+
+void tevent_before_wait(struct event_context *ev);
+void tevent_after_wait(struct event_context *ev);
+
+
+/* Defined here so we can build against older talloc versions that don't
+ * have this define yet. */
+#ifndef TALLOC_FREE
+#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
+#endif

Added: branches/ctdb/squeeze-backports/lib/tevent/tevent_wakeup.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/tevent_wakeup.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/tevent_wakeup.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,69 @@
+/*
+   Unix SMB/CIFS implementation.
+   Infrastructure for async requests
+   Copyright (C) Volker Lendecke 2008
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct tevent_wakeup_state {
+	struct timeval wakeup_time;
+};
+
+struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      struct timeval wakeup_time)
+{
+	struct tevent_req *req;
+	struct tevent_wakeup_state *state;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct tevent_wakeup_state);
+	if (!req) {
+		return NULL;
+	}
+	state->wakeup_time = wakeup_time;
+
+	if (!tevent_req_set_endtime(req, ev, wakeup_time)) {
+		goto post;
+	}
+
+	return req;
+post:
+	return tevent_req_post(req, ev);
+}
+
+bool tevent_wakeup_recv(struct tevent_req *req)
+{
+	enum tevent_req_state state;
+	uint64_t error;
+
+	if (tevent_req_is_error(req, &state, &error)) {
+		if (state == TEVENT_REQ_TIMED_OUT) {
+			return true;
+		}
+	}
+
+	return false;
+}

Added: branches/ctdb/squeeze-backports/lib/tevent/wscript
===================================================================
--- branches/ctdb/squeeze-backports/lib/tevent/wscript	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/tevent/wscript	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+APPNAME = 'tevent'
+VERSION = '0.9.9'
+
+blddir = 'bin'
+
+import sys, os
+
+# find the buildtools directory
+srcdir = '.'
+while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5:
+    srcdir = '../' + srcdir
+sys.path.insert(0, srcdir + '/buildtools/wafsamba')
+
+import wafsamba, samba_dist
+
+samba_dist.DIST_DIRS('lib/tevent:. lib/replace:lib/replace lib/talloc:lib/talloc buildtools:buildtools')
+
+def set_options(opt):
+    opt.BUILTIN_DEFAULT('replace')
+    opt.BUNDLED_EXTENSION_DEFAULT('tevent', noextension='tevent')
+    opt.RECURSE('lib/replace')
+    opt.RECURSE('lib/talloc')
+
+def configure(conf):
+    conf.RECURSE('lib/replace')
+    conf.RECURSE('lib/talloc')
+
+    conf.env.standalone_tevent = conf.IN_LAUNCH_DIR()
+
+    if not conf.env.standalone_tevent:
+        if conf.CHECK_BUNDLED_SYSTEM('tevent', minversion=VERSION,
+                                     onlyif='talloc', implied_deps='replace talloc'):
+            conf.define('USING_SYSTEM_TEVENT', 1)
+
+    if conf.CHECK_FUNCS('epoll_create', headers='sys/epoll.h'):
+        conf.DEFINE('HAVE_EPOLL', 1)
+
+    conf.SAMBA_CONFIG_H()
+
+def build(bld):
+    bld.RECURSE('lib/replace')
+    bld.RECURSE('lib/talloc')
+
+    SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c
+             tevent_queue.c tevent_req.c tevent_select.c
+             tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c'''
+
+    if bld.CONFIG_SET('HAVE_EPOLL'):
+        SRC += ' tevent_epoll.c'
+
+    if not bld.CONFIG_SET('USING_SYSTEM_TEVENT'):
+        bld.SAMBA_LIBRARY('tevent',
+                          SRC,
+                          deps='replace talloc',
+                          enabled= not bld.CONFIG_SET('USING_SYSTEM_TEVENT'),
+                          abi_file='ABI/tevent-%s.sigs' % VERSION,
+                          abi_match='tevent_* _tevent_*',
+                          vnum=VERSION,
+						  is_bundled=not bld.env.standalone_tevent)
+
+    if bld.env.standalone_tevent:
+        bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
+        bld.PKG_CONFIG_FILES('tevent.pc', vnum=VERSION)
+        bld.INSTALL_FILES('${INCLUDEDIR}', 'tevent.h')
+
+def test(ctx):
+    '''test tevent'''
+    print("The tevent testsuite is part of smbtorture in samba4")
+
+
+def dist():
+    '''makes a tarball for distribution'''
+    samba_dist.dist()

Added: branches/ctdb/squeeze-backports/lib/util/db_wrap.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/db_wrap.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/db_wrap.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,103 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   database wrap functions
+
+   Copyright (C) Andrew Tridgell 2004
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  the stupidity of the unix fcntl locking design forces us to never
+  allow a database file to be opened twice in the same process. These
+  wrappers provide convenient access to a tdb or ldb, taking advantage
+  of talloc destructors to ensure that only a single open is done
+*/
+
+#include "includes.h"
+#include "lib/util/dlinklist.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "db_wrap.h"
+
+static struct tdb_wrap *tdb_list;
+
+
+
+/* destroy the last connection to a tdb */
+static int tdb_wrap_destructor(struct tdb_wrap *w)
+{
+	tdb_close(w->tdb);
+	DLIST_REMOVE(tdb_list, w);
+	return 0;
+}				 
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+	if (level <= TDB_DEBUG_ERROR) {
+		va_list ap;
+		char newfmt[strlen(tdb_name(tdb)) + 1 + strlen(fmt) + 1];
+		sprintf(newfmt, "%s:%s", tdb_name(tdb), fmt);
+		va_start(ap, fmt);
+		do_debug_v(newfmt, ap);
+		va_end(ap);
+	}
+}
+
+
+/*
+  wrapped connection to a tdb database
+  to close just talloc_free() the tdb_wrap pointer
+ */
+struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
+			       const char *name, int hash_size, int tdb_flags,
+			       int open_flags, mode_t mode)
+{
+	struct tdb_wrap *w;
+	struct tdb_logging_context log_ctx;
+
+	log_ctx.log_fn = log_fn;
+	log_ctx.log_private = NULL;
+
+	for (w=tdb_list;w;w=w->next) {
+		if (strcmp(name, w->name) == 0) {
+			return talloc_reference(mem_ctx, w);
+		}
+	}
+
+	w = talloc(mem_ctx, struct tdb_wrap);
+	if (w == NULL) {
+		return NULL;
+	}
+
+	w->name = talloc_strdup(w, name);
+	if (w->name == NULL) {
+		talloc_free(w);
+		return NULL;
+	}
+
+	w->tdb = tdb_open_ex(name, hash_size, tdb_flags, 
+			     open_flags, mode, &log_ctx, NULL);
+	if (w->tdb == NULL) {
+		talloc_free(w);
+		return NULL;
+	}
+
+	talloc_set_destructor(w, tdb_wrap_destructor);
+
+	DLIST_ADD(tdb_list, w);
+
+	return w;
+}

Added: branches/ctdb/squeeze-backports/lib/util/db_wrap.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/db_wrap.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/db_wrap.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,32 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   database wrap headers
+
+   Copyright (C) Andrew Tridgell 2004
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+struct tdb_wrap {
+	struct tdb_context *tdb;
+
+	const char *name;
+	struct tdb_wrap *next, *prev;
+};
+
+struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
+			       const char *name, int hash_size, int tdb_flags,
+			       int open_flags, mode_t mode);

Added: branches/ctdb/squeeze-backports/lib/util/debug.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/debug.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/debug.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,136 @@
+/*
+   Unix SMB/CIFS implementation.
+   ctdb debug functions
+   Copyright (C) Volker Lendecke 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include <unistd.h>
+#include <ctype.h>
+
+static void _do_debug_v(const char *format, va_list ap)
+{
+	struct timeval t;
+	char *s = NULL;
+	struct tm *tm;
+	char tbuf[100];
+	int ret;
+
+	ret = vasprintf(&s, format, ap);
+	if (ret == -1) {
+		fprintf(stderr, "vasprintf failed in _do_debug_v, cannot print debug message.\n");
+		fflush(stderr);
+		return;
+	}
+
+	t = timeval_current();
+	tm = localtime(&t.tv_sec);
+
+	strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
+
+	fprintf(stderr, "%s.%06u [%s%5u]: %s", tbuf, (unsigned)t.tv_usec,
+		debug_extra, (unsigned)getpid(), s);
+	fflush(stderr);
+	free(s);
+}
+
+/* default logging function */
+void (*do_debug_v)(const char *, va_list ap) = _do_debug_v;
+const char *debug_extra = "";
+
+void do_debug(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	do_debug_v(format, ap);
+	va_end(ap);
+}
+
+
+static void _do_debug_add_v(const char *format, va_list ap)
+{
+	char *s = NULL;
+	int ret;
+
+	ret = vasprintf(&s, format, ap);
+	if (ret == -1) {
+		fprintf(stderr, "vasprintf failed in _do_debug_add_v, cannot print debug message.\n");
+		fflush(stderr);
+		return;
+	}
+
+	fprintf(stderr, "%s", s);
+	fflush(stderr);
+	free(s);
+}
+
+/* default logging function */
+void (*do_debug_add_v)(const char *, va_list ap) = _do_debug_add_v;
+
+void do_debug_add(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	do_debug_add_v(format, ap);
+	va_end(ap);
+}
+
+static void print_asc(int level, const uint8_t *buf, size_t len)
+{
+	int i;
+	for (i=0;i<len;i++) {
+		DEBUGADD(level,("%c", isprint(buf[i])?buf[i]:'.'));
+	}
+}
+
+void dump_data(int level, const uint8_t *buf, size_t len)
+{
+	int i=0;
+
+	if (len<=0) return;
+
+	if (!DEBUGLVL(level)) return;
+
+	DEBUG(level, (__location__ " dump data of size %i:\n", (int)len));
+	DEBUGADD(level,("[%03X] ",i));
+	for (i=0;i<len;) {
+		DEBUGADD(level,("%02X ",(int)buf[i]));
+		i++;
+		if (i%8 == 0) DEBUGADD(level,(" "));
+		if (i%16 == 0) {
+			print_asc(level,&buf[i-16],8); DEBUGADD(level,(" "));
+			print_asc(level,&buf[i-8],8); DEBUGADD(level,("\n"));
+			if (i<len) DEBUGADD(level,("[%03X] ",i));
+		}
+	}
+	if (i%16) {
+		int n;
+		n = 16 - (i%16);
+		DEBUGADD(level,(" "));
+		if (n>8) DEBUGADD(level,(" "));
+		while (n--) DEBUGADD(level,("   "));
+		n = MIN(8,i%16);
+		print_asc(level,&buf[i-(i%16)],n); DEBUGADD(level,( " " ));
+		n = (i%16) - n;
+		if (n>0) print_asc(level,&buf[i-n],n);
+		DEBUGADD(level,("\n"));
+	}
+	DEBUG(level, (__location__ " dump data of size %i finished\n", (int)len));
+}
+

Added: branches/ctdb/squeeze-backports/lib/util/debug.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/debug.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/debug.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,27 @@
+/*
+   Unix SMB/CIFS implementation.
+   ctdb debug functions
+   Copyright (C) Volker Lendecke 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+void (*do_debug_v)(const char *, va_list ap);
+const char *debug_extra;
+void (*do_debug_add_v)(const char *, va_list ap);
+void log_ringbuffer(const char *format, ...);
+void do_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void do_debug_add(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void dump_data(int level, const uint8_t *buf1, size_t len);
+

Added: branches/ctdb/squeeze-backports/lib/util/dlinklist.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/dlinklist.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/dlinklist.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,181 @@
+/* 
+   Unix SMB/CIFS implementation.
+   some simple double linked list macros
+
+   Copyright (C) Andrew Tridgell 1998-2010
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* To use these macros you must have a structure containing a next and
+   prev pointer */
+
+#ifndef _DLINKLIST_H
+#define _DLINKLIST_H
+
+/*
+  February 2010 - changed list format to have a prev pointer from the
+  list head. This makes DLIST_ADD_END() O(1) even though we only have
+  one list pointer.
+
+  The scheme is as follows:
+
+     1) with no entries in the list:
+          list_head == NULL
+
+     2) with 1 entry in the list:
+          list_head->next == NULL
+          list_head->prev == list_head
+
+     3) with 2 entries in the list:
+          list_head->next == element2
+          list_head->prev == element2
+	  element2->prev == list_head
+	  element2->next == NULL
+
+     4) with N entries in the list:
+          list_head->next == element2
+          list_head->prev == elementN
+	  elementN->prev == element{N-1}
+	  elementN->next == NULL
+
+  This allows us to find the tail of the list by using
+  list_head->prev, which means we can add to the end of the list in
+  O(1) time
+
+
+  Note that the 'type' arguments below are no longer needed, but
+  are kept for now to prevent an incompatible argument change
+ */
+
+
+/*
+   add an element at the front of a list
+*/
+#define DLIST_ADD(list, p) \
+do { \
+        if (!(list)) { \
+		(p)->prev = (list) = (p);  \
+		(p)->next = NULL; \
+	} else { \
+		(p)->prev = (list)->prev; \
+		(list)->prev = (p); \
+		(p)->next = (list); \
+		(list) = (p); \
+	} \
+} while (0)
+
+/*
+   remove an element from a list
+   Note that the element doesn't have to be in the list. If it
+   isn't then this is a no-op
+*/
+#define DLIST_REMOVE(list, p) \
+do { \
+	if ((p) == (list)) { \
+		if ((p)->next) (p)->next->prev = (p)->prev; \
+		(list) = (p)->next; \
+	} else if ((list) && (p) == (list)->prev) {	\
+		(p)->prev->next = NULL; \
+		(list)->prev = (p)->prev; \
+	} else { \
+		if ((p)->prev) (p)->prev->next = (p)->next; \
+		if ((p)->next) (p)->next->prev = (p)->prev; \
+	} \
+	if ((p) != (list)) (p)->next = (p)->prev = NULL;	\
+} while (0)
+
+/*
+   find the head of the list given any element in it.
+   Note that this costs O(N), so you should avoid this macro
+   if at all possible!
+*/
+#define DLIST_HEAD(p, result_head) \
+do { \
+       (result_head) = (p); \
+       while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
+} while(0)
+
+/* return the last element in the list */
+#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
+
+/* return the previous element in the list. */
+#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
+
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+   this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
+do { \
+        if (!(list) || !(el)) { \
+		DLIST_ADD(list, p); \
+	} else { \
+		(p)->prev = (el);   \
+		(p)->next = (el)->next;		\
+		(el)->next = (p);		\
+		if ((p)->next) (p)->next->prev = (p);	\
+		if ((list)->prev == (el)) (list)->prev = (p); \
+	}\
+} while (0)
+
+
+/*
+   add to the end of a list.
+   Note that 'type' is ignored
+*/
+#define DLIST_ADD_END(list, p, type)			\
+do { \
+	if (!(list)) { \
+		DLIST_ADD(list, p); \
+	} else { \
+		DLIST_ADD_AFTER(list, p, (list)->prev); \
+	} \
+} while (0)
+
+/* promote an element to the from of a list */
+#define DLIST_PROMOTE(list, p) \
+do { \
+          DLIST_REMOVE(list, p); \
+          DLIST_ADD(list, p); \
+} while (0)
+
+/*
+   demote an element to the end of a list.
+   Note that 'type' is ignored
+*/
+#define DLIST_DEMOTE(list, p, type)			\
+do { \
+	DLIST_REMOVE(list, p); \
+	DLIST_ADD_END(list, p, NULL);		\
+} while (0)
+
+/*
+   concatenate two lists - putting all elements of the 2nd list at the
+   end of the first list.
+   Note that 'type' is ignored
+*/
+#define DLIST_CONCATENATE(list1, list2, type)	\
+do { \
+	if (!(list1)) { \
+		(list1) = (list2); \
+	} else { \
+		(list1)->prev->next = (list2); \
+		if (list2) { \
+			void *_tmplist = (void *)(list1)->prev; \
+			(list1)->prev = (list2)->prev; \
+			(list2)->prev = _tmplist; \
+		} \
+	} \
+} while (0)
+
+#endif /* _DLINKLIST_H */

Added: branches/ctdb/squeeze-backports/lib/util/fault.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/fault.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/fault.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,239 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Critical Fault handling
+   Copyright (C) Andrew Tridgell 1992-1998
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+
+/**
+ * @file
+ * @brief Fault handling
+ */
+
+/* the registered fault handler */
+static struct {
+	const char *name;
+	void (*fault_handler)(int sig);
+} fault_handlers;
+
+static const char *progname;
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#elif HAVE_LIBEXC_H
+#include <libexc.h>
+#endif
+
+/**
+ * Write backtrace to debug log
+ */
+_PUBLIC_ void call_backtrace(void)
+{
+#ifdef HAVE_BACKTRACE
+#ifndef BACKTRACE_STACK_SIZE
+#define BACKTRACE_STACK_SIZE 64
+#endif
+	void *backtrace_stack[BACKTRACE_STACK_SIZE];
+	size_t backtrace_size;
+	char **backtrace_strings;
+
+	/* get the backtrace (stack frames) */
+	backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
+	backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
+
+	DEBUG(0, ("BACKTRACE: %lu stack frames:\n", 
+		  (unsigned long)backtrace_size));
+	
+	if (backtrace_strings) {
+		int i;
+
+		for (i = 0; i < backtrace_size; i++)
+			DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
+
+		/* Leak the backtrace_strings, rather than risk what free() might do */
+	}
+
+#elif HAVE_LIBEXC
+
+#define NAMESIZE 32 /* Arbitrary */
+#ifndef BACKTRACE_STACK_SIZE
+#define BACKTRACE_STACK_SIZE 64
+#endif
+
+	/* The IRIX libexc library provides an API for unwinding the stack. See
+	 * libexc(3) for details. Apparantly trace_back_stack leaks memory, but
+	 * since we are about to abort anyway, it hardly matters.
+	 *
+	 * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
+	 * will fail with a nasty message upon failing to open the /proc entry.
+	 */
+	{
+		uint64_t	addrs[BACKTRACE_STACK_SIZE];
+		char *      	names[BACKTRACE_STACK_SIZE];
+		char		namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
+
+		int		i;
+		int		levels;
+
+		ZERO_ARRAY(addrs);
+		ZERO_ARRAY(names);
+		ZERO_ARRAY(namebuf);
+
+		for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
+			names[i] = namebuf + (i * NAMESIZE);
+		}
+
+		levels = trace_back_stack(0, addrs, names,
+				BACKTRACE_STACK_SIZE, NAMESIZE);
+
+		DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
+		for (i = 0; i < levels; i++) {
+			DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
+		}
+     }
+#undef NAMESIZE
+#else
+	DEBUG(0, ("call_backstrace: not implemented\n"));
+#error bla
+#endif
+}
+
+_PUBLIC_ const char *panic_action = NULL;
+_PUBLIC_ void (*pre_panic_action_hook)(void) = NULL;
+_PUBLIC_ void (*post_panic_action_hook)(void) = NULL;
+
+/**
+ Something really nasty happened - panic !
+**/
+_PUBLIC_ void smb_panic(const char *why)
+{
+	int result;
+
+	if (panic_action && *panic_action) {
+		char pidstr[20];
+		char cmdstring[200];
+		strlcpy(cmdstring, panic_action, sizeof(cmdstring));
+		snprintf(pidstr, sizeof(pidstr), "%u", getpid());
+		all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring));
+		if (progname) {
+			all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring));
+		}
+		DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring));
+
+		if (pre_panic_action_hook) {
+			pre_panic_action_hook();
+		}
+
+		result = system(cmdstring);
+
+		if (post_panic_action_hook) {
+			post_panic_action_hook();
+		}
+
+		if (result == -1)
+			DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
+				  strerror(errno)));
+		else
+			DEBUG(0, ("smb_panic(): action returned status %d\n",
+				  WEXITSTATUS(result)));
+	}
+	DEBUG(0,("PANIC: %s\n", why));
+
+	call_backtrace();
+
+#ifdef SIGABRT
+	CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
+#endif
+	abort();
+}
+
+/**
+report a fault
+**/
+_NORETURN_ static void fault_report(int sig)
+{
+	static int counter;
+	
+	if (counter) _exit(1);
+
+	DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
+	DEBUG(0,("INTERNAL ERROR: Signal %d in %s pid %d",sig, progname, (int)getpid()));
+	DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
+	DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
+
+	smb_panic("internal error");
+
+	exit(1);
+}
+
+/**
+catch serious errors
+**/
+_NORETURN_ static void sig_fault(int sig)
+{
+	if (fault_handlers.fault_handler) {
+		/* we have a fault handler, call it. It may not return. */
+		fault_handlers.fault_handler(sig);
+	}
+	/* If it returns or doesn't exist, use regular reporter */
+	fault_report(sig);
+}
+
+/**
+setup our fault handlers
+**/
+_PUBLIC_ void fault_setup(const char *pname)
+{
+	if (progname == NULL) {
+		progname = pname;
+	}
+#ifdef SIGSEGV
+	CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGBUS
+	CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGABRT
+	CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGFPE
+	CatchSignal(SIGFPE,SIGNAL_CAST sig_fault);
+#endif
+}
+
+/**
+  register a fault handler. 
+  Should only be called once in the execution of smbd.
+*/
+_PUBLIC_ bool register_fault_handler(const char *name, 
+				     void (*fault_handler)(int sig))
+{
+	if (fault_handlers.name != NULL) {
+		/* it's already registered! */
+		DEBUG(2,("fault handler '%s' already registered - failed '%s'\n", 
+			 fault_handlers.name, name));
+		return false;
+	}
+
+	fault_handlers.name = name;
+	fault_handlers.fault_handler = fault_handler;
+
+	DEBUG(2,("fault handler '%s' registered\n", name));
+	return true;
+}

Added: branches/ctdb/squeeze-backports/lib/util/fault.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/fault.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/fault.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+AC_CHECK_HEADERS(execinfo.h)
+AC_SEARCH_LIBS_EXT(backtrace, [execinfo], EXECINFO_LIBS)
+AC_CHECK_FUNC_EXT(backtrace, $EXECINFO_LIBS)
+
+
+if test x"$ac_cv_header_execinfo_h" = x"yes" -a x"$ac_cv_func_ext_backtrace" = x"yes";then
+	SMB_ENABLE(EXECINFO, YES)
+	EXECINFO_CFLAGS="$CFLAGS"
+	EXECINFO_CPPFLAGS="$CPPFLAGS"
+	EXECINFO_LDFLAGS="$LDFLAGS"
+else
+	SMB_ENABLE(EXECINFO,NO)
+fi
+
+SMB_EXT_LIB(EXECINFO, [${EXECINFO_LIBS}], [${EXECINFO_CFLAGS}], [${EXECINFO_CPPFLAGS}], [${EXECINFO_LDFLAGS}])

Added: branches/ctdb/squeeze-backports/lib/util/idtree.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/idtree.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/idtree.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,387 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   very efficient functions to manage mapping a id (such as a fnum) to
+   a pointer. This is used for fnum and search id allocation.
+
+   Copyright (C) Andrew Tridgell 2004
+
+   This code is derived from lib/idr.c in the 2.6 Linux kernel, which was 
+   written by Jim Houston jim.houston at ccur.com, and is
+   Copyright (C) 2002 by Concurrent Computer Corporation
+    
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  see the section marked "public interface" below for documentation
+*/
+
+/**
+ * @file
+ */
+
+#include "includes.h"
+
+#define IDR_BITS 5
+#define IDR_FULL 0xfffffffful
+#if 0 /* unused */
+#define TOP_LEVEL_FULL (IDR_FULL >> 30)
+#endif
+#define IDR_SIZE (1 << IDR_BITS)
+#define IDR_MASK ((1 << IDR_BITS)-1)
+#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
+#define MAX_ID_MASK (MAX_ID_BIT - 1)
+#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
+#define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
+
+#define set_bit(bit, v) (v) |= (1<<(bit))
+#define clear_bit(bit, v) (v) &= ~(1<<(bit))
+#define test_bit(bit, v) ((v) & (1<<(bit)))
+				   
+struct idr_layer {
+	uint32_t		 bitmap;
+	struct idr_layer	*ary[IDR_SIZE];
+	int			 count;
+};
+
+struct idr_context {
+	struct idr_layer *top;
+	struct idr_layer *id_free;
+	int		  layers;
+	int		  id_free_cnt;
+};
+
+static struct idr_layer *alloc_layer(struct idr_context *idp)
+{
+	struct idr_layer *p;
+
+	if (!(p = idp->id_free))
+		return NULL;
+	idp->id_free = p->ary[0];
+	idp->id_free_cnt--;
+	p->ary[0] = NULL;
+	return p;
+}
+
+static int find_next_bit(uint32_t bm, int maxid, int n)
+{
+	while (n<maxid && !test_bit(n, bm)) n++;
+	return n;
+}
+
+static void free_layer(struct idr_context *idp, struct idr_layer *p)
+{
+	p->ary[0] = idp->id_free;
+	idp->id_free = p;
+	idp->id_free_cnt++;
+}
+
+static int idr_pre_get(struct idr_context *idp)
+{
+	while (idp->id_free_cnt < IDR_FREE_MAX) {
+		struct idr_layer *new = talloc_zero(idp, struct idr_layer);
+		if(new == NULL)
+			return (0);
+		free_layer(idp, new);
+	}
+	return 1;
+}
+
+static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
+{
+	int n, m, sh;
+	struct idr_layer *p, *new;
+	struct idr_layer *pa[MAX_LEVEL+1];
+	unsigned int l, id, oid;
+	uint32_t bm;
+
+	memset(pa, 0, sizeof(pa));
+
+	id = *starting_id;
+restart:
+	p = idp->top;
+	l = idp->layers;
+	pa[l--] = NULL;
+	while (1) {
+		/*
+		 * We run around this while until we reach the leaf node...
+		 */
+		n = (id >> (IDR_BITS*l)) & IDR_MASK;
+		bm = ~p->bitmap;
+		m = find_next_bit(bm, IDR_SIZE, n);
+		if (m == IDR_SIZE) {
+			/* no space available go back to previous layer. */
+			l++;
+			oid = id;
+			id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
+
+			/* if already at the top layer, we need to grow */
+			if (!(p = pa[l])) {
+				*starting_id = id;
+				return -2;
+			}
+
+			/* If we need to go up one layer, continue the
+			 * loop; otherwise, restart from the top.
+			 */
+			sh = IDR_BITS * (l + 1);
+			if (oid >> sh == id >> sh)
+				continue;
+			else
+				goto restart;
+		}
+		if (m != n) {
+			sh = IDR_BITS*l;
+			id = ((id >> sh) ^ n ^ m) << sh;
+		}
+		if ((id >= MAX_ID_BIT) || (id < 0))
+			return -1;
+		if (l == 0)
+			break;
+		/*
+		 * Create the layer below if it is missing.
+		 */
+		if (!p->ary[m]) {
+			if (!(new = alloc_layer(idp)))
+				return -1;
+			p->ary[m] = new;
+			p->count++;
+		}
+		pa[l--] = p;
+		p = p->ary[m];
+	}
+	/*
+	 * We have reached the leaf node, plant the
+	 * users pointer and return the raw id.
+	 */
+	p->ary[m] = (struct idr_layer *)ptr;
+	set_bit(m, p->bitmap);
+	p->count++;
+	/*
+	 * If this layer is full mark the bit in the layer above
+	 * to show that this part of the radix tree is full.
+	 * This may complete the layer above and require walking
+	 * up the radix tree.
+	 */
+	n = id;
+	while (p->bitmap == IDR_FULL) {
+		if (!(p = pa[++l]))
+			break;
+		n = n >> IDR_BITS;
+		set_bit((n & IDR_MASK), p->bitmap);
+	}
+	return(id);
+}
+
+static int idr_get_new_above_int(struct idr_context *idp, void *ptr, int starting_id)
+{
+	struct idr_layer *p, *new;
+	int layers, v, id;
+
+	idr_pre_get(idp);
+	
+	id = starting_id;
+build_up:
+	p = idp->top;
+	layers = idp->layers;
+	if (!p) {
+		if (!(p = alloc_layer(idp)))
+			return -1;
+		layers = 1;
+	}
+	/*
+	 * Add a new layer to the top of the tree if the requested
+	 * id is larger than the currently allocated space.
+	 */
+	while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
+		layers++;
+		if (!p->count)
+			continue;
+		if (!(new = alloc_layer(idp))) {
+			/*
+			 * The allocation failed.  If we built part of
+			 * the structure tear it down.
+			 */
+			for (new = p; p && p != idp->top; new = p) {
+				p = p->ary[0];
+				new->ary[0] = NULL;
+				new->bitmap = new->count = 0;
+				free_layer(idp, new);
+			}
+			return -1;
+		}
+		new->ary[0] = p;
+		new->count = 1;
+		if (p->bitmap == IDR_FULL)
+			set_bit(0, new->bitmap);
+		p = new;
+	}
+	idp->top = p;
+	idp->layers = layers;
+	v = sub_alloc(idp, ptr, &id);
+	if (v == -2)
+		goto build_up;
+	return(v);
+}
+
+static int sub_remove(struct idr_context *idp, int shift, int id)
+{
+	struct idr_layer *p = idp->top;
+	struct idr_layer **pa[1+MAX_LEVEL];
+	struct idr_layer ***paa = &pa[0];
+	int n;
+
+	*paa = NULL;
+	*++paa = &idp->top;
+
+	while ((shift > 0) && p) {
+		n = (id >> shift) & IDR_MASK;
+		clear_bit(n, p->bitmap);
+		*++paa = &p->ary[n];
+		p = p->ary[n];
+		shift -= IDR_BITS;
+	}
+	n = id & IDR_MASK;
+	if (p != NULL && test_bit(n, p->bitmap)) {
+		clear_bit(n, p->bitmap);
+		p->ary[n] = NULL;
+		while(*paa && ! --((**paa)->count)){
+			free_layer(idp, **paa);
+			**paa-- = NULL;
+		}
+		if ( ! *paa )
+			idp->layers = 0;
+		return 0;
+	}
+	return -1;
+}
+
+static void *_idr_find(struct idr_context *idp, int id)
+{
+	int n;
+	struct idr_layer *p;
+
+	n = idp->layers * IDR_BITS;
+	p = idp->top;
+	/*
+	 * This tests to see if bits outside the current tree are
+	 * present.  If so, tain't one of ours!
+	 */
+	if (n + IDR_BITS < 31 &&
+	    ((id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))) {
+	     return NULL;
+	}
+
+	/* Mask off upper bits we don't use for the search. */
+	id &= MAX_ID_MASK;
+
+	while (n >= IDR_BITS && p) {
+		n -= IDR_BITS;
+		p = p->ary[(id >> n) & IDR_MASK];
+	}
+	return((void *)p);
+}
+
+static int _idr_remove(struct idr_context *idp, int id)
+{
+	struct idr_layer *p;
+
+	/* Mask off upper bits we don't use for the search. */
+	id &= MAX_ID_MASK;
+
+	if (sub_remove(idp, (idp->layers - 1) * IDR_BITS, id) == -1) {
+		return -1;
+	}
+
+	if ( idp->top && idp->top->count == 1 && 
+	     (idp->layers > 1) &&
+	     idp->top->ary[0]) {
+		/* We can drop a layer */
+		p = idp->top->ary[0];
+		idp->top->bitmap = idp->top->count = 0;
+		free_layer(idp, idp->top);
+		idp->top = p;
+		--idp->layers;
+	}
+	while (idp->id_free_cnt >= IDR_FREE_MAX) {
+		p = alloc_layer(idp);
+		talloc_free(p);
+	}
+	return 0;
+}
+
+/************************************************************************
+  this is the public interface
+**************************************************************************/
+
+/**
+  initialise a idr tree. The context return value must be passed to
+  all subsequent idr calls. To destroy the idr tree use talloc_free()
+  on this context
+ */
+_PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx)
+{
+	return talloc_zero(mem_ctx, struct idr_context);
+}
+
+/**
+  allocate the next available id, and assign 'ptr' into its slot.
+  you can retrieve later this pointer using idr_find()
+*/
+_PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit)
+{
+	int ret = idr_get_new_above_int(idp, ptr, 0);
+	if (ret > limit) {
+		idr_remove(idp, ret);
+		return -1;
+	}
+	return ret;
+}
+
+/**
+   allocate a new id, giving the first available value greater than or
+   equal to the given starting id
+*/
+_PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit)
+{
+	int ret = idr_get_new_above_int(idp, ptr, starting_id);
+	if (ret > limit) {
+		idr_remove(idp, ret);
+		return -1;
+	}
+	return ret;
+}
+
+/**
+  find a pointer value previously set with idr_get_new given an id
+*/
+_PUBLIC_ void *idr_find(struct idr_context *idp, int id)
+{
+	return _idr_find(idp, id);
+}
+
+/**
+  remove an id from the idr tree
+*/
+_PUBLIC_ int idr_remove(struct idr_context *idp, int id)
+{
+	int ret;
+	ret = _idr_remove((struct idr_context *)idp, id);
+	if (ret != 0) {
+		DEBUG(0,("WARNING: attempt to remove unset id %d in idtree\n", id));
+	}
+	return ret;
+}

Added: branches/ctdb/squeeze-backports/lib/util/signal.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/signal.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/signal.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,144 @@
+/* 
+   Unix SMB/CIFS implementation.
+   signal handling functions
+
+   Copyright (C) Andrew Tridgell 1998
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/wait.h"
+
+/**
+ * @file
+ * @brief Signal handling
+ */
+
+/****************************************************************************
+ Catch child exits and reap the child zombie status.
+****************************************************************************/
+
+static void sig_cld(int signum)
+{
+	while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
+		;
+
+	/*
+	 * Turns out it's *really* important not to
+	 * restore the signal handler here if we have real POSIX
+	 * signal handling. If we do, then we get the signal re-delivered
+	 * immediately - hey presto - instant loop ! JRA.
+	 */
+
+#if !defined(HAVE_SIGACTION)
+	CatchSignal(SIGCLD, sig_cld);
+#endif
+}
+
+/****************************************************************************
+catch child exits - leave status;
+****************************************************************************/
+
+static void sig_cld_leave_status(int signum)
+{
+	/*
+	 * Turns out it's *really* important not to
+	 * restore the signal handler here if we have real POSIX
+	 * signal handling. If we do, then we get the signal re-delivered
+	 * immediately - hey presto - instant loop ! JRA.
+	 */
+
+#if !defined(HAVE_SIGACTION)
+	CatchSignal(SIGCLD, sig_cld_leave_status);
+#endif
+}
+
+/**
+ Block sigs.
+**/
+
+void BlockSignals(bool block, int signum)
+{
+#ifdef HAVE_SIGPROCMASK
+	sigset_t set;
+	sigemptyset(&set);
+	sigaddset(&set,signum);
+	sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
+#elif defined(HAVE_SIGBLOCK)
+	if (block) {
+		sigblock(sigmask(signum));
+	} else {
+		sigsetmask(siggetmask() & ~sigmask(signum));
+	}
+#else
+	/* yikes! This platform can't block signals? */
+	static int done;
+	if (!done) {
+		DEBUG(0,("WARNING: No signal blocking available\n"));
+		done=1;
+	}
+#endif
+}
+
+/**
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+**/
+
+void (*CatchSignal(int signum,void (*handler)(int )))(int)
+{
+#ifdef HAVE_SIGACTION
+	struct sigaction act;
+	struct sigaction oldact;
+
+	ZERO_STRUCT(act);
+
+	act.sa_handler = handler;
+#ifdef SA_RESTART
+	/*
+	 * We *want* SIGALRM to interrupt a system call.
+	 */
+	if(signum != SIGALRM)
+		act.sa_flags = SA_RESTART;
+#endif
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask,signum);
+	sigaction(signum,&act,&oldact);
+	return oldact.sa_handler;
+#else /* !HAVE_SIGACTION */
+	/* FIXME: need to handle sigvec and systems with broken signal() */
+	return signal(signum, handler);
+#endif
+}
+
+/**
+ Ignore SIGCLD via whatever means is necessary for this OS.
+**/
+
+void CatchChild(void)
+{
+	CatchSignal(SIGCLD, sig_cld);
+}
+
+/**
+ Catch SIGCLD but leave the child around so it's status can be reaped.
+**/
+
+void CatchChildLeaveStatus(void)
+{
+	CatchSignal(SIGCLD, sig_cld_leave_status);
+}

Added: branches/ctdb/squeeze-backports/lib/util/signal.m4
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/signal.m4	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/signal.m4	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+AC_CHECK_FUNCS(sigprocmask sigblock sigaction)

Added: branches/ctdb/squeeze-backports/lib/util/strlist.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/strlist.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/strlist.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,52 @@
+/* 
+   Unix SMB/CIFS implementation.
+   
+   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Jelmer Vernooij 2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/locale.h"
+
+/**
+  return the number of elements in a string list
+*/
+_PUBLIC_ size_t str_list_length(const char **list)
+{
+	size_t ret;
+	for (ret=0;list && list[ret];ret++) /* noop */ ;
+	return ret;
+}
+
+
+/**
+  add an entry to a string list
+*/
+_PUBLIC_ const char **str_list_add(const char **list, const char *s)
+{
+	size_t len = str_list_length(list);
+	const char **ret;
+
+	ret = talloc_realloc(NULL, list, const char *, len+2);
+	if (ret == NULL) return NULL;
+
+	ret[len] = talloc_strdup(ret, s);
+	if (ret[len] == NULL) return NULL;
+
+	ret[len+1] = NULL;
+
+	return ret;
+}

Added: branches/ctdb/squeeze-backports/lib/util/substitute.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/substitute.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/substitute.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,167 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Samba utility functions
+   
+   Copyright (C) Andrew Tridgell 1992-2001
+   Copyright (C) Simo Sorce      2001-2002
+   Copyright (C) Martin Pool     2003
+   Copyright (C) James Peach	 2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/**
+ * @file
+ * @brief Substitute utilities.
+ **/
+
+/**
+ Substitute a string for a pattern in another string. Make sure there is 
+ enough room!
+
+ This routine looks for pattern in s and replaces it with 
+ insert. It may do multiple replacements.
+
+ Any of " ; ' $ or ` in the insert string are replaced with _
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+
+_PUBLIC_ void string_sub(char *s, const char *pattern, const char *insert, size_t len)
+{
+	char *p;
+	ssize_t ls, lp, li, i;
+
+	if (!insert || !pattern || !*pattern || !s)
+		return;
+
+	ls = (ssize_t)strlen(s);
+	lp = (ssize_t)strlen(pattern);
+	li = (ssize_t)strlen(insert);
+
+	if (len == 0)
+		len = ls + 1; /* len is number of *bytes* */
+
+	while (lp <= ls && (p = strstr(s, pattern))) {
+		if (ls + (li-lp) >= len) {
+			DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n", 
+				 (int)(ls + (li-lp) - len),
+				 pattern, (int)len));
+			break;
+		}
+		if (li != lp) {
+			memmove(p+li,p+lp,strlen(p+lp)+1);
+		}
+		for (i=0;i<li;i++) {
+			switch (insert[i]) {
+			case '`':
+			case '"':
+			case '\'':
+			case ';':
+			case '$':
+			case '%':
+			case '\r':
+			case '\n':
+				p[i] = '_';
+				break;
+			default:
+				p[i] = insert[i];
+			}
+		}
+		s = p + li;
+		ls += (li-lp);
+	}
+}
+
+/**
+ * Talloc'ed version of string_sub
+ */
+_PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s, 
+				const char *pattern, const char *insert)
+{
+	const char *p;
+	char *ret;
+	size_t len, alloc_len;
+
+	if (insert == NULL || pattern == NULL || !*pattern || s == NULL)
+		return NULL;
+
+	/* determine length needed */
+	len = strlen(s);
+	
+	for (p = strstr(s, pattern); p != NULL; 
+	     p = strstr(p+strlen(pattern), pattern)) {
+		len += strlen(insert) - strlen(pattern);
+	}
+
+	alloc_len = MAX(len, strlen(s))+1;
+	ret = talloc_array(mem_ctx, char, alloc_len);
+	if (ret == NULL)
+		return NULL;
+	strncpy(ret, s, alloc_len);
+	string_sub(ret, pattern, insert, alloc_len);
+
+	ret = talloc_realloc(mem_ctx, ret, char, len+1);
+	if (ret == NULL)
+		return NULL;
+
+	SMB_ASSERT(ret[len] == '\0');
+
+	talloc_set_name_const(ret, ret);
+
+	return ret;
+}
+
+/**
+ Similar to string_sub() but allows for any character to be substituted. 
+ Use with caution!
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+
+_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
+{
+	char *p;
+	ssize_t ls,lp,li;
+
+	if (!insert || !pattern || !s)
+		return;
+
+	ls = (ssize_t)strlen(s);
+	lp = (ssize_t)strlen(pattern);
+	li = (ssize_t)strlen(insert);
+
+	if (!*pattern)
+		return;
+	
+	if (len == 0)
+		len = ls + 1; /* len is number of *bytes* */
+	
+	while (lp <= ls && (p = strstr(s,pattern))) {
+		if (ls + (li-lp) >= len) {
+			DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n", 
+				 (int)(ls + (li-lp) - len),
+				 pattern, (int)len));
+			break;
+		}
+		if (li != lp) {
+			memmove(p+li,p+lp,strlen(p+lp)+1);
+		}
+		memcpy(p, insert, li);
+		s = p + li;
+		ls += (li-lp);
+	}
+}

Added: branches/ctdb/squeeze-backports/lib/util/util.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/util.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/util.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,52 @@
+/* 
+   Unix SMB/CIFS implementation.
+   
+   Copyright (C) Andrew Tridgell 2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+
+
+/**
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+  if SYSV use O_NDELAY
+  if BSD use FNDELAY
+**/
+
+_PUBLIC_ int set_blocking(int fd, BOOL set)
+{
+	int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+	if((val = fcntl(fd, F_GETFL, 0)) == -1)
+		return -1;
+	if(set) /* Turn blocking on - ie. clear nonblock flag */
+		val &= ~FLAG_TO_SET;
+	else
+		val |= FLAG_TO_SET;
+	return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}

Added: branches/ctdb/squeeze-backports/lib/util/util.h
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/util.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/util.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,651 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Utility functions for Samba
+   Copyright (C) Andrew Tridgell 1992-1999
+   Copyright (C) Jelmer Vernooij 2005
+    
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_UTIL_H_
+#define _SAMBA_UTIL_H_
+
+/**
+ * @file
+ * @brief Helpful macros
+ */
+
+struct smbsrv_tcon;
+
+#ifdef _SAMBA_BUILD_
+extern const char *logfile;
+#endif
+extern const char *panic_action;
+extern void (*pre_panic_action_hook)(void);
+extern void (*post_panic_action_hook)(void);
+
+/**
+ * assert macros 
+ */
+#ifdef DEVELOPER
+#define SMB_ASSERT(b) do { if (!(b)) { \
+        DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
+		 __FILE__, __LINE__, #b)); smb_panic("assert failed: " #b); }} while(0)
+#else
+/* redefine the assert macro for non-developer builds */
+#define SMB_ASSERT(b) do { if (!(b)) { \
+        DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
+	    __FILE__, __LINE__, #b)); }} while (0)
+#endif
+
+#if _SAMBA_BUILD_ == 4
+#ifdef VALGRIND
+#define strlen(x) valgrind_strlen(x)
+size_t valgrind_strlen(const char *s);
+#endif
+#endif
+
+#ifndef ABS
+#define ABS(a) ((a)>0?(a):(-(a)))
+#endif
+
+/**
+ * Write backtrace to debug log
+ */
+_PUBLIC_ void call_backtrace(void);
+
+/**
+ Something really nasty happened - panic !
+**/
+_PUBLIC_ _NORETURN_ void smb_panic(const char *why);
+
+/**
+setup our fault handlers
+**/
+_PUBLIC_ void fault_setup(const char *pname);
+
+/**
+  register a fault handler. 
+  Should only be called once in the execution of smbd.
+*/
+_PUBLIC_ bool register_fault_handler(const char *name, void (*fault_handler)(int sig));
+
+/* The following definitions come from lib/util/signal.c  */
+
+
+/**
+ Block sigs.
+**/
+void BlockSignals(bool block, int signum);
+
+/**
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+**/
+void (*CatchSignal(int signum,void (*handler)(int )))(int);
+
+/**
+ Ignore SIGCLD via whatever means is necessary for this OS.
+**/
+void CatchChild(void);
+
+/**
+ Catch SIGCLD but leave the child around so it's status can be reaped.
+**/
+void CatchChildLeaveStatus(void);
+
+
+/* The following definitions come from lib/util/util_str.c  */
+
+
+/**
+ Trim the specified elements off the front and back of a string.
+**/
+_PUBLIC_ bool trim_string(char *s, const char *front, const char *back);
+
+/**
+ Find the number of 'c' chars in a string
+**/
+_PUBLIC_ _PURE_ size_t count_chars(const char *s, char c);
+
+/**
+ Safe string copy into a known length string. maxlength does not
+ include the terminating zero.
+**/
+_PUBLIC_ char *safe_strcpy(char *dest,const char *src, size_t maxlength);
+
+/**
+ Safe string cat into a string. maxlength does not
+ include the terminating zero.
+**/
+_PUBLIC_ char *safe_strcat(char *dest, const char *src, size_t maxlength);
+
+/**
+ Routine to get hex characters and turn them into a 16 byte array.
+ the array can be variable length, and any non-hex-numeric
+ characters are skipped.  "0xnn" or "0Xnn" is specially catered
+ for.
+
+ valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
+
+
+**/
+_PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len);
+
+#ifdef _SAMBA_BUILD_
+/** 
+ * Parse a hex string and return a data blob. 
+ */
+_PUBLIC_ _PURE_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) ;
+#endif
+
+/**
+ * Routine to print a buffer as HEX digits, into an allocated string.
+ */
+_PUBLIC_ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer);
+
+/**
+ * talloc version of hex_encode()
+ */
+_PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len);
+
+/**
+ Substitute a string for a pattern in another string. Make sure there is 
+ enough room!
+
+ This routine looks for pattern in s and replaces it with 
+ insert. It may do multiple replacements.
+
+ Any of " ; ' $ or ` in the insert string are replaced with _
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+_PUBLIC_ void string_sub(char *s,const char *pattern, const char *insert, size_t len);
+
+
+_PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s, 
+				const char *pattern, const char *insert);
+
+/**
+ Similar to string_sub() but allows for any character to be substituted. 
+ Use with caution!
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len);
+
+/**
+ Unescape a URL encoded string, in place.
+**/
+_PUBLIC_ void rfc1738_unescape(char *buf);
+
+/**
+  format a string into length-prefixed dotted domain format, as used in NBT
+  and in some ADS structures
+**/
+_PUBLIC_ const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s);
+
+/**
+ * Add a string to an array of strings.
+ *
+ * num should be a pointer to an integer that holds the current 
+ * number of elements in strings. It will be updated by this function.
+ */
+_PUBLIC_ bool add_string_to_array(TALLOC_CTX *mem_ctx,
+			 const char *str, const char ***strings, int *num);
+
+/**
+  varient of strcmp() that handles NULL ptrs
+**/
+_PUBLIC_ int strcmp_safe(const char *s1, const char *s2);
+
+/**
+return the number of bytes occupied by a buffer in ASCII format
+the result includes the null termination
+limited by 'n' bytes
+**/
+_PUBLIC_ size_t ascii_len_n(const char *src, size_t n);
+
+/**
+ Set a boolean variable from the text value stored in the passed string.
+ Returns true in success, false if the passed string does not correctly 
+ represent a boolean.
+**/
+_PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean);
+
+/**
+ * Parse a string containing a boolean value.
+ *
+ * val will be set to the read value.
+ *
+ * @retval true if a boolean value was parsed, false otherwise.
+ */
+_PUBLIC_ bool conv_str_bool(const char * str, bool * val);
+
+#if _SAMBA_BUILD_ == 4
+/**
+ * Convert a size specification like 16K into an integral number of bytes. 
+ **/
+_PUBLIC_ bool conv_str_size(const char * str, uint64_t * val);
+#endif
+
+/**
+ * Parse a uint64_t value from a string
+ *
+ * val will be set to the value read.
+ *
+ * @retval true if parsing was successful, false otherwise
+ */
+_PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val);
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+**/
+_PUBLIC_ size_t utf16_len(const void *buf);
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+limited by 'n' bytes
+**/
+_PUBLIC_ size_t utf16_len_n(const void *src, size_t n);
+_PUBLIC_ size_t ucs2_align(const void *base_ptr, const void *p, int flags);
+
+/**
+Do a case-insensitive, whitespace-ignoring string compare.
+**/
+_PUBLIC_ int strwicmp(const char *psz1, const char *psz2);
+
+/**
+ String replace.
+**/
+_PUBLIC_ void string_replace(char *s, char oldc, char newc);
+
+/**
+ * Compare 2 strings.
+ *
+ * @note The comparison is case-insensitive.
+ **/
+_PUBLIC_ bool strequal(const char *s1, const char *s2);
+
+/* The following definitions come from lib/util/util_strlist.c  */
+#ifdef _SAMBA_BUILD_
+
+/* separators for lists */
+#ifndef LIST_SEP
+#define LIST_SEP " \t,\n\r"
+#endif
+
+/**
+  build a null terminated list of strings from a input string and a
+  separator list. The separator list must contain characters less than
+  or equal to 0x2f for this to work correctly on multi-byte strings
+*/
+_PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
+
+/**
+ * build a null terminated list of strings from an argv-like input string 
+ * Entries are seperated by spaces and can be enclosed by quotes. 
+ * Does NOT support escaping
+ */
+_PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
+
+/**
+ * join a list back to one string 
+ */
+_PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator);
+
+/** join a list back to one (shell-like) string; entries 
+ * seperated by spaces, using quotes where necessary */
+_PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep);
+
+/**
+  return the number of elements in a string list
+*/
+_PUBLIC_ size_t str_list_length(const char * const *list);
+
+/**
+  copy a string list
+*/
+_PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list);
+
+/**
+   Return true if all the elements of the list match exactly.
+ */
+_PUBLIC_ bool str_list_equal(const char **list1, const char **list2);
+
+/**
+  add an entry to a string list
+*/
+_PUBLIC_ const char **str_list_add(const char **list, const char *s);
+
+/**
+  remove an entry from a string list
+*/
+_PUBLIC_ void str_list_remove(const char **list, const char *s);
+
+/**
+  return true if a string is in a list
+*/
+_PUBLIC_ bool str_list_check(const char **list, const char *s);
+
+/**
+  return true if a string is in a list, case insensitively
+*/
+_PUBLIC_ bool str_list_check_ci(const char **list, const char *s);
+#endif
+
+/* The following definitions come from lib/util/util_file.c  */
+
+
+#ifdef _SAMBA_BUILD_
+/**
+read a line from a file with possible \ continuation chars. 
+Blanks at the start or end of a line are stripped.
+The string will be allocated if s2 is NULL
+**/
+_PUBLIC_ char *fgets_slash(char *s2,int maxlen,XFILE *f);
+#endif
+
+/**
+ * Read one line (data until next newline or eof) and allocate it 
+ */
+_PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint);
+
+#ifdef _SAMBA_BUILD_
+/**
+load a file into memory from a fd.
+**/
+_PUBLIC_ char *fd_load(int fd, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx);
+
+
+char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx);
+
+/**
+load a file into memory
+**/
+_PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx);
+#endif
+
+/**
+mmap (if possible) or read a file
+**/
+_PUBLIC_ void *map_file(const char *fname, size_t size);
+
+#ifdef _SAMBA_BUILD_
+/**
+load a file into memory and return an array of pointers to lines in the file
+must be freed with talloc_free(). 
+**/
+_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx);
+#endif
+
+/**
+load a fd into memory and return an array of pointers to lines in the file
+must be freed with talloc_free(). If convert is true calls unix_to_dos on
+the list.
+**/
+_PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx);
+
+/**
+take a list of lines and modify them to produce a list where \ continues
+a line
+**/
+_PUBLIC_ void file_lines_slashcont(char **lines);
+
+/**
+  save a lump of data into a file. Mostly used for debugging 
+*/
+_PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length);
+_PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
+_PUBLIC_ int fdprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+_PUBLIC_ bool large_file_support(const char *path);
+
+/* The following definitions come from lib/util/util.c  */
+
+
+/**
+ Find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call.
+**/
+_PUBLIC_ const char *tmpdir(void);
+
+/**
+ Check if a file exists - call vfs_file_exist for samba files.
+**/
+_PUBLIC_ bool file_exist(const char *fname);
+
+/**
+ Check a files mod time.
+**/
+_PUBLIC_ time_t file_modtime(const char *fname);
+
+/**
+ Check if a directory exists.
+**/
+_PUBLIC_ bool directory_exist(const char *dname);
+
+/**
+ * Try to create the specified directory if it didn't exist.
+ *
+ * @retval true if the directory already existed and has the right permissions 
+ * or was successfully created.
+ */
+_PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid, 
+			       mode_t dir_perms);
+
+/**
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+  if SYSV use O_NDELAY
+  if BSD use FNDELAY
+**/
+_PUBLIC_ int set_blocking(int fd, bool set);
+
+/**
+ Sleep for a specified number of milliseconds.
+**/
+_PUBLIC_ void msleep(unsigned int t);
+
+/**
+ Get my own name, return in malloc'ed storage.
+**/
+_PUBLIC_ char* get_myname(void);
+
+/**
+ Return true if a string could be a pure IP address.
+**/
+_PUBLIC_ bool is_ipaddress(const char *str);
+
+/**
+ Interpret an internet address or name into an IP address in 4 byte form.
+**/
+_PUBLIC_ uint32_t interpret_addr(const char *str);
+
+/**
+ A convenient addition to interpret_addr().
+**/
+_PUBLIC_ struct in_addr interpret_addr2(const char *str);
+
+/**
+ Check if an IP is the 0.0.0.0.
+**/
+_PUBLIC_ bool is_zero_ip_v4(struct in_addr ip);
+
+/**
+ Are two IPs on the same subnet?
+**/
+_PUBLIC_ bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
+
+_PUBLIC_ bool is_ipaddress_v4(const char *str);
+
+/**
+ Check if a process exists. Does this work on all unixes?
+**/
+_PUBLIC_ bool process_exists_by_pid(pid_t pid);
+
+/**
+ Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
+**/
+_PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type);
+
+/**
+ malloc that aborts with smb_panic on fail or zero size.
+**/
+_PUBLIC_ void *smb_xmalloc(size_t size);
+
+/**
+ Memdup with smb_panic on fail.
+**/
+_PUBLIC_ void *smb_xmemdup(const void *p, size_t size);
+
+/**
+ strdup that aborts on malloc fail.
+**/
+_PUBLIC_ char *smb_xstrdup(const char *s);
+
+char *smb_xstrndup(const char *s, size_t n);
+
+/**
+ Like strdup but for memory.
+**/
+_PUBLIC_ void *memdup(const void *p, size_t size);
+
+/**
+ * see if a range of memory is all zero. A NULL pointer is considered
+ * to be all zero 
+ */
+_PUBLIC_ bool all_zero(const uint8_t *ptr, size_t size);
+
+/**
+  realloc an array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count, bool free_on_fail);
+
+void *malloc_array(size_t el_size, unsigned int count);
+
+/* The following definitions come from lib/util/fsusage.c  */
+
+
+/**
+ * Retrieve amount of free disk space.
+ * this does all of the system specific guff to get the free disk space.
+ * It is derived from code in the GNU fileutils package, but has been
+ * considerably mangled for use here 
+ *
+ * results are returned in *dfree and *dsize, in 512 byte units
+*/
+_PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize);
+
+/* The following definitions come from lib/util/ms_fnmatch.c  */
+
+
+/**
+ * @file
+ * @brief MS-style Filename matching
+ */
+
+#if _SAMBA_BUILD_ == 4
+/* protocol types. It assumes that higher protocols include lower protocols
+   as subsets. FIXME: Move to one of the smb-specific headers */
+enum protocol_types {
+	PROTOCOL_NONE,
+	PROTOCOL_CORE,
+	PROTOCOL_COREPLUS,
+	PROTOCOL_LANMAN1,
+	PROTOCOL_LANMAN2,
+	PROTOCOL_NT1,
+	PROTOCOL_SMB2
+};
+
+int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol);
+
+/** a generic fnmatch function - uses for non-CIFS pattern matching */
+int gen_fnmatch(const char *pattern, const char *string);
+#endif
+
+/* The following definitions come from lib/util/mutex.c  */
+
+
+#ifdef _SAMBA_BUILD_
+/**
+  register a set of mutex/rwlock handlers. 
+  Should only be called once in the execution of smbd.
+*/
+_PUBLIC_ bool register_mutex_handlers(const char *name, struct mutex_ops *ops);
+#endif
+
+/* The following definitions come from lib/util/idtree.c  */
+
+
+/**
+  initialise a idr tree. The context return value must be passed to
+  all subsequent idr calls. To destroy the idr tree use talloc_free()
+  on this context
+ */
+_PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx);
+
+/**
+  allocate the next available id, and assign 'ptr' into its slot.
+  you can retrieve later this pointer using idr_find()
+*/
+_PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit);
+
+/**
+   allocate a new id, giving the first available value greater than or
+   equal to the given starting id
+*/
+_PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit);
+
+/**
+  allocate a new id randomly in the given range
+*/
+_PUBLIC_ int idr_get_new_random(struct idr_context *idp, void *ptr, int limit);
+
+/**
+  find a pointer value previously set with idr_get_new given an id
+*/
+_PUBLIC_ void *idr_find(struct idr_context *idp, int id);
+
+/**
+  remove an id from the idr tree
+*/
+_PUBLIC_ int idr_remove(struct idr_context *idp, int id);
+
+/* The following definitions come from lib/util/become_daemon.c  */
+
+#if _SAMBA_BUILD_ == 4
+/**
+ Become a daemon, discarding the controlling terminal.
+**/
+_PUBLIC_ void become_daemon(bool fork);
+#endif
+
+/**
+ * Load a ini-style file.
+ */
+bool pm_process( const char *fileName,
+                 bool (*sfunc)(const char *, void *),
+                 bool (*pfunc)(const char *, const char *, void *),
+				 void *userdata);
+
+bool unmap_file(void *start, size_t size);
+
+#define CONST_DISCARD(type, ptr)      ((type) ((void *) (ptr)))
+
+#endif /* _SAMBA_UTIL_H_ */

Added: branches/ctdb/squeeze-backports/lib/util/util_file.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/util_file.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/util_file.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,116 @@
+/*
+  functions taken from samba4 for quick prototyping of ctdb. These are
+  not intended to remain part of ctdb
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+
+
+static char *fd_load(int fd, size_t *size, TALLOC_CTX *mem_ctx)
+{
+	struct stat sbuf;
+	char *p;
+
+	if (fstat(fd, &sbuf) != 0) return NULL;
+
+	p = (char *)talloc_size(mem_ctx, sbuf.st_size+1);
+	if (!p) return NULL;
+
+	if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
+		talloc_free(p);
+		return NULL;
+	}
+	p[sbuf.st_size] = 0;
+
+	if (size) *size = sbuf.st_size;
+
+	return p;
+}
+
+
+static char *file_load(const char *fname, size_t *size, TALLOC_CTX *mem_ctx)
+{
+	int fd;
+	char *p;
+
+	if (!fname || !*fname) return NULL;
+	
+	fd = open(fname,O_RDONLY);
+	if (fd == -1) return NULL;
+
+	p = fd_load(fd, size, mem_ctx);
+
+	close(fd);
+
+	return p;
+}
+
+
+/**
+parse a buffer into lines
+'p' will be freed on error, and otherwise will be made a child of the returned array
+**/
+static char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
+{
+	int i;
+	char *s, **ret;
+
+	if (!p) return NULL;
+
+	for (s = p, i=0; s < p+size; s++) {
+		if (s[0] == '\n') i++;
+	}
+
+	ret = talloc_array(mem_ctx, char *, i+2);
+	if (!ret) {
+		talloc_free(p);
+		return NULL;
+	}	
+	
+	talloc_steal(ret, p);
+	
+	memset(ret, 0, sizeof(ret[0])*(i+2));
+	if (numlines) *numlines = i;
+
+	ret[0] = p;
+	for (s = p, i=0; s < p+size; s++) {
+		if (s[0] == '\n') {
+			s[0] = 0;
+			i++;
+			ret[i] = s+1;
+		}
+		if (s[0] == '\r') s[0] = 0;
+	}
+
+	return ret;
+}
+
+
+/**
+load a file into memory and return an array of pointers to lines in the file
+must be freed with talloc_free(). 
+**/
+_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, TALLOC_CTX *mem_ctx)
+{
+	char *p;
+	size_t size;
+
+	p = file_load(fname, &size, mem_ctx);
+	if (!p) return NULL;
+
+	return file_lines_parse(p, size, numlines, mem_ctx);
+}
+
+char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len)
+{
+	int i;
+	char *hex_buffer;
+
+	hex_buffer = talloc_array(mem_ctx, char, (len*2)+1);
+
+	for (i = 0; i < len; i++)
+		slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
+
+	return hex_buffer;
+}

Added: branches/ctdb/squeeze-backports/lib/util/util_time.c
===================================================================
--- branches/ctdb/squeeze-backports/lib/util/util_time.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/lib/util/util_time.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,108 @@
+/*
+  functions taken from samba4 for quick prototyping of ctdb. These are
+  not intended to remain part of ctdb
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "system/filesys.h"
+
+
+/**
+  return a zero timeval
+*/
+struct timeval timeval_zero(void)
+{
+	struct timeval tv;
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	return tv;
+}
+
+/**
+  return True if a timeval is zero
+*/
+bool timeval_is_zero(const struct timeval *tv)
+{
+	return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+/**
+  return a timeval for the current time
+*/
+struct timeval timeval_current(void)
+{
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return tv;
+}
+
+double timeval_elapsed(struct timeval *tv)
+{
+	struct timeval tv2 = timeval_current();
+	return (tv2.tv_sec - tv->tv_sec) + 
+	       (tv2.tv_usec - tv->tv_usec)*1.0e-6;
+}
+
+double timeval_delta(struct timeval *tv2, struct timeval *tv)
+{
+	return (tv2->tv_sec - tv->tv_sec) + 
+	       (tv2->tv_usec - tv->tv_usec)*1.0e-6;
+}
+
+/**
+  return a timeval struct with the given elements
+*/
+_PUBLIC_ struct timeval timeval_set(uint32_t secs, uint32_t usecs)
+{
+	struct timeval tv;
+	tv.tv_sec = secs;
+	tv.tv_usec = usecs;
+	return tv;
+}
+
+_PUBLIC_ int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
+{
+	if (tv1->tv_sec  > tv2->tv_sec)  return 1;
+	if (tv1->tv_sec  < tv2->tv_sec)  return -1;
+	if (tv1->tv_usec > tv2->tv_usec) return 1;
+	if (tv1->tv_usec < tv2->tv_usec) return -1;
+	return 0;
+}
+
+_PUBLIC_ struct timeval timeval_until(const struct timeval *tv1,
+				      const struct timeval *tv2)
+{
+	struct timeval t;
+	if (timeval_compare(tv1, tv2) >= 0) {
+		return timeval_zero();
+	}
+	t.tv_sec = tv2->tv_sec - tv1->tv_sec;
+	if (tv1->tv_usec > tv2->tv_usec) {
+		t.tv_sec--;
+		t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
+	} else {
+		t.tv_usec = tv2->tv_usec - tv1->tv_usec;
+	}
+	return t;
+}
+
+static struct timeval timeval_add(const struct timeval *tv,
+			   uint32_t secs, uint32_t usecs)
+{
+	struct timeval tv2 = *tv;
+	const unsigned int million = 1000000;
+	tv2.tv_sec += secs;
+	tv2.tv_usec += usecs;
+	tv2.tv_sec += tv2.tv_usec / million;
+	tv2.tv_usec = tv2.tv_usec % million;
+	return tv2;
+}
+
+
+_PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
+{
+	struct timeval tv = timeval_current();
+	return timeval_add(&tv, secs, usecs);
+}
+

Added: branches/ctdb/squeeze-backports/libctdb/TODO
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/TODO	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/TODO	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,3 @@
+- Use CTDB_CONTROL_GET_DB_PRIORITY to ensure db locking is done in order.
+- Attach tdb's logging to libctdb logging.
+- Threadsafe version.

Added: branches/ctdb/squeeze-backports/libctdb/control.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/control.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/control.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,202 @@
+/*
+   Misc control routines of libctdb
+
+   Copyright (C) Rusty Russell 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <string.h>
+#include <ctdb.h>
+#include <ctdb_protocol.h>
+#include "libctdb_private.h"
+
+/* Remove type-safety macros. */
+#undef ctdb_getrecmaster_send
+#undef ctdb_getrecmode_send
+#undef ctdb_getpnn_send
+#undef ctdb_getnodemap_send
+#undef ctdb_getpublicips_send
+
+bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb,
+			   struct ctdb_request *req, uint32_t *recmaster)
+{
+	struct ctdb_reply_control *reply;
+
+	reply = unpack_reply_control(req, CTDB_CONTROL_GET_RECMASTER);
+	if (!reply) {
+		return false;
+	}
+	if (reply->status == -1) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getrecmaster_recv: status -1");
+		return false;
+	}
+	*recmaster = reply->status;
+	return true;
+}
+
+struct ctdb_request *ctdb_getrecmaster_send(struct ctdb_connection *ctdb,
+					    uint32_t destnode,
+					    ctdb_callback_t callback,
+					    void *private_data)
+{
+	return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_RECMASTER,
+					destnode, NULL, 0,
+					callback, private_data);
+}
+
+bool ctdb_getrecmode_recv(struct ctdb_connection *ctdb,
+			  struct ctdb_request *req, uint32_t *recmode)
+{
+	struct ctdb_reply_control *reply;
+
+	reply = unpack_reply_control(req, CTDB_CONTROL_GET_RECMODE);
+	if (!reply) {
+		return false;
+	}
+	if (reply->status == -1) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getrecmode_recv: status -1");
+		return false;
+	}
+	*recmode = reply->status;
+	return true;
+}
+
+struct ctdb_request *ctdb_getrecmode_send(struct ctdb_connection *ctdb,
+					    uint32_t destnode,
+					    ctdb_callback_t callback,
+					    void *private_data)
+{
+	return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_RECMODE,
+					destnode, NULL, 0,
+					callback, private_data);
+}
+
+bool ctdb_getpnn_recv(struct ctdb_connection *ctdb,
+		     struct ctdb_request *req, uint32_t *pnn)
+{
+	struct ctdb_reply_control *reply;
+
+	reply = unpack_reply_control(req, CTDB_CONTROL_GET_PNN);
+	if (!reply) {
+		return false;
+	}
+	if (reply->status == -1) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
+		return false;
+	}
+	*pnn = reply->status;
+	return true;
+}
+
+struct ctdb_request *ctdb_getpnn_send(struct ctdb_connection *ctdb,
+				      uint32_t destnode,
+				      ctdb_callback_t callback,
+				      void *private_data)
+{
+	return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_PNN, destnode,
+					NULL, 0, callback, private_data);
+}
+
+bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb,
+		      struct ctdb_request *req, struct ctdb_node_map **nodemap)
+{
+	struct ctdb_reply_control *reply;
+
+	*nodemap = NULL;
+	reply = unpack_reply_control(req, CTDB_CONTROL_GET_NODEMAP);
+	if (!reply) {
+		return false;
+	}
+	if (reply->status == -1) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: status -1");
+		return false;
+	}
+	if (reply->datalen == 0) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: returned data is 0 bytes");
+		return false;
+	}
+
+	*nodemap = malloc(reply->datalen);
+	if (*nodemap == NULL) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: failed to malloc buffer");
+		return false;
+	}
+	memcpy(*nodemap, reply->data, reply->datalen);
+
+	return true;
+}
+struct ctdb_request *ctdb_getnodemap_send(struct ctdb_connection *ctdb,
+					  uint32_t destnode,
+					  ctdb_callback_t callback,
+					  void *private_data)
+{
+	return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_NODEMAP,
+					destnode,
+					NULL, 0, callback, private_data);
+}
+
+void ctdb_free_nodemap(struct ctdb_node_map *nodemap)
+{
+	if (nodemap == NULL) {
+		return;
+	}
+	free(nodemap);
+}
+
+bool ctdb_getpublicips_recv(struct ctdb_connection *ctdb,
+			    struct ctdb_request *req,
+			    struct ctdb_all_public_ips **ips)
+{
+	struct ctdb_reply_control *reply;
+
+	*ips = NULL;
+	reply = unpack_reply_control(req, CTDB_CONTROL_GET_PUBLIC_IPS);
+	if (!reply) {
+		return false;
+	}
+	if (reply->status == -1) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: status -1");
+		return false;
+	}
+	if (reply->datalen == 0) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: returned data is 0 bytes");
+		return false;
+	}
+
+	*ips = malloc(reply->datalen);
+	if (*ips == NULL) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: failed to malloc buffer");
+		return false;
+	}
+	memcpy(*ips, reply->data, reply->datalen);
+
+	return true;
+}
+struct ctdb_request *ctdb_getpublicips_send(struct ctdb_connection *ctdb,
+					    uint32_t destnode,
+					    ctdb_callback_t callback,
+					    void *private_data)
+{
+	return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_PUBLIC_IPS,
+					destnode,
+					NULL, 0, callback, private_data);
+}
+
+void ctdb_free_publicips(struct ctdb_all_public_ips *ips)
+{
+	if (ips == NULL) {
+		return;
+	}
+	free(ips);
+}

Added: branches/ctdb/squeeze-backports/libctdb/ctdb.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/ctdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/ctdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1216 @@
+/*
+   core of libctdb
+
+   Copyright (C) Rusty Russell 2010
+   Copyright (C) Ronnie Sahlberg 2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <ctdb.h>
+#include <poll.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include "libctdb_private.h"
+#include "io_elem.h"
+#include "local_tdb.h"
+#include "messages.h"
+#include <dlinklist.h>
+#include <ctdb_protocol.h>
+
+/* Remove type-safety macros. */
+#undef ctdb_attachdb_send
+#undef ctdb_readrecordlock_async
+#undef ctdb_readonlyrecordlock_async
+#undef ctdb_connect
+
+struct ctdb_lock {
+	struct ctdb_lock *next, *prev;
+
+	struct ctdb_db *ctdb_db;
+	TDB_DATA key;
+
+	/* Is this a request for read-only lock ? */
+	bool readonly;
+
+	/* This will always be set by the time user sees this. */
+	unsigned long held_magic;
+	struct ctdb_ltdb_header *hdr;
+
+	/* For convenience, we stash original callback here. */
+	ctdb_rrl_callback_t callback;
+};
+
+struct ctdb_db {
+	struct ctdb_connection *ctdb;
+	bool persistent;
+	uint32_t tdb_flags;
+	uint32_t id;
+	struct tdb_context *tdb;
+
+	ctdb_callback_t callback;
+	void *private_data;
+};
+
+static void remove_lock(struct ctdb_connection *ctdb, struct ctdb_lock *lock)
+{
+	DLIST_REMOVE(ctdb->locks, lock);
+}
+
+/* FIXME: for thread safety, need tid info too. */
+static bool holding_lock(struct ctdb_connection *ctdb)
+{
+	/* For the moment, you can't ever hold more than 1 lock. */
+	return (ctdb->locks != NULL);
+}
+
+static void add_lock(struct ctdb_connection *ctdb, struct ctdb_lock *lock)
+{
+	DLIST_ADD(ctdb->locks, lock);
+}
+
+static void cleanup_locks(struct ctdb_connection *ctdb, struct ctdb_db *db)
+{
+	struct ctdb_lock *i, *next;
+
+	for (i = ctdb->locks; i; i = next) {
+		/* Grab next pointer, as release_lock will free i */
+		next = i->next;
+		if (i->ctdb_db == db) {
+			ctdb_release_lock(db, i);
+		}
+	}
+}
+
+/* FIXME: Could be in shared util code with rest of ctdb */
+static void close_noerr(int fd)
+{
+	int olderr = errno;
+	close(fd);
+	errno = olderr;
+}
+
+/* FIXME: Could be in shared util code with rest of ctdb */
+static void free_noerr(void *p)
+{
+	int olderr = errno;
+	free(p);
+	errno = olderr;
+}
+
+/* FIXME: Could be in shared util code with rest of ctdb */
+static void set_nonblocking(int fd)
+{
+	unsigned v;
+	v = fcntl(fd, F_GETFL, 0);
+        fcntl(fd, F_SETFL, v | O_NONBLOCK);
+}
+
+/* FIXME: Could be in shared util code with rest of ctdb */
+static void set_close_on_exec(int fd)
+{
+	unsigned v;
+	v = fcntl(fd, F_GETFD, 0);
+        fcntl(fd, F_SETFD, v | FD_CLOEXEC);
+}
+
+static void set_pnn(struct ctdb_connection *ctdb,
+		    struct ctdb_request *req,
+		    void *unused)
+{
+	if (!ctdb_getpnn_recv(ctdb, req, &ctdb->pnn)) {
+		DEBUG(ctdb, LOG_CRIT,
+		      "ctdb_connect(async): failed to get pnn");
+		ctdb->broken = true;
+	}
+	ctdb_request_free(req);
+}
+
+struct ctdb_connection *ctdb_connect(const char *addr,
+				     ctdb_log_fn_t log_fn, void *log_priv)
+{
+	struct ctdb_connection *ctdb;
+	struct sockaddr_un sun;
+
+	ctdb = malloc(sizeof(*ctdb));
+	if (!ctdb) {
+		/* With no format string, we hope it doesn't use ap! */
+		va_list ap;
+		memset(&ap, 0, sizeof(ap));
+		errno = ENOMEM;
+		log_fn(log_priv, LOG_ERR, "ctdb_connect: no memory", ap);
+		goto fail;
+	}
+	ctdb->pnn = -1;
+	ctdb->outq = NULL;
+	ctdb->doneq = NULL;
+	ctdb->in = NULL;
+	ctdb->inqueue = NULL;
+	ctdb->message_handlers = NULL;
+	ctdb->next_id = 0;
+	ctdb->broken = false;
+	ctdb->log = log_fn;
+	ctdb->log_priv = log_priv;
+	ctdb->locks = NULL;
+
+	memset(&sun, 0, sizeof(sun));
+	sun.sun_family = AF_UNIX;
+	if (!addr)
+		addr = CTDB_PATH;
+	strncpy(sun.sun_path, addr, sizeof(sun.sun_path)-1);
+	ctdb->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (ctdb->fd < 0)
+		goto free_fail;
+
+	set_nonblocking(ctdb->fd);
+	set_close_on_exec(ctdb->fd);
+
+	if (connect(ctdb->fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
+		goto close_fail;
+
+	/* Immediately queue a request to get our pnn. */
+	if (!ctdb_getpnn_send(ctdb, CTDB_CURRENT_NODE, set_pnn, NULL))
+		goto close_fail;
+
+	return ctdb;
+
+close_fail:
+	close_noerr(ctdb->fd);
+free_fail:
+	free_noerr(ctdb);
+fail:
+	return NULL;
+}
+
+void ctdb_disconnect(struct ctdb_connection *ctdb)
+{
+	struct ctdb_request *i;
+
+	DEBUG(ctdb, LOG_DEBUG, "ctdb_disconnect");
+
+	while ((i = ctdb->outq) != NULL) {
+		DLIST_REMOVE(ctdb->outq, i);
+		ctdb_request_free(i);
+	}
+
+	while ((i = ctdb->doneq) != NULL) {
+		DLIST_REMOVE(ctdb->doneq, i);
+		ctdb_request_free(i);
+	}
+
+	if (ctdb->in)
+		free_io_elem(ctdb->in);
+
+	remove_message_handlers(ctdb);
+
+	close(ctdb->fd);
+	/* Just in case they try to reuse */
+	ctdb->fd = -1;
+	free(ctdb);
+}
+
+int ctdb_get_fd(struct ctdb_connection *ctdb)
+{
+	return ctdb->fd;
+}
+
+int ctdb_which_events(struct ctdb_connection *ctdb)
+{
+	int events = POLLIN;
+
+	if (ctdb->outq)
+		events |= POLLOUT;
+	return events;
+}
+
+struct ctdb_request *new_ctdb_request(struct ctdb_connection *ctdb, size_t len,
+				      ctdb_callback_t cb, void *cbdata)
+{
+	struct ctdb_request *req = malloc(sizeof(*req));
+	if (!req)
+		return NULL;
+	req->io = new_io_elem(len);
+	if (!req->io) {
+		free(req);
+		return NULL;
+	}
+	req->ctdb = ctdb;
+	req->hdr.hdr = io_elem_data(req->io, NULL);
+	req->reply = NULL;
+	req->callback = cb;
+	req->priv_data = cbdata;
+	req->extra = NULL;
+	req->extra_destructor = NULL;
+	return req;
+}
+
+void ctdb_request_free(struct ctdb_request *req)
+{
+	struct ctdb_connection *ctdb = req->ctdb;
+
+	if (req->next || req->prev) {
+		DEBUG(ctdb, LOG_ALERT,
+		      "ctdb_request_free: request not complete! ctdb_cancel? %p (id %u)",
+		      req, req->hdr.hdr ? req->hdr.hdr->reqid : 0);
+		ctdb_cancel(ctdb, req);
+		return;
+	}
+	if (req->extra_destructor) {
+		req->extra_destructor(ctdb, req);
+	}
+	if (req->reply) {
+		free_io_elem(req->reply);
+	}
+	free_io_elem(req->io);
+	free(req);
+}
+
+/* Sanity-checking wrapper for reply. */
+static struct ctdb_reply_call *unpack_reply_call(struct ctdb_request *req,
+						 uint32_t callid)
+{
+	size_t len;
+	struct ctdb_reply_call *inhdr = io_elem_data(req->reply, &len);
+
+	/* Library user error if this isn't a reply to a call. */
+	if (req->hdr.hdr->operation != CTDB_REQ_CALL) {
+		errno = EINVAL;
+		DEBUG(req->ctdb, LOG_ALERT,
+		      "This was not a ctdbd call request: operation %u",
+		      req->hdr.hdr->operation);
+		return NULL;
+	}
+
+	if (req->hdr.call->callid != callid) {
+		errno = EINVAL;
+		DEBUG(req->ctdb, LOG_ALERT,
+		      "This was not a ctdbd %u call request: %u",
+		      callid, req->hdr.call->callid);
+		return NULL;
+	}
+
+	/* ctdbd or our error if this isn't a reply call. */
+	if (len < sizeof(*inhdr) || inhdr->hdr.operation != CTDB_REPLY_CALL) {
+		errno = EIO;
+		DEBUG(req->ctdb, LOG_CRIT,
+		      "Invalid ctdbd call reply: len %zu, operation %u",
+		      len, inhdr->hdr.operation);
+		return NULL;
+	}
+
+	return inhdr;
+}
+
+/* Sanity-checking wrapper for reply. */
+struct ctdb_reply_control *unpack_reply_control(struct ctdb_request *req,
+						enum ctdb_controls control)
+{
+	size_t len;
+	struct ctdb_reply_control *inhdr = io_elem_data(req->reply, &len);
+
+	/* Library user error if this isn't a reply to a call. */
+	if (len < sizeof(*inhdr)) {
+		errno = EINVAL;
+		DEBUG(req->ctdb, LOG_ALERT,
+		      "Short ctdbd control reply: %zu bytes", len);
+		return NULL;
+	}
+	if (req->hdr.hdr->operation != CTDB_REQ_CONTROL) {
+		errno = EINVAL;
+		DEBUG(req->ctdb, LOG_ALERT,
+		      "This was not a ctdbd control request: operation %u",
+		      req->hdr.hdr->operation);
+		return NULL;
+	}
+
+	/* ... or if it was a different control from what we expected. */
+	if (req->hdr.control->opcode != control) {
+		errno = EINVAL;
+		DEBUG(req->ctdb, LOG_ALERT,
+		      "This was not an opcode %u ctdbd control request: %u",
+		      control, req->hdr.control->opcode);
+		return NULL;
+	}
+
+	/* ctdbd or our error if this isn't a reply call. */
+	if (inhdr->hdr.operation != CTDB_REPLY_CONTROL) {
+		errno = EIO;
+		DEBUG(req->ctdb, LOG_CRIT,
+		      "Invalid ctdbd control reply: operation %u",
+		      inhdr->hdr.operation);
+		return NULL;
+	}
+
+	return inhdr;
+}
+
+static void handle_incoming(struct ctdb_connection *ctdb, struct io_elem *in)
+{
+	struct ctdb_req_header *hdr;
+	size_t len;
+	struct ctdb_request *i;
+
+	hdr = io_elem_data(in, &len);
+	/* FIXME: use len to check packet! */
+
+	if (hdr->operation == CTDB_REQ_MESSAGE) {
+		deliver_message(ctdb, hdr);
+		return;
+	}
+
+	for (i = ctdb->doneq; i; i = i->next) {
+		if (i->hdr.hdr->reqid == hdr->reqid) {
+			DLIST_REMOVE(ctdb->doneq, i);
+			i->reply = in;
+			i->callback(ctdb, i, i->priv_data);
+			return;
+		}
+	}
+	DEBUG(ctdb, LOG_WARNING,
+	      "Unexpected ctdbd request reply: operation %u reqid %u",
+	      hdr->operation, hdr->reqid);
+	free_io_elem(in);
+}
+
+/* Remove "harmless" errors. */
+static ssize_t real_error(ssize_t ret)
+{
+	if (ret < 0 && (errno == EINTR || errno == EWOULDBLOCK))
+		return 0;
+	return ret;
+}
+
+bool ctdb_service(struct ctdb_connection *ctdb, int revents)
+{
+	if (ctdb->broken) {
+		return false;
+	}
+
+	if (holding_lock(ctdb)) {
+		DEBUG(ctdb, LOG_ALERT, "Do not block while holding lock!");
+	}
+
+	if (revents & POLLOUT) {
+		while (ctdb->outq) {
+			if (real_error(write_io_elem(ctdb->fd,
+						     ctdb->outq->io)) < 0) {
+				DEBUG(ctdb, LOG_ERR,
+				      "ctdb_service: error writing to ctdbd");
+				ctdb->broken = true;
+				return false;
+			}
+			if (io_elem_finished(ctdb->outq->io)) {
+				struct ctdb_request *done = ctdb->outq;
+				DLIST_REMOVE(ctdb->outq, done);
+				/* We add at the head: any dead ones
+				 * sit and end. */
+				DLIST_ADD(ctdb->doneq, done);
+			}
+		}
+	}
+
+	while (revents & POLLIN) {
+		int ret;
+		int num_ready = 0;
+
+		if (ioctl(ctdb->fd, FIONREAD, &num_ready) != 0) {
+			DEBUG(ctdb, LOG_ERR,
+			      "ctdb_service: ioctl(FIONREAD) %d", errno);
+			ctdb->broken = true;
+			return false;
+		}
+		if (num_ready == 0) {
+			/* the descriptor has been closed or we have all our data */
+			break;
+		}
+
+
+		if (!ctdb->in) {
+			ctdb->in = new_io_elem(sizeof(struct ctdb_req_header));
+			if (!ctdb->in) {
+				DEBUG(ctdb, LOG_ERR,
+				      "ctdb_service: allocating readbuf");
+				ctdb->broken = true;
+				return false;
+			}
+		}
+
+		ret = read_io_elem(ctdb->fd, ctdb->in);
+		if (real_error(ret) < 0 || ret == 0) {
+			/* They closed fd? */
+			if (ret == 0)
+				errno = EBADF;
+			DEBUG(ctdb, LOG_ERR,
+			      "ctdb_service: error reading from ctdbd");
+			ctdb->broken = true;
+			return false;
+		} else if (ret < 0) {
+			/* No progress, stop loop. */
+			break;
+		} else if (io_elem_finished(ctdb->in)) {
+			io_elem_queue(ctdb, ctdb->in);
+			ctdb->in = NULL;
+		}
+	}
+
+
+	while (ctdb->inqueue != NULL) {
+		struct io_elem *io = ctdb->inqueue;
+
+		io_elem_dequeue(ctdb, io);
+		handle_incoming(ctdb, io);
+	}
+
+	return true;
+}
+
+/* This is inefficient.  We could pull in idtree.c. */
+static bool reqid_used(const struct ctdb_connection *ctdb, uint32_t reqid)
+{
+	struct ctdb_request *i;
+
+	for (i = ctdb->outq; i; i = i->next) {
+		if (i->hdr.hdr->reqid == reqid) {
+			return true;
+		}
+	}
+	for (i = ctdb->doneq; i; i = i->next) {
+		if (i->hdr.hdr->reqid == reqid) {
+			return true;
+		}
+	}
+	return false;
+}
+
+uint32_t new_reqid(struct ctdb_connection *ctdb)
+{
+	while (reqid_used(ctdb, ctdb->next_id)) {
+		ctdb->next_id++;
+	}
+	return ctdb->next_id++;
+}
+
+struct ctdb_request *new_ctdb_control_request(struct ctdb_connection *ctdb,
+					      uint32_t opcode,
+					      uint32_t destnode,
+					      const void *extra_data,
+					      size_t extra,
+					      ctdb_callback_t callback,
+					      void *cbdata)
+{
+	struct ctdb_request *req;
+	struct ctdb_req_control *pkt;
+
+	req = new_ctdb_request(
+		ctdb, offsetof(struct ctdb_req_control, data) + extra,
+		callback, cbdata);
+	if (!req)
+		return NULL;
+
+	io_elem_init_req_header(req->io,
+				CTDB_REQ_CONTROL, destnode, new_reqid(ctdb));
+
+	pkt = req->hdr.control;
+	pkt->pad = 0;
+	pkt->opcode = opcode;
+	pkt->srvid = 0;
+	pkt->client_id = 0;
+	pkt->flags = 0;
+	pkt->datalen = extra;
+	memcpy(pkt->data, extra_data, extra);
+	DLIST_ADD(ctdb->outq, req);
+	return req;
+}
+
+void ctdb_cancel_callback(struct ctdb_connection *ctdb,
+			  struct ctdb_request *req,
+			  void *unused)
+{
+	ctdb_request_free(req);
+}
+
+void ctdb_cancel(struct ctdb_connection *ctdb, struct ctdb_request *req)
+{
+	if (!req->next && !req->prev) {
+		DEBUG(ctdb, LOG_ALERT,
+		      "ctdb_cancel: request completed! ctdb_request_free? %p (id %u)",
+		      req, req->hdr.hdr ? req->hdr.hdr->reqid : 0);
+		ctdb_request_free(req);
+		return;
+	}
+
+	DEBUG(ctdb, LOG_DEBUG, "ctdb_cancel: %p (id %u)",
+	      req, req->hdr.hdr ? req->hdr.hdr->reqid : 0);
+
+	/* FIXME: If it's not sent, we could just free it right now. */
+	req->callback = ctdb_cancel_callback;
+}
+
+void ctdb_detachdb(struct ctdb_connection *ctdb, struct ctdb_db *db)
+{
+	cleanup_locks(ctdb, db);
+	tdb_close(db->tdb);
+	free(db);
+}
+
+static void destroy_req_db(struct ctdb_connection *ctdb,
+			   struct ctdb_request *req);
+static void attachdb_done(struct ctdb_connection *ctdb,
+			  struct ctdb_request *req,
+			  void *_db);
+static void attachdb_getdbpath_done(struct ctdb_connection *ctdb,
+				    struct ctdb_request *req,
+				    void *_db);
+
+struct ctdb_request *
+ctdb_attachdb_send(struct ctdb_connection *ctdb,
+		   const char *name, bool persistent, uint32_t tdb_flags,
+		   ctdb_callback_t callback, void *private_data)
+{
+	struct ctdb_request *req;
+	struct ctdb_db *db;
+	uint32_t opcode;
+
+	/* FIXME: Search if db already open. */
+	db = malloc(sizeof(*db));
+	if (!db) {
+		return NULL;
+	}
+
+	if (persistent) {
+		opcode = CTDB_CONTROL_DB_ATTACH_PERSISTENT;
+	} else {
+		opcode = CTDB_CONTROL_DB_ATTACH;
+	}
+
+	req = new_ctdb_control_request(ctdb, opcode, CTDB_CURRENT_NODE, name,
+				       strlen(name) + 1, attachdb_done, db);
+	if (!req) {
+		DEBUG(ctdb, LOG_ERR,
+		      "ctdb_attachdb_send: failed allocating DB_ATTACH");
+		free(db);
+		return NULL;
+	}
+
+	db->ctdb = ctdb;
+	db->tdb_flags = tdb_flags;
+	db->persistent = persistent;
+	db->callback = callback;
+	db->private_data = private_data;
+
+	req->extra_destructor = destroy_req_db;
+	/* This is set non-NULL when we succeed, see ctdb_attachdb_recv */
+	req->extra = NULL;
+
+	/* Flags get overloaded into srvid. */
+	req->hdr.control->srvid = tdb_flags;
+	DEBUG(db->ctdb, LOG_DEBUG,
+	      "ctdb_attachdb_send: DB_ATTACH request %p", req);
+	return req;
+}
+
+static void destroy_req_db(struct ctdb_connection *ctdb,
+			   struct ctdb_request *req)
+{
+	/* Incomplete db is in priv_data. */
+	free(req->priv_data);
+	/* second request is chained off this one. */
+	if (req->extra) {
+		ctdb_request_free(req->extra);
+	}
+}
+
+static void attachdb_done(struct ctdb_connection *ctdb,
+			  struct ctdb_request *req,
+			  void *_db)
+{
+	struct ctdb_db *db = _db;
+	struct ctdb_request *req2;
+	struct ctdb_reply_control *reply;
+	enum ctdb_controls control = CTDB_CONTROL_DB_ATTACH;
+
+	if (db->persistent) {
+		control = CTDB_CONTROL_DB_ATTACH_PERSISTENT;
+	}
+
+	reply = unpack_reply_control(req, control);
+	if (!reply || reply->status != 0) {
+		if (reply) {
+			DEBUG(ctdb, LOG_ERR,
+			      "ctdb_attachdb_send(async): DB_ATTACH status %i",
+			      reply->status);
+		}
+		/* We failed.  Hand request to user and have them discover it
+		 * via ctdb_attachdb_recv. */
+		db->callback(ctdb, req, db->private_data);
+		return;
+	}
+	db->id = *(uint32_t *)reply->data;
+
+	/* Now we do another call, to get the dbpath. */
+	req2 = new_ctdb_control_request(db->ctdb, CTDB_CONTROL_GETDBPATH,
+					CTDB_CURRENT_NODE,
+					&db->id, sizeof(db->id),
+					attachdb_getdbpath_done, db);
+	if (!req2) {
+		DEBUG(db->ctdb, LOG_ERR,
+		      "ctdb_attachdb_send(async): failed to allocate");
+		db->callback(ctdb, req, db->private_data);
+		return;
+	}
+	req->extra = req2;
+	req2->extra = req;
+	DEBUG(db->ctdb, LOG_DEBUG,
+	      "ctdb_attachdb_send(async): created getdbpath request");
+}
+
+static void attachdb_getdbpath_done(struct ctdb_connection *ctdb,
+				    struct ctdb_request *req,
+				    void *_db)
+{
+	struct ctdb_db *db = _db;
+
+	/* Do callback on original request. */
+	db->callback(ctdb, req->extra, db->private_data);
+}
+
+struct ctdb_db *ctdb_attachdb_recv(struct ctdb_connection *ctdb,
+				   struct ctdb_request *req)
+{
+	struct ctdb_request *dbpath_req = req->extra;
+	struct ctdb_reply_control *reply;
+	struct ctdb_db *db = req->priv_data;
+	uint32_t tdb_flags = db->tdb_flags;
+	struct tdb_logging_context log;
+
+	/* Never sent the dbpath request?  We've failed. */
+	if (!dbpath_req) {
+		/* FIXME: Save errno? */
+		errno = EINVAL;
+		return NULL;
+	}
+
+	reply = unpack_reply_control(dbpath_req, CTDB_CONTROL_GETDBPATH);
+	if (!reply) {
+		return NULL;
+	}
+	if (reply->status != 0) {
+		DEBUG(db->ctdb, LOG_ERR,
+		      "ctdb_attachdb_recv: reply status %i", reply->status);
+		return NULL;
+	}
+
+	tdb_flags = db->persistent ? TDB_DEFAULT : TDB_NOSYNC;
+	tdb_flags |= TDB_DISALLOW_NESTING;
+
+	log.log_fn = ctdb_tdb_log_bridge;
+	log.log_private = ctdb;
+	db->tdb = tdb_open_ex((char *)reply->data, 0, tdb_flags, O_RDWR, 0,
+			      &log, NULL);
+	if (db->tdb == NULL) {
+		DEBUG(db->ctdb, LOG_ERR,
+		      "ctdb_attachdb_recv: failed to tdb_open %s",
+		      (char *)reply->data);
+		return NULL;
+	}
+
+	/* Finally, separate the db from the request (see destroy_req_db). */
+	req->priv_data = NULL;
+	DEBUG(db->ctdb, LOG_DEBUG,
+	      "ctdb_attachdb_recv: db %p, tdb %s", db, (char *)reply->data);
+	return db;
+}
+
+static unsigned long lock_magic(struct ctdb_lock *lock)
+{
+	/* A non-zero magic specific to this structure. */
+	return ((unsigned long)lock->key.dptr
+		^ (((unsigned long)lock->key.dptr) << 16)
+		^ 0xBADC0FFEEBADC0DEULL)
+		| 1;
+}
+
+/* This is only called on locks before they're held. */
+static void free_lock(struct ctdb_lock *lock)
+{
+	if (lock->held_magic) {
+		DEBUG(lock->ctdb_db->ctdb, LOG_ALERT,
+		      "free_lock invalid lock %p", lock);
+	}
+	free(lock->hdr);
+	free(lock);
+}
+
+
+void ctdb_release_lock(struct ctdb_db *ctdb_db, struct ctdb_lock *lock)
+{
+	if (lock->held_magic != lock_magic(lock)) {
+		DEBUG(lock->ctdb_db->ctdb, LOG_ALERT,
+		      "ctdb_release_lock invalid lock %p", lock);
+	} else if (lock->ctdb_db != ctdb_db) {
+		errno = EBADF;
+		DEBUG(ctdb_db->ctdb, LOG_ALERT,
+		      "ctdb_release_lock: wrong ctdb_db.");
+	} else {
+		tdb_chainunlock(lock->ctdb_db->tdb, lock->key);
+		DEBUG(lock->ctdb_db->ctdb, LOG_DEBUG,
+		      "ctdb_release_lock %p", lock);
+		remove_lock(lock->ctdb_db->ctdb, lock);
+	}
+	lock->held_magic = 0;
+	free_lock(lock);
+}
+
+
+/* We keep the lock if local node is the dmaster. */
+static bool try_readrecordlock(struct ctdb_lock *lock, TDB_DATA *data)
+{
+	struct ctdb_ltdb_header *hdr;
+
+	if (tdb_chainlock(lock->ctdb_db->tdb, lock->key) != 0) {
+		DEBUG(lock->ctdb_db->ctdb, LOG_WARNING,
+		      "ctdb_readrecordlock_async: failed to chainlock");
+		return NULL;
+	}
+
+	hdr = ctdb_local_fetch(lock->ctdb_db->tdb, lock->key, data);
+	if (hdr && lock->readonly && (hdr->flags & CTDB_REC_RO_HAVE_READONLY) ) {
+		DEBUG(lock->ctdb_db->ctdb, LOG_DEBUG,
+		      "ctdb_readrecordlock_async: got local lock for ro");
+		lock->held_magic = lock_magic(lock);
+		lock->hdr = hdr;
+		add_lock(lock->ctdb_db->ctdb, lock);
+		return true;
+	}
+	if (hdr && hdr->dmaster == lock->ctdb_db->ctdb->pnn) {
+		DEBUG(lock->ctdb_db->ctdb, LOG_DEBUG,
+		      "ctdb_readrecordlock_async: got local lock");
+		lock->held_magic = lock_magic(lock);
+		lock->hdr = hdr;
+		add_lock(lock->ctdb_db->ctdb, lock);
+		return true;
+	}
+
+	/* we dont have the record locally,
+	 * drop to writelock to force a migration
+	 */
+	if (!hdr && lock->readonly) {
+		lock->readonly = false;
+	}
+
+	tdb_chainunlock(lock->ctdb_db->tdb, lock->key);
+	free(hdr);
+	return NULL;
+}
+
+/* If they shutdown before we hand them the lock, we free it here. */
+static void destroy_lock(struct ctdb_connection *ctdb,
+			 struct ctdb_request *req)
+{
+	free_lock(req->extra);
+}
+
+static void readrecordlock_retry(struct ctdb_connection *ctdb,
+				 struct ctdb_request *req, void *private)
+{
+	struct ctdb_lock *lock = req->extra;
+	struct ctdb_reply_call *reply;
+	TDB_DATA data;
+
+	/* OK, we've received reply to fetch-with-header migration */
+	reply = unpack_reply_call(req, CTDB_FETCH_WITH_HEADER_FUNC);
+	if (!reply || reply->status != 0) {
+		if (reply) {
+			DEBUG(ctdb, LOG_ERR,
+			      "ctdb_readrecordlock_async(async):"
+			      " FETCH_WITH_HEADER_FUNC returned %i", reply->status);
+		}
+		lock->callback(lock->ctdb_db, NULL, tdb_null, private);
+		ctdb_request_free(req); /* Also frees lock. */
+		return;
+	}
+
+	/* Can we get lock now? */
+	if (try_readrecordlock(lock, &data)) {
+		/* Now it's their responsibility to free lock & request! */
+		req->extra_destructor = NULL;
+		lock->callback(lock->ctdb_db, lock, data, private);
+		ctdb_request_free(req);
+		return;
+	}
+
+	/* Retransmit the same request again (we lost race). */
+	io_elem_reset(req->io);
+	DLIST_ADD(ctdb->outq, req);
+}
+
+static bool
+ctdb_readrecordlock_internal(struct ctdb_db *ctdb_db, TDB_DATA key,
+			     bool readonly,
+			     ctdb_rrl_callback_t callback, void *cbdata)
+{
+	struct ctdb_request *req;
+	struct ctdb_lock *lock;
+	TDB_DATA data;
+
+	if (holding_lock(ctdb_db->ctdb)) {
+		DEBUG(ctdb_db->ctdb, LOG_ALERT,
+		      "ctdb_readrecordlock_async: already holding lock");
+		return false;
+	}
+
+	/* Setup lock */
+	lock = malloc(sizeof(*lock) + key.dsize);
+	if (!lock) {
+		DEBUG(ctdb_db->ctdb, LOG_ERR,
+		      "ctdb_readrecordlock_async: lock allocation failed");
+		return false;
+	}
+	lock->key.dptr = (void *)(lock + 1);
+	memcpy(lock->key.dptr, key.dptr, key.dsize);
+	lock->key.dsize = key.dsize;
+	lock->ctdb_db = ctdb_db;
+	lock->hdr = NULL;
+	lock->held_magic = 0;
+	lock->readonly = readonly;
+
+	/* Fast path. */
+	if (try_readrecordlock(lock, &data)) {
+		callback(ctdb_db, lock, data, cbdata);
+		return true;
+	}
+
+	/* Slow path: create request. */
+	req = new_ctdb_request(
+		ctdb_db->ctdb,
+		offsetof(struct ctdb_req_call, data) + key.dsize,
+		readrecordlock_retry, cbdata);
+	if (!req) {
+		DEBUG(ctdb_db->ctdb, LOG_ERR,
+		      "ctdb_readrecordlock_async: allocation failed");
+		free_lock(lock);
+		return NULL;
+	}
+	req->extra = lock;
+	req->extra_destructor = destroy_lock;
+	/* We store the original callback in the lock, and use our own. */
+	lock->callback = callback;
+
+	io_elem_init_req_header(req->io, CTDB_REQ_CALL, CTDB_CURRENT_NODE,
+				new_reqid(ctdb_db->ctdb));
+
+	if (lock->readonly) {
+		req->hdr.call->flags = CTDB_WANT_READONLY;
+	} else {
+		req->hdr.call->flags = CTDB_IMMEDIATE_MIGRATION;
+	}
+	req->hdr.call->db_id = ctdb_db->id;
+	req->hdr.call->callid = CTDB_FETCH_WITH_HEADER_FUNC;
+	req->hdr.call->hopcount = 0;
+	req->hdr.call->keylen = key.dsize;
+	req->hdr.call->calldatalen = 0;
+	memcpy(req->hdr.call->data, key.dptr, key.dsize);
+	DLIST_ADD(ctdb_db->ctdb->outq, req);
+	return true;
+}
+
+bool
+ctdb_readrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key,
+			  ctdb_rrl_callback_t callback, void *cbdata)
+{
+	return ctdb_readrecordlock_internal(ctdb_db, key,
+			false,
+			callback, cbdata);
+}
+
+bool
+ctdb_readonlyrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key,
+			  ctdb_rrl_callback_t callback, void *cbdata)
+{
+	return ctdb_readrecordlock_internal(ctdb_db, key,
+			true,
+			callback, cbdata);
+}
+
+bool ctdb_writerecord(struct ctdb_db *ctdb_db,
+		      struct ctdb_lock *lock, TDB_DATA data)
+{
+	if (lock->readonly) {
+		errno = EBADF;
+		DEBUG(ctdb_db->ctdb, LOG_ALERT,
+		      "ctdb_writerecord: Can not write, read-only record.");
+		return false;
+	}
+
+	if (lock->ctdb_db != ctdb_db) {
+		errno = EBADF;
+		DEBUG(ctdb_db->ctdb, LOG_ALERT,
+		      "ctdb_writerecord: Can not write, wrong ctdb_db.");
+		return false;
+	}
+
+	if (lock->held_magic != lock_magic(lock)) {
+		errno = EBADF;
+		DEBUG(ctdb_db->ctdb, LOG_ALERT,
+		      "ctdb_writerecord: Can not write. Lock has been released.");
+		return false;
+	}
+		
+	if (ctdb_db->persistent) {
+		errno = EINVAL;
+		DEBUG(ctdb_db->ctdb, LOG_ALERT,
+		      "ctdb_writerecord: cannot write to persistent db");
+		return false;
+	}
+
+	switch (ctdb_local_store(ctdb_db->tdb, lock->key, lock->hdr, data)) {
+	case 0:
+		DEBUG(ctdb_db->ctdb, LOG_DEBUG,
+		      "ctdb_writerecord: optimized away noop write.");
+		/* fall thru */
+	case 1:
+		return true;
+
+	default:
+		switch (errno) {
+		case ENOMEM:
+			DEBUG(ctdb_db->ctdb, LOG_CRIT,
+			      "ctdb_writerecord: out of memory.");
+			break;
+		case EINVAL:
+			DEBUG(ctdb_db->ctdb, LOG_ALERT,
+			      "ctdb_writerecord: record changed under lock?");
+			break;
+		default: /* TDB already logged. */
+			break;
+		}
+		return false;
+	}
+}
+
+
+struct ctdb_traverse_state {
+	struct ctdb_request *handle;
+	struct ctdb_db *ctdb_db;
+	uint64_t srvid;
+
+	ctdb_traverse_callback_t callback;
+	void *cbdata;
+};
+
+static void traverse_remhnd_cb(struct ctdb_connection *ctdb,
+                        struct ctdb_request *req, void *private_data)
+{
+	struct ctdb_traverse_state *state = private_data;
+
+	if (!ctdb_remove_message_handler_recv(ctdb, state->handle)) {
+		DEBUG(ctdb, LOG_ERR,
+				"Failed to remove message handler for"
+				" traverse.");
+		state->callback(state->ctdb_db->ctdb, state->ctdb_db,
+				TRAVERSE_STATUS_ERROR,
+				tdb_null, tdb_null,
+				state->cbdata);
+	}
+	ctdb_request_free(state->handle);
+	state->handle = NULL;
+	free(state);
+}
+	
+static void msg_h(struct ctdb_connection *ctdb, uint64_t srvid,
+	   TDB_DATA data, void *private_data)
+{
+	struct ctdb_traverse_state *state = private_data;
+	struct ctdb_db *ctdb_db = state->ctdb_db;
+	struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr;
+	TDB_DATA key;
+
+	if (data.dsize < sizeof(uint32_t) ||
+	    d->length != data.dsize) {
+		DEBUG(ctdb, LOG_ERR,
+			"Bad data size %u in traverse_handler",
+			(unsigned)data.dsize);
+		state->callback(state->ctdb_db->ctdb, state->ctdb_db,
+				TRAVERSE_STATUS_ERROR,
+				tdb_null, tdb_null,
+				state->cbdata);
+		state->handle = ctdb_remove_message_handler_send(
+				state->ctdb_db->ctdb, state->srvid,
+				msg_h, state,
+				traverse_remhnd_cb, state);
+		return;
+	}
+
+	key.dsize = d->keylen;
+	key.dptr  = &d->data[0];
+	data.dsize = d->datalen;
+	data.dptr = &d->data[d->keylen];
+
+	if (key.dsize == 0 && data.dsize == 0) {
+		state->callback(state->ctdb_db->ctdb, state->ctdb_db,
+				TRAVERSE_STATUS_FINISHED,
+				tdb_null, tdb_null,
+				state->cbdata);
+		state->handle = ctdb_remove_message_handler_send(
+				state->ctdb_db->ctdb, state->srvid,
+				msg_h, state,
+				traverse_remhnd_cb, state);
+		return;
+	}
+
+	if (data.dsize <= sizeof(struct ctdb_ltdb_header)) {
+		/* empty records are deleted records in ctdb */
+		return;
+	}
+
+	data.dsize -= sizeof(struct ctdb_ltdb_header);
+	data.dptr  += sizeof(struct ctdb_ltdb_header);
+
+	if (state->callback(ctdb, ctdb_db,
+			TRAVERSE_STATUS_RECORD,
+			key, data, state->cbdata) != 0) {
+		state->handle = ctdb_remove_message_handler_send(
+				state->ctdb_db->ctdb, state->srvid,
+				msg_h, state,
+				traverse_remhnd_cb, state);
+		return;
+	}
+}
+
+static void traverse_start_cb(struct ctdb_connection *ctdb,
+                        struct ctdb_request *req, void *private_data)
+{
+	struct ctdb_traverse_state *state = private_data;
+
+        ctdb_request_free(state->handle);
+	state->handle = NULL;
+}
+
+static void traverse_msghnd_cb(struct ctdb_connection *ctdb,
+                        struct ctdb_request *req, void *private_data)
+{
+	struct ctdb_traverse_state *state = private_data;
+	struct ctdb_db *ctdb_db = state->ctdb_db;
+	struct ctdb_traverse_start t;
+
+	if (!ctdb_set_message_handler_recv(ctdb, state->handle)) {
+		DEBUG(ctdb, LOG_ERR,
+				"Failed to register message handler for"
+				" traverse.");
+		state->callback(state->ctdb_db->ctdb, state->ctdb_db,
+				TRAVERSE_STATUS_ERROR,
+				tdb_null, tdb_null,
+				state->cbdata);
+	        ctdb_request_free(state->handle);
+		state->handle = NULL;
+		free(state);
+		return;
+        }
+        ctdb_request_free(state->handle);
+	state->handle = NULL;
+
+	t.db_id = ctdb_db->id;
+	t.srvid = state->srvid;
+	t.reqid = 0;
+
+	state->handle = new_ctdb_control_request(ctdb,
+				CTDB_CONTROL_TRAVERSE_START,
+				CTDB_CURRENT_NODE,
+				&t, sizeof(t),
+				traverse_start_cb, state);
+	if (state->handle == NULL) {
+		DEBUG(ctdb, LOG_ERR,
+				"ctdb_traverse_async:"
+				" failed to send traverse_start control");
+		state->callback(state->ctdb_db->ctdb, state->ctdb_db,
+				TRAVERSE_STATUS_ERROR,
+				tdb_null, tdb_null,
+				state->cbdata);
+		state->handle = ctdb_remove_message_handler_send(
+				state->ctdb_db->ctdb, state->srvid,
+				msg_h, state,
+				traverse_remhnd_cb, state);
+		return;
+	}
+}
+
+bool ctdb_traverse_async(struct ctdb_db *ctdb_db,
+			 ctdb_traverse_callback_t callback, void *cbdata)
+{
+	struct ctdb_connection *ctdb = ctdb_db->ctdb;
+	struct ctdb_traverse_state *state;
+	static uint32_t tid = 0;
+
+	state = malloc(sizeof(struct ctdb_traverse_state));
+	if (state == NULL) {
+		DEBUG(ctdb, LOG_ERR,
+				"ctdb_traverse_async: no memory."
+				" allocate state failed");
+		return false;
+	}
+
+	tid++;
+	state->srvid = CTDB_SRVID_TRAVERSE_RANGE|tid;
+
+	state->callback = callback;
+	state->cbdata   = cbdata;
+	state->ctdb_db  = ctdb_db;
+
+	state->handle = ctdb_set_message_handler_send(ctdb_db->ctdb,
+				state->srvid,
+				msg_h, state,
+				traverse_msghnd_cb, state);
+	if (state->handle == NULL) {
+		DEBUG(ctdb, LOG_ERR,
+			"ctdb_traverse_async:"
+			" failed ctdb_set_message_handler_send");
+		free(state);
+		return false;
+	}
+
+	return true;
+}
+
+int ctdb_num_out_queue(struct ctdb_connection *ctdb)
+{
+	struct ctdb_request *req;
+	int i;
+
+	for (i = 0, req = ctdb->outq; req; req = req->next, i++)
+		;
+
+	return i;
+}
+
+int ctdb_num_in_flight(struct ctdb_connection *ctdb)
+{
+	struct ctdb_request *req;
+	int i;
+
+	for (i = 0, req = ctdb->doneq; req; req = req->next, i++)
+		;
+
+	return i;
+}
+
+int ctdb_num_active(struct ctdb_connection *ctdb)
+{
+	return ctdb_num_out_queue(ctdb)
+		 + ctdb_num_in_flight(ctdb);
+}
+

Added: branches/ctdb/squeeze-backports/libctdb/io_elem.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/io_elem.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/io_elem.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,163 @@
+/*
+   Simple queuing of input and output records for libctdb
+
+   Copyright (C) Rusty Russell 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <sys/types.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "libctdb_private.h"
+#include "io_elem.h"
+#include <tdb.h>
+#include <netinet/in.h>
+#include <dlinklist.h>
+#include <ctdb_protocol.h> // For CTDB_DS_ALIGNMENT and ctdb_req_header
+
+struct io_elem {
+	struct io_elem *next, *prev;
+	size_t len, off;
+	char *data;
+};
+
+struct io_elem *new_io_elem(size_t len)
+{
+	struct io_elem *elem;
+	size_t ask = len;
+
+	len = (len + (CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1);
+
+	elem = malloc(sizeof(*elem));
+	if (!elem)
+		return NULL;
+	elem->data = malloc(len);
+	if (!elem->data) {
+		free(elem);
+		return NULL;
+	}
+
+	/* stamp out any padding to keep valgrind happy */
+	if (ask != len) {
+		memset(elem->data + ask, 0, len-ask);
+	}
+	elem->len = len;
+	elem->off = 0;
+	elem->next = NULL;
+	elem->prev = NULL;
+	return elem;
+}
+
+void free_io_elem(struct io_elem *io)
+{
+	free(io->data);
+	free(io);
+}
+
+bool io_elem_finished(const struct io_elem *io)
+{
+	return io->off == io->len;
+}
+
+void io_elem_init_req_header(struct io_elem *io,
+			     uint32_t operation,
+			     uint32_t destnode,
+			     uint32_t reqid)
+{
+	struct ctdb_req_header *hdr = io_elem_data(io, NULL);
+
+	hdr->length = io->len;
+	hdr->ctdb_magic = CTDB_MAGIC;
+	hdr->ctdb_version = CTDB_VERSION;
+	/* Generation and srcnode only used for inter-ctdbd communication. */
+	hdr->generation = 0;
+	hdr->destnode = destnode;
+	hdr->srcnode = 0;
+	hdr->operation = operation;
+	hdr->reqid = reqid;
+}
+
+/* Access to raw data: if len is non-NULL it is filled in. */
+void *io_elem_data(const struct io_elem *io, size_t *len)
+{
+	if (len)
+		*len = io->len;
+	return io->data;
+}
+
+/* Returns -1 if we hit an error.  Errno will be set. */
+int read_io_elem(int fd, struct io_elem *io)
+{
+	ssize_t ret;
+
+	ret = read(fd, io->data + io->off, io->len - io->off);
+	if (ret < 0)
+		return ret;
+
+	io->off += ret;
+	if (io_elem_finished(io)) {
+		struct ctdb_req_header *hdr = (void *)io->data;
+
+		/* Finished.  But maybe this was just header? */
+		if (io->len == sizeof(*hdr) && hdr->length > io->len) {
+			int reret;
+			void *newdata;
+			/* Enlarge and re-read. */
+			io->len = hdr->length;
+			newdata = realloc(io->data, io->len);
+			if (!newdata)
+				return -1;
+			io->data = newdata;
+			/* Try reading again immediately. */
+			reret = read_io_elem(fd, io);
+			if (reret >= 0)
+				reret += ret;
+			return reret;
+		}
+	}
+	return ret;
+}
+
+/* Returns -1 if we hit an error.  Errno will be set. */
+int write_io_elem(int fd, struct io_elem *io)
+{
+	ssize_t ret;
+
+	ret = write(fd, io->data + io->off, io->len - io->off);
+	if (ret < 0)
+		return ret;
+
+	io->off += ret;
+	return ret;
+}
+
+void io_elem_reset(struct io_elem *io)
+{
+	io->off = 0;
+}
+
+void io_elem_queue(struct ctdb_connection *ctdb, struct io_elem *io)
+{
+	DLIST_ADD_END(ctdb->inqueue, io, struct io_elem);
+}
+
+void io_elem_dequeue(struct ctdb_connection *ctdb, struct io_elem *io)
+{
+	DLIST_REMOVE(ctdb->inqueue, io);
+}
+

Added: branches/ctdb/squeeze-backports/libctdb/io_elem.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/io_elem.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/io_elem.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,41 @@
+#ifndef _LIBCTDB_IO_ELEM_H
+#define _LIBCTDB_IO_ELEM_H
+#include <stdbool.h>
+
+/* Packets are of form: <u32 length><data>. */
+
+/* Create a new queue element of at least len bytes (for reading or writing).
+ * Len may be rounded up for alignment. */
+struct io_elem *new_io_elem(size_t len);
+
+/* Free a queue element. */
+void free_io_elem(struct io_elem *io);
+
+/* If finished, this returns the request header, otherwise NULL. */
+bool io_elem_finished(const struct io_elem *io);
+
+/* Reset an io_elem to the start. */
+void io_elem_reset(struct io_elem *io);
+
+/* Access to raw data: if len is non-NULL it is filled in. */
+void *io_elem_data(const struct io_elem *io, size_t *len);
+
+/* Initialise the struct ctdb_req_header at the front of the I/O. */
+void io_elem_init_req_header(struct io_elem *io,
+			     uint32_t operation,
+			     uint32_t destnode,
+			     uint32_t reqid);
+
+/* Returns -1 if we hit an error.  Otherwise bytes read. */
+int read_io_elem(int fd, struct io_elem *io);
+
+/* Returns -1 if we hit an error.  Otherwise bytes written. */
+int write_io_elem(int fd, struct io_elem *io);
+
+/* Queues a received io element for later processing */
+void io_elem_queue(struct ctdb_connection *ctdb, struct io_elem *io);
+
+/* Removes an element from the queue */
+void io_elem_dequeue(struct ctdb_connection *ctdb, struct io_elem *io);
+
+#endif /* _LIBCTDB_IO_ELEM_H */

Added: branches/ctdb/squeeze-backports/libctdb/libctdb_private.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/libctdb_private.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/libctdb_private.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,107 @@
+#ifndef _LIBCTDB_PRIVATE_H
+#define _LIBCTDB_PRIVATE_H
+#include <dlinklist.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <ctdb.h>
+#include <ctdb_protocol.h>
+#include <syslog.h>
+#include <tdb.h>
+#include <stddef.h>
+
+#ifndef offsetof
+#define offsetof(t,f) ((unsigned int)&((t *)0)->f)
+#endif
+
+#ifndef COLD_ATTRIBUTE
+#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+#define COLD_ATTRIBUTE __attribute__((cold))
+#else
+#define COLD_ATTRIBUTE
+#endif
+#endif /* COLD_ATTRIBUTE */
+
+#define DEBUG(ctdb, lvl, format, args...) do { if (lvl <= ctdb_log_level) { ctdb_do_debug(ctdb, lvl, format , ## args ); }} while(0)
+
+struct message_handler_info;
+struct ctdb_reply_call;
+
+struct ctdb_request {
+	struct ctdb_connection *ctdb;
+	struct ctdb_request *next, *prev;
+	bool cancelled;
+
+	struct io_elem *io;
+	union {
+		struct ctdb_req_header *hdr;
+		struct ctdb_req_call *call;
+		struct ctdb_req_control *control;
+		struct ctdb_req_message *message;
+	} hdr;
+
+	struct io_elem *reply;
+
+	ctdb_callback_t callback;
+	void *priv_data;
+
+	/* Extra per-request info. */
+	void (*extra_destructor)(struct ctdb_connection *,
+				 struct ctdb_request *);
+	void *extra;
+};
+
+struct ctdb_connection {
+	/* Socket to ctdbd. */
+	int fd;
+	/* Currently our failure mode is simple; return -1 from ctdb_service */
+	bool broken;
+	/* Linked list of pending outgoings. */
+	struct ctdb_request *outq;
+	/* Finished outgoings (awaiting response) */
+	struct ctdb_request *doneq;
+
+	/* Current incoming. */
+	struct io_elem *in;
+	/* Queue of received pdus */
+	struct io_elem *inqueue;
+
+	/* Guess at a good reqid to try next. */
+	uint32_t next_id;
+	/* List of messages */
+	struct message_handler_info *message_handlers;
+	/* PNN of this ctdb: valid by the time we do our first db connection. */
+	uint32_t pnn;
+	/* Chain of locks we hold. */
+	struct ctdb_lock *locks;
+	/* Extra logging. */
+	ctdb_log_fn_t log;
+	void *log_priv;
+};
+
+/* ctdb.c */
+struct ctdb_request *new_ctdb_request(struct ctdb_connection *ctdb, size_t len,
+				      ctdb_callback_t cb, void *cbdata);
+struct ctdb_request *new_ctdb_control_request(struct ctdb_connection *ctdb,
+					      uint32_t opcode,
+					      uint32_t destnode,
+					      const void *extra_data,
+					      size_t extra,
+					      ctdb_callback_t, void *);
+uint32_t new_reqid(struct ctdb_connection *ctdb);
+
+struct ctdb_reply_control *unpack_reply_control(struct ctdb_request *req,
+						enum ctdb_controls control);
+void ctdb_cancel_callback(struct ctdb_connection *ctdb,
+			  struct ctdb_request *req,
+			  void *unused);
+
+/* logging.c */
+void ctdb_tdb_log_bridge(struct tdb_context *tdb,
+			 enum tdb_debug_level level,
+			 const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
+
+void ctdb_do_debug(struct ctdb_connection *, int, const char *format, ...)
+	PRINTF_ATTRIBUTE(3, 4) COLD_ATTRIBUTE;
+
+#endif /* _LIBCTDB_PRIVATE_H */

Added: branches/ctdb/squeeze-backports/libctdb/local_tdb.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/local_tdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/local_tdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,103 @@
+/*
+   libctdb local tdb access code
+
+   Copyright (C) Andrew Tridgell  2006
+   Copyright (C) Rusty Russell  2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ctdb.h>
+#include <tdb.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <ctdb_protocol.h> // For struct ctdb_ltdb_header
+#include "local_tdb.h"
+
+/*
+  fetch a record from the ltdb, separating out the header information
+  and returning the body of the record.  The caller should free() the
+  header when done, rather than the (optional) data->dptr.
+*/
+struct ctdb_ltdb_header *ctdb_local_fetch(struct tdb_context *tdb,
+					  TDB_DATA key, TDB_DATA *data)
+{
+	TDB_DATA rec;
+
+	rec = tdb_fetch(tdb, key);
+	if (rec.dsize < sizeof(struct ctdb_ltdb_header)) {
+		free(rec.dptr);
+		return NULL;
+	}
+
+	if (data) {
+		data->dsize = rec.dsize - sizeof(struct ctdb_ltdb_header);
+		data->dptr = rec.dptr + sizeof(struct ctdb_ltdb_header);
+	}
+	return (struct ctdb_ltdb_header *)rec.dptr;
+}
+
+
+/*
+  write a record to a normal database: 1 on success, 0 if noop, -1 on fail.
+  errno = EIO => tdb error.
+*/
+int ctdb_local_store(struct tdb_context *tdb, TDB_DATA key,
+		     struct ctdb_ltdb_header *header, TDB_DATA data)
+{
+	TDB_DATA rec;
+	int ret;
+	TDB_DATA old;
+
+	old = tdb_fetch(tdb, key);
+	if (old.dsize < sizeof(*header)) {
+		errno = EIO;
+		return -1;
+	}
+
+	/* Debugging check: we have lock and should not change hdr. */
+	if (memcmp(old.dptr, header, sizeof(*header)) != 0) {
+		free(old.dptr);
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* Optimize out the nothing-changed case. */
+	if (old.dsize == sizeof(*header) + data.dsize
+	    && memcmp(old.dptr+sizeof(*header), data.dptr, data.dsize) == 0) {
+		free(old.dptr);
+		return 0;
+	}
+
+	rec.dsize = sizeof(*header) + data.dsize;
+	rec.dptr = malloc(rec.dsize);
+	if (!rec.dptr) {
+		free(old.dptr);
+		errno = ENOMEM;
+		return -1;
+	}
+	memcpy(rec.dptr, header, sizeof(*header));
+	memcpy(rec.dptr + sizeof(*header), data.dptr, data.dsize);
+
+	ret = tdb_store(tdb, key, rec, TDB_REPLACE);
+	free(old.dptr);
+	free(rec.dptr);
+	if (ret != 0) {
+		errno = EIO;
+		return -1;
+	}
+	return 1;
+}

Added: branches/ctdb/squeeze-backports/libctdb/local_tdb.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/local_tdb.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/local_tdb.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,10 @@
+#ifndef _LIBCTDB_LOCAL_TDB_H
+#define _LIBCTDB_LOCAL_TDB_H
+
+struct ctdb_ltdb_header *ctdb_local_fetch(struct tdb_context *tdb,
+					  TDB_DATA key, TDB_DATA *data);
+
+int ctdb_local_store(struct tdb_context *tdb, TDB_DATA key,
+		     struct ctdb_ltdb_header *header, TDB_DATA data);
+
+#endif /* _LIBCTDB_LOCAL_TDB_H */

Added: branches/ctdb/squeeze-backports/libctdb/logging.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/logging.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/logging.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,108 @@
+/*
+   logging wrapper for libctdb
+
+   Copyright (C) Ronnie Sahlberg 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <errno.h>
+#include <ctdb.h>
+#include <string.h>
+#include <tdb.h>
+#include "libctdb_private.h"
+
+int ctdb_log_level = LOG_WARNING;
+
+void ctdb_do_debug(struct ctdb_connection *ctdb,
+		   int severity, const char *format, ...)
+{
+        va_list ap;
+
+        va_start(ap, format);
+	ctdb->log(ctdb->log_priv, severity, format, ap);
+        va_end(ap);
+}
+
+/* Attach tdb logging to our ctdb logging. */
+void ctdb_tdb_log_bridge(struct tdb_context *tdb,
+			 enum tdb_debug_level level,
+			 const char *format, ...)
+{
+	va_list ap;
+	int sev;
+	struct ctdb_connection *ctdb = tdb_get_logging_private(tdb);
+	char *newformat;
+
+	switch (level) {
+	case TDB_DEBUG_FATAL:
+		sev = LOG_CRIT;
+		break;
+	case TDB_DEBUG_ERROR:
+		sev = LOG_ERR;
+		break;
+	case TDB_DEBUG_WARNING:
+		sev = LOG_WARNING;
+		break;
+	case TDB_DEBUG_TRACE:
+		sev = LOG_DEBUG;
+		break;
+	default:
+		sev = LOG_CRIT;
+	}
+
+	if (sev > ctdb_log_level) {
+		return;
+	}
+
+	newformat = malloc(sizeof("TDB error: ") + strlen(format));
+	if (!newformat) {
+		DEBUG(ctdb, LOG_ERR,
+		      "memory allocation failure reporting tdb error %s",
+		      format);
+		return;
+	}
+
+	/* Prepend TDB error: and remove \n */
+	strcpy(newformat, "TDB error: ");
+	strcat(newformat, format);
+	if (newformat[strlen(newformat)-1] == '\n')
+		newformat[strlen(newformat)-1] = '\0';
+
+	va_start(ap, format);
+	ctdb->log(ctdb->log_priv, sev, newformat, ap);
+	va_end(ap);
+	free(newformat);
+}
+
+/* Convenient log helper. */
+void ctdb_log_file(FILE *outf, int priority, const char *format, va_list ap)
+{
+	fprintf(outf, "%s:",
+		priority == LOG_EMERG ? "EMERG" :
+		priority == LOG_ALERT ? "ALERT" :
+		priority == LOG_CRIT ? "CRIT" :
+		priority == LOG_ERR ? "ERR" :
+		priority == LOG_WARNING ? "WARNING" :
+		priority == LOG_NOTICE ? "NOTICE" :
+		priority == LOG_INFO ? "INFO" :
+		priority == LOG_DEBUG ? "DEBUG" :
+		"Unknown Error Level");
+
+	vfprintf(outf, format, ap);
+	if (priority == LOG_ERR) {
+		fprintf(outf, " (%s)", strerror(errno));
+	}
+	fprintf(outf, "\n");
+}

Added: branches/ctdb/squeeze-backports/libctdb/messages.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/messages.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/messages.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,236 @@
+/*
+   core of libctdb
+
+   Copyright (C) Rusty Russell 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libctdb_private.h"
+#include "messages.h"
+#include "io_elem.h"
+#include <ctdb.h>
+#include <tdb.h>
+#include <ctdb_protocol.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* Remove type-safety macros. */
+#undef ctdb_set_message_handler_send
+#undef ctdb_set_message_handler_recv
+#undef ctdb_remove_message_handler_send
+
+struct message_handler_info {
+	struct message_handler_info *next, *prev;
+
+	uint64_t srvid;
+	ctdb_message_fn_t handler;
+	void *handler_data;
+};
+
+void deliver_message(struct ctdb_connection *ctdb, struct ctdb_req_header *hdr)
+{
+	struct message_handler_info *i;
+	struct ctdb_req_message *msg = (struct ctdb_req_message *)hdr;
+	TDB_DATA data;
+	bool found;
+
+	data.dptr = msg->data;
+	data.dsize = msg->datalen;
+
+	/* Note: we want to call *every* handler: there may be more than one */
+	for (i = ctdb->message_handlers; i; i = i->next) {
+		if (i->srvid == msg->srvid) {
+			i->handler(ctdb, msg->srvid, data, i->handler_data);
+			found = true;
+		}
+	}
+	if (!found) {
+		DEBUG(ctdb, LOG_WARNING,
+		      "ctdb_service: messsage for unregistered srvid %llu",
+		      (unsigned long long)msg->srvid);
+	}
+}
+
+void remove_message_handlers(struct ctdb_connection *ctdb)
+{
+	struct message_handler_info *i;
+
+	/* ctdbd should unregister automatically when we close fd, so we don't
+	   need to do that here. */
+	while ((i = ctdb->message_handlers) != NULL) {
+		DLIST_REMOVE(ctdb->message_handlers, i);
+		free(i);
+	}
+}
+
+static void free_info(struct ctdb_connection *ctdb, struct ctdb_request *req);
+
+struct ctdb_request *
+ctdb_set_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
+			      ctdb_message_fn_t handler, void *handler_data,
+			      ctdb_callback_t callback, void *private_data)
+{
+	struct message_handler_info *info;
+	struct ctdb_request *req;
+
+	info = malloc(sizeof(*info));
+	if (!info) {
+		DEBUG(ctdb, LOG_ERR,
+		      "ctdb_set_message_handler_send: allocating info");
+		return NULL;
+	}
+
+	req = new_ctdb_control_request(ctdb, CTDB_CONTROL_REGISTER_SRVID,
+				       CTDB_CURRENT_NODE, NULL, 0,
+				       callback, private_data);
+	if (!req) {
+		DEBUG(ctdb, LOG_ERR,
+		      "ctdb_set_message_handler_send: allocating request");
+		free(info);
+		return NULL;
+	}
+	req->extra = info;
+	req->extra_destructor = free_info;
+	req->hdr.control->srvid = srvid;
+
+	info->srvid = srvid;
+	info->handler = handler;
+	info->handler_data = handler_data;
+
+	DEBUG(ctdb, LOG_DEBUG,
+	      "ctdb_set_message_handler_send: sending request %u for id %llx",
+	      req->hdr.hdr->reqid, (unsigned long long)srvid);
+	return req;
+}
+
+static void free_info(struct ctdb_connection *ctdb, struct ctdb_request *req)
+{
+	free(req->extra);
+}
+
+bool ctdb_set_message_handler_recv(struct ctdb_connection *ctdb,
+				   struct ctdb_request *req)
+{
+	struct message_handler_info *info = req->extra;
+	struct ctdb_reply_control *reply;
+
+	reply = unpack_reply_control(req, CTDB_CONTROL_REGISTER_SRVID);
+	if (!reply) {
+		return false;
+	}
+	if (reply->status != 0) {
+		DEBUG(ctdb, LOG_ERR,
+		      "ctdb_set_message_handler_recv: status %i",
+		      reply->status);
+		return false;
+	}
+
+	/* Put ourselves in list of handlers. */
+	DLIST_ADD(ctdb->message_handlers, info);
+	/* Keep safe from destructor */
+	req->extra = NULL;
+	return true;
+}
+
+struct ctdb_request *
+ctdb_remove_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
+				 ctdb_message_fn_t handler, void *hdata,
+				 ctdb_callback_t callback, void *cbdata)
+{
+	struct message_handler_info *i;
+	struct ctdb_request *req;
+
+	for (i = ctdb->message_handlers; i; i = i->next) {
+		if (i->srvid == srvid
+		    && i->handler == handler && i->handler_data == hdata) {
+			break;
+		}
+	}
+	if (!i) {
+		DEBUG(ctdb, LOG_ALERT,
+		      "ctdb_remove_message_handler_send: no such handler");
+		errno = ENOENT;
+		return NULL;
+	}
+
+	req = new_ctdb_control_request(ctdb, CTDB_CONTROL_DEREGISTER_SRVID,
+				       CTDB_CURRENT_NODE, NULL, 0,
+				       callback, cbdata);
+	if (!req) {
+		DEBUG(ctdb, LOG_ERR,
+		      "ctdb_remove_message_handler_send: allocating request");
+		return NULL;
+	}
+	req->hdr.control->srvid = srvid;
+	req->extra = i;
+
+	DEBUG(ctdb, LOG_DEBUG,
+	      "ctdb_set_remove_handler_send: sending request %u for id %llu",
+	      req->hdr.hdr->reqid, (unsigned long long)srvid);
+	return req;
+}
+
+bool ctdb_remove_message_handler_recv(struct ctdb_connection *ctdb,
+				      struct ctdb_request *req)
+{
+	struct message_handler_info *handler = req->extra;
+	struct ctdb_reply_control *reply;
+
+	reply = unpack_reply_control(req, CTDB_CONTROL_DEREGISTER_SRVID);
+	if (!reply) {
+		return false;
+	}
+	if (reply->status != 0) {
+		DEBUG(ctdb, LOG_ERR,
+		      "ctdb_remove_message_handler_recv: status %i",
+		      reply->status);
+		return false;
+	}
+
+	/* Remove ourselves from list of handlers. */
+	DLIST_REMOVE(ctdb->message_handlers, handler);
+	free(handler);
+	/* Crash if they call this again! */
+	req->extra = NULL;
+	return true;
+}
+
+bool ctdb_send_message(struct ctdb_connection *ctdb,
+		      uint32_t pnn, uint64_t srvid,
+		      TDB_DATA data)
+{
+	struct ctdb_request *req;
+	struct ctdb_req_message *pkt;
+
+	/* We just discard it once it's finished: no reply. */
+	req = new_ctdb_request(
+		ctdb, offsetof(struct ctdb_req_message, data) + data.dsize,
+		ctdb_cancel_callback, NULL);
+	if (!req) {
+		DEBUG(ctdb, LOG_ERR, "ctdb_set_message: allocating message");
+		return false;
+	}
+
+	io_elem_init_req_header(req->io,
+				CTDB_REQ_MESSAGE, pnn, new_reqid(ctdb));
+
+	pkt = req->hdr.message;
+	pkt->srvid = srvid;
+	pkt->datalen = data.dsize;
+	memcpy(pkt->data, data.dptr, data.dsize);
+	DLIST_ADD_END(ctdb->outq, req, struct ctdb_request);
+	return true;
+}

Added: branches/ctdb/squeeze-backports/libctdb/messages.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/messages.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/messages.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,9 @@
+#ifndef _LIBCTDB_MESSAGE_H
+#define _LIBCTDB_MESSAGE_H
+struct message_handler_info;
+struct ctdb_connection;
+struct ctdb_req_header;
+
+void deliver_message(struct ctdb_connection *ctdb, struct ctdb_req_header *hdr);
+void remove_message_handlers(struct ctdb_connection *ctdb);
+#endif /* _LIBCTDB_MESSAGE_H */

Added: branches/ctdb/squeeze-backports/libctdb/sync.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/sync.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/sync.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,246 @@
+/*
+   synchronous wrappers for libctdb
+
+   Copyright (C) Rusty Russell 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <ctdb.h>
+#include <stdbool.h>
+#include <poll.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "libctdb_private.h"
+
+/* Remove type-safety macros. */
+#undef ctdb_set_message_handler
+
+/* On failure, frees req and returns NULL. */
+static struct ctdb_request *synchronous(struct ctdb_connection *ctdb,
+					struct ctdb_request *req,
+					bool *done)
+{
+	struct pollfd fds;
+
+	/* Pass through allocation failures. */
+	if (!req)
+		return NULL;
+
+	fds.fd = ctdb_get_fd(ctdb);
+	while (!*done) {
+		fds.events = ctdb_which_events(ctdb);
+		if (poll(&fds, 1, -1) < 0) {
+			/* Signalled is OK, other error is bad. */
+			if (errno == EINTR)
+				continue;
+			ctdb_cancel(ctdb, req);
+			DEBUG(ctdb, LOG_ERR, "ctdb_synchronous: poll failed");
+			return NULL;
+		}
+		if (!ctdb_service(ctdb, fds.revents)) {
+			/* It can have failed after it completed request. */
+			if (!*done)
+				ctdb_cancel(ctdb, req);
+			else
+				ctdb_request_free(req);
+			return NULL;
+		}
+	}
+	return req;
+}
+
+static void set(struct ctdb_connection *ctdb,
+		struct ctdb_request *req, bool *done)
+{
+	*done = true;
+}
+
+bool ctdb_getrecmaster(struct ctdb_connection *ctdb,
+		       uint32_t destnode, uint32_t *recmaster)
+{
+	struct ctdb_request *req;
+	bool done = false;
+	bool ret = false;
+
+	req = synchronous(ctdb,
+			  ctdb_getrecmaster_send(ctdb, destnode, set, &done),
+			  &done);
+	if (req != NULL) {
+		ret = ctdb_getrecmaster_recv(ctdb, req, recmaster);
+		ctdb_request_free(req);
+	}
+	return ret;
+}
+
+bool ctdb_getrecmode(struct ctdb_connection *ctdb,
+		       uint32_t destnode, uint32_t *recmode)
+{
+	struct ctdb_request *req;
+	bool done = false;
+	bool ret = false;
+
+	req = synchronous(ctdb,
+			  ctdb_getrecmode_send(ctdb, destnode, set, &done),
+			  &done);
+	if (req != NULL) {
+		ret = ctdb_getrecmode_recv(ctdb, req, recmode);
+		ctdb_request_free(req);
+	}
+	return ret;
+}
+
+struct ctdb_db *ctdb_attachdb(struct ctdb_connection *ctdb,
+			      const char *name, bool persistent,
+			      uint32_t tdb_flags)
+{
+	struct ctdb_request *req;
+	bool done = false;
+	struct ctdb_db *ret = NULL;
+
+	req = synchronous(ctdb,
+			  ctdb_attachdb_send(ctdb, name, persistent, tdb_flags,
+					     set, &done),
+			  &done);
+	if (req != NULL) {
+		ret = ctdb_attachdb_recv(ctdb, req);
+		ctdb_request_free(req);
+	}
+	return ret;
+}
+
+bool ctdb_getpnn(struct ctdb_connection *ctdb,
+		 uint32_t destnode, uint32_t *pnn)
+{
+	struct ctdb_request *req;
+	bool done = false;
+	bool ret = false;
+
+	req = synchronous(ctdb,
+			  ctdb_getpnn_send(ctdb, destnode, set, &done),
+			  &done);
+	if (req != NULL) {
+		ret = ctdb_getpnn_recv(ctdb, req, pnn);
+		ctdb_request_free(req);
+	}
+	return ret;
+}
+
+bool ctdb_getnodemap(struct ctdb_connection *ctdb,
+		 uint32_t destnode, struct ctdb_node_map **nodemap)
+{
+	struct ctdb_request *req;
+	bool done = false;
+	bool ret = false;
+
+	*nodemap = NULL;
+
+	req = synchronous(ctdb,
+			  ctdb_getnodemap_send(ctdb, destnode, set, &done),
+			  &done);
+	if (req != NULL) {
+		ret = ctdb_getnodemap_recv(ctdb, req, nodemap);
+		ctdb_request_free(req);
+	}
+	return ret;
+}
+
+bool ctdb_getpublicips(struct ctdb_connection *ctdb,
+		       uint32_t destnode, struct ctdb_all_public_ips **ips)
+{
+	struct ctdb_request *req;
+	bool done = false;
+	bool ret = false;
+
+	*ips = NULL;
+
+	req = synchronous(ctdb,
+			  ctdb_getpublicips_send(ctdb, destnode, set, &done),
+			  &done);
+	if (req != NULL) {
+		ret = ctdb_getpublicips_recv(ctdb, req, ips);
+		ctdb_request_free(req);
+	}
+	return ret;
+}
+
+bool ctdb_set_message_handler(struct ctdb_connection *ctdb, uint64_t srvid,
+			      ctdb_message_fn_t handler, void *cbdata)
+{
+	struct ctdb_request *req;
+	bool done = false;
+	bool ret = false;
+
+	req = synchronous(ctdb,
+			  ctdb_set_message_handler_send(ctdb, srvid, handler,
+							cbdata, set, &done),
+			  &done);
+	if (req != NULL) {
+		ret = ctdb_set_message_handler_recv(ctdb, req);
+		ctdb_request_free(req);
+	}
+	return ret;
+}
+
+struct rrl_info {
+	bool done;
+	struct ctdb_lock *lock;
+	TDB_DATA *data;
+};
+
+static void rrl_callback(struct ctdb_db *ctdb_db,
+			 struct ctdb_lock *lock,
+			 TDB_DATA data,
+			 struct rrl_info *rrl)
+{
+	rrl->done = true;
+	rrl->lock = lock;
+	*rrl->data = data;
+}
+
+struct ctdb_lock *ctdb_readrecordlock(struct ctdb_connection *ctdb,
+				      struct ctdb_db *ctdb_db, TDB_DATA key,
+				      TDB_DATA *data)
+{
+	struct pollfd fds;
+	struct rrl_info rrl;
+
+	rrl.done = false;
+	rrl.lock = NULL;
+	rrl.data = data;
+
+	/* Immediate failure is easy. */
+	if (!ctdb_readrecordlock_async(ctdb_db, key, rrl_callback, &rrl))
+		return NULL;
+
+	/* Immediate success is easy. */
+	if (!rrl.done) {
+		/* Otherwise wait until callback called. */
+		fds.fd = ctdb_get_fd(ctdb);
+		while (!rrl.done) {
+			fds.events = ctdb_which_events(ctdb);
+			if (poll(&fds, 1, -1) < 0) {
+				/* Signalled is OK, other error is bad. */
+				if (errno == EINTR)
+					continue;
+				DEBUG(ctdb, LOG_ERR,
+				      "ctdb_readrecordlock: poll failed");
+				return NULL;
+			}
+			if (!ctdb_service(ctdb, fds.revents)) {
+				break;
+			}
+		}
+	}
+	return rrl.lock;
+}

Added: branches/ctdb/squeeze-backports/libctdb/test/Makefile
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/Makefile	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/Makefile	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,23 @@
+CFLAGS=-Wall -g -I../../include/ -I../../lib/talloc/ -I../../lib/tdb/include/ -I../../lib/util/
+LDLIBS=-lreadline
+
+USAGE_SOURCES := $(shell grep -l 'XML Argument' *.c)
+HELP_SOURCES := $(shell grep -l 'XML Help' *.c)
+
+ctdb-test: $(patsubst %.c,%.o,$(wildcard *.c)) generated-usage.o ../../talloc.o ../../common/check.o ../../common/error.o ../../common/freelist.o ../../common/io.o ../../common/lock.o ../../common/open.o ../../common/tdb.o ../../common/transaction.o ../../common/traverse.o
+
+$(patsubst %.c,%.o,$(wildcard *.c)): .help-files
+
+.PHONY: links
+links:
+	cd tools && ./create-links
+
+generated-usage.o: generated-usage.c links .help-files
+generated-usage.c: $(USAGE_SOURCES) tools/gen-usage links
+	tools/gen-usage $(USAGE_SOURCES) >$@
+
+.help-files: $(HELP_SOURCES) links
+	set -e; for f in $(HELP_SOURCES); do tools/gen-help $$f; done; touch .help-files
+
+clean:
+	rm -f ctdb-test .help-files generated-* *.o

Added: branches/ctdb/squeeze-backports/libctdb/test/attachdb.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/attachdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/attachdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,177 @@
+#include "utils.h"
+#include "log.h"
+#include "tui.h"
+#include "ctdb-test.h"
+#include <ctdb.h>
+#include <tdb.h>
+#include <talloc.h>
+#include <dlinklist.h>
+#include <errno.h>
+
+static unsigned int db_num;
+static struct db *dbs;
+
+struct db {
+	struct db *next, *prev;
+	struct ctdb_db *db;
+	const char *name;
+	unsigned int num;
+	bool persistent;
+	uint32_t tdb_flags;
+};
+
+struct ctdb_db *find_db_by_id(unsigned int id)
+{
+	struct db *db;
+
+	for (db = dbs; db; db = db->next) {
+		if (db->num == id)
+			return db->db;
+	}
+	return NULL;
+}
+
+static void attachdb_help(int agc, char **argv)
+{
+#include "generated-attachdb-help:attachdb"
+/*** XML Help:
+    <section id="c:attachdb">
+     <title><command>attachdb</command></title>
+     <para>Attach to a ctdb database</para>
+     <cmdsynopsis>
+      <command>attachdb</command>
+      <arg choice="req"><replaceable>name</replaceable></arg>
+      <arg choice="req"><replaceable>persistent</replaceable></arg>
+      <arg choice="opt"><replaceable>tdb-flags</replaceable></arg>
+     </cmdsynopsis>
+     <para>Attach to the database of the given <replaceable>name</replaceable>.
+	<replaceable>persistent</replaceable> is 'true' or 'false', an
+
+	<replaceable>tdb-flags</replaceable> an optional one or more
+	comma-separated values:</para>
+     <variablelist>
+      <varlistentry>
+       <term>SEQNUM</term>
+       <listitem>
+        <para>Use sequence numbers on the tdb</para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+
+     <para>It uses a consecutive number for each attached db to
+     identify it for other ctdb-test commands, starting with 1.</para>
+
+     <para>Without any options, the <command>attachdb</command>
+      command lists all databases attached.</para>
+     </section>
+*/
+}
+
+static void detachdb_help(int agc, char **argv)
+{
+#include "generated-attachdb-help:detachdb"
+/*** XML Help:
+    <section id="c:detachdb">
+     <title><command>detachdb</command></title>
+     <para>Detach from a ctdb database</para>
+     <cmdsynopsis>
+      <command>detachdb</command>
+      <arg choice="req"><replaceable>number</replaceable></arg>
+     </cmdsynopsis>
+     <para>Detach from the database returned by <command>attachdb</command>.
+     </para>
+     </section>
+*/
+}
+static int db_destructor(struct db *db)
+{
+	ctdb_detachdb(get_ctdb(), db->db);
+	DLIST_REMOVE(dbs, db);
+	return 0;
+}
+
+static bool detachdb(int argc, char **argv)
+{
+	struct db *db;
+
+	if (argc != 2) {
+		log_line(LOG_ALWAYS, "Need database number");
+		return false;
+	}
+
+	for (db = dbs; db; db = db->next) {
+		if (db->num == atoi(argv[1]))
+			break;
+	}
+	if (!db) {
+		log_line(LOG_ALWAYS, "Unknown db number %s", argv[1]);
+		return false;
+	}
+	talloc_free(db);
+	return true;
+}
+
+static bool attachdb(int argc, char **argv)
+{
+	struct db *db;
+
+	if (!get_ctdb()) {
+		log_line(LOG_ALWAYS, "No ctdb connection");
+		return false;
+	}
+
+	if (argc == 1) {
+		log_line(LOG_UI, "Databases currently attached:");
+		for (db = dbs; db; db = db->next) {
+			log_line(LOG_ALWAYS, "  %i: %s: %s %u",
+				 db->num, db->name,
+				 db->persistent
+				 ? "persistent" : "not persistent",
+				 db->tdb_flags);
+		}
+		return true;
+	}
+	if (argc != 3 && argc != 4) {
+		log_line(LOG_ALWAYS, "Need 2 or 3 args");
+		return false;
+	}
+	db = talloc(working, struct db);
+	db->name = talloc_strdup(db, argv[1]);
+	if (strcasecmp(argv[2], "true") == 0)
+		db->persistent = true;
+	else if (strcasecmp(argv[2], "false") == 0)
+		db->persistent = false;
+	else {
+		log_line(LOG_ALWAYS, "persistent should be true or false");
+		talloc_free(db);
+		return false;
+	}
+	db->tdb_flags = 0;
+	if (argc == 4) {
+		if (strcasecmp(argv[3], "seqnum") == 0)
+			db->tdb_flags |= TDB_SEQNUM;
+		else {
+			log_line(LOG_ALWAYS, "invalid tdb-flags");
+			talloc_free(db);
+			return false;
+		}
+	}
+	db->db = ctdb_attachdb(get_ctdb(), db->name, db->persistent,
+			       db->tdb_flags);
+	if (!db->db) {
+		log_line(LOG_UI, "ctdb_attachdb: %s", strerror(errno));
+		return false;
+	}
+	db->num = ++db_num;
+	DLIST_ADD(dbs, db);
+	talloc_set_destructor(db, db_destructor);
+	log_line(LOG_UI, "attached: %u", db->num);
+	return true;
+}
+
+static void attachdb_init(void)
+{
+	tui_register_command("attachdb", attachdb, attachdb_help);
+	tui_register_command("detachdb", detachdb, detachdb_help);
+}
+init_call(attachdb_init);

Added: branches/ctdb/squeeze-backports/libctdb/test/ctdb-test.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/ctdb-test.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/ctdb-test.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,454 @@
+/*
+   test driver for libctdb
+
+   Copyright (C) Rusty Russell 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <talloc.h>
+#include <tdb.h>
+
+/* We replace the following functions, for finer control. */
+#define poll(fds, nfds, timeout) ctdb_test_poll((fds), (nfds), (timeout), __location__)
+#define malloc(size) ctdb_test_malloc((size), __location__)
+#define free(ptr) ctdb_test_free((ptr), __location__)
+#define realloc(ptr, size) ctdb_test_realloc((ptr), (size), __location__)
+#define read(fd, buf, count) ctdb_test_read((fd), (buf), (count), __location__)
+#define write(fd, buf, count) ctdb_test_write((fd), (buf), (count), __location__)
+#define socket(domain, type, protocol) ctdb_test_socket((domain), (type), (protocol), __location__)
+#define connect(sockfd, addr, addrlen) ctdb_test_connect((sockfd), (addr), (addrlen), __location__)
+
+#define tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, log_ctx, hash_fn) ctdb_test_tdb_open_ex((name), (hash_size), (tdb_flags), (open_flags), (mode), (log_ctx), (hash_fn), __location__)
+#define tdb_fetch(tdb, key) ctdb_test_tdb_fetch((tdb), (key))
+
+/* Implement these if they're ever used. */
+#define calloc ctdb_test_calloc
+#define select ctdb_test_select
+#define epoll_wait ctdb_test_epoll_wait
+#define epoll_ctl ctdb_test_epoll_ctl
+#define tdb_open ctdb_test_tdb_open
+
+static int ctdb_test_poll(struct pollfd *fds, nfds_t nfds, int timeout, const char *location);
+static void *ctdb_test_malloc(size_t size, const char *location);
+static void ctdb_test_free(void *ptr, const char *location);
+static void *ctdb_test_realloc(void *ptr, size_t size, const char *location);
+static ssize_t ctdb_test_read(int fd, void *buf, size_t count, const char *location);
+static ssize_t ctdb_test_write(int fd, const void *buf, size_t count, const char *location);
+static int ctdb_test_socket(int domain, int type, int protocol, const char *location);
+static int ctdb_test_connect(int sockfd, const struct sockaddr *addr,
+			     socklen_t addrlen, const char *location);
+static struct tdb_context *ctdb_test_tdb_open_ex(const char *name,
+						 int hash_size, int tdb_flags,
+						 int open_flags, mode_t mode,
+						 const struct tdb_logging_context *log_ctx,
+						 tdb_hash_func hash_fn, const char *location);
+static TDB_DATA ctdb_test_tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
+
+#include "../sync.c"
+#include "../control.c"
+#include "../ctdb.c"
+#include "../io_elem.c"
+#include "../local_tdb.c"
+#include "../logging.c"
+#include "../messages.c"
+
+#undef poll
+#undef malloc
+#undef realloc
+#undef read
+#undef write
+#undef socket
+#undef connect
+#undef tdb_open_ex
+#undef calloc
+#undef select
+#undef epoll_wait
+#undef epoll_ctl
+#undef tdb_open
+#undef tdb_fetch
+
+#include "ctdb-test.h"
+#include "utils.h"
+#include "tui.h"
+#include "log.h"
+#include "failtest.h"
+#include "expect.h"
+#include <err.h>
+
+/* Talloc contexts */
+void *allocations;
+void *working;
+
+static void run_inits(void)
+{
+	/* Linker magic creates these to delineate section. */
+	extern initcall_t __start_init_call[], __stop_init_call[];
+	initcall_t *p;
+
+	for (p = __start_init_call; p < __stop_init_call; p++)
+		(*p)();
+}
+
+static void print_license(void)
+{
+	printf("ctdb-test, Copyright (C) 2010 Jeremy Kerr, Rusty Russell\n"
+	       "ctdb-test comes with ABSOLUTELY NO WARRANTY; see COPYING.\n"
+	       "This is free software, and you are welcome to redistribute\n"
+	       "it under certain conditions; see COPYING for details.\n");
+}
+
+/*** XML Argument:
+    <section id="a:echo">
+     <title><option>--echo</option>, <option>-x</option></title>
+     <subtitle>Echo commands as they are executed</subtitle>
+     <para>ctdb-test will echo each command before it is executed. Useful when
+      commands are read from a file</para>
+    </section>
+*/
+static void cmdline_echo(struct option *opt)
+{
+	tui_echo_commands = 1;
+}
+cmdline_opt("echo", 0, 'x', cmdline_echo);
+
+/*** XML Argument:
+    <section id="a:quiet">
+     <title><option>--quiet</option>, <option>-q</option></title>
+     <subtitle>Run quietly</subtitle>
+     <para>Causes ctdb-test to reduce its output to the minimum possible - no prompt
+      is displayed, and most warning messages are suppressed
+     </para>
+    </section>
+*/
+static void cmdline_quiet(struct option *opt)
+{
+	tui_quiet = 1;
+}
+cmdline_opt("quiet", 0, 'q', cmdline_quiet);
+
+/*** XML Argument:
+    <section id="a:exit">
+     <title><option>--exit</option>, <option>-e</option></title>
+     <subtitle>Exit on error</subtitle>
+     <para>If <option>--exit</option> is specified, ctdb-test will exit (with a
+     non-zero error code) on the first script error it encounters (eg an
+     expect command does not match). This is the default when invoked as a
+     non-interactive script.</para>
+    </section>
+*/
+static void cmdline_abort_on_fail(struct option *opt)
+{
+	tui_abort_on_fail = 1;
+}
+cmdline_opt("exit", 0, 'e', cmdline_abort_on_fail);
+
+/*** XML Argument:
+    <section id="a:help">
+     <title><option>--help</option></title>
+     <subtitle>Print usage information</subtitle>
+     <para>Causes ctdb-test to print its command line arguments and then exit</para>
+    </section>
+*/
+static void cmdline_help(struct option *opt)
+{
+	print_license();
+	print_usage();
+	exit(EXIT_SUCCESS);
+}
+cmdline_opt("help", 0, 'h', cmdline_help);
+
+extern struct cmdline_option __start_cmdline[], __stop_cmdline[];
+
+static struct cmdline_option *get_cmdline_option(int opt)
+{
+	struct cmdline_option *copt;
+
+	/* if opt is < '0', we have been passed a long option, which is
+	 * indexed directly */
+	if (opt < '0')
+		return __start_cmdline + opt;
+
+	/* otherwise search for the short option in the .val member */
+	for (copt = __start_cmdline; copt < __stop_cmdline; copt++)
+		if (copt->opt.val == opt)
+			return copt;
+
+	return NULL;
+}
+
+static struct option *get_cmdline_options(void)
+{
+	struct cmdline_option *copts;
+	struct option *opts;
+	unsigned int x, n_opts;
+
+	n_opts = ((void *)__stop_cmdline - (void *)__start_cmdline) /
+		sizeof(struct cmdline_option);
+
+	opts = talloc_zero_array(NULL, struct option, n_opts + 1);
+	copts = __start_cmdline;
+
+	for (x = 0; x < n_opts; x++) {
+		unsigned int y;
+
+		if (copts[x].opt.has_arg > 2)
+			errx(1, "Bad argument `%s'", copts[x].opt.name);
+
+		for (y = 0; y < x; y++)
+			if ((copts[x].opt.val && copts[x].opt.val
+						== opts[y].val)
+					|| streq(copts[x].opt.name,
+						opts[y].name))
+				errx(1, "Conflicting arguments %s = %s\n",
+				     copts[x].opt.name, opts[y].name);
+
+		opts[x] = copts[x].opt;
+		opts[x].val = x;
+	}
+
+	return opts;
+}
+
+static char *get_cmdline_optstr(void)
+{
+	struct cmdline_option *copts;
+	unsigned int x, n_opts;
+	char *optstr, tmpstr[3], *colonstr = "::";
+
+	n_opts = ((void *)__stop_cmdline - (void *)__start_cmdline) /
+		sizeof(struct cmdline_option);
+
+	optstr = talloc_size(NULL, 3 * n_opts * sizeof(*optstr) + 1);
+	*optstr = '\0';
+
+	copts = __start_cmdline;
+
+	for (x = 0; x < n_opts; x++) {
+		if (!copts[x].opt.val)
+			continue;
+		snprintf(tmpstr, 4, "%c%s", copts[x].opt.val,
+			colonstr + 2 - copts[x].opt.has_arg);
+		strcat(optstr, tmpstr);
+	}
+	return optstr;
+}
+
+static int ctdb_test_poll(struct pollfd *fds, nfds_t nfds, int timeout,
+			  const char *location)
+{
+	if (should_i_fail("poll", location)) {
+		errno = EINVAL;
+		return -1;
+	}
+	return poll(fds, nfds, timeout);
+}
+
+static void *ctdb_test_malloc(size_t size, const char *location)
+{
+	if (should_i_fail("malloc", location)) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	return talloc_named_const(allocations, size, location);
+}
+
+static void ctdb_test_free(void *ptr, const char *location)
+{
+	talloc_free(ptr);
+}
+
+static void *ctdb_test_realloc(void *ptr, size_t size, const char *location)
+{
+	if (should_i_fail("realloc", location)) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	ptr = _talloc_realloc(allocations, ptr, size, location);
+	if (ptr)
+		talloc_set_name(ptr, "%s (reallocated to %u at %s)",
+				talloc_get_name(ptr), size, location);
+	return ptr;
+}
+
+static ssize_t ctdb_test_read(int fd, void *buf, size_t count,
+			      const char *location)
+{
+	if (should_i_fail("read", location)) {
+		errno = EBADF;
+		return -1;
+	}
+	/* FIXME: We only let parent read and write.
+	 * We should have child do short read, at least until whole packet is
+	 * read.  Then we terminate child. */
+	if (!am_parent()) {
+		log_line(LOG_DEBUG, "Child reading fd");
+		return 0;
+	}
+	return read(fd, buf, count);
+}
+
+static ssize_t ctdb_test_write(int fd, const void *buf, size_t count,
+			       const char *location)
+{
+	if (should_i_fail("write", location)) {
+		errno = EBADF;
+		return -1;
+	}
+	/* FIXME: We only let parent read and write.
+	 * We should have child do short write, at least until whole packet is
+	 * written, then terminate child.  Check that all children and parent
+	 * write the same data. */
+	if (!am_parent()) {
+		log_line(LOG_DEBUG, "Child writing fd");
+		return 0;
+	}
+	return write(fd, buf, count);
+}
+
+static int ctdb_test_socket(int domain, int type, int protocol,
+			    const char *location)
+{
+	if (should_i_fail("socket", location)) {
+		errno = EINVAL;
+		return -1;
+	}
+	return socket(domain, type, protocol);
+}
+
+static int ctdb_test_connect(int sockfd, const struct sockaddr *addr,
+			     socklen_t addrlen, const char *location)
+{
+	if (should_i_fail("connect", location)) {
+		errno = EINVAL;
+		return -1;
+	}
+	return connect(sockfd, addr, addrlen);
+}
+
+static struct tdb_context *ctdb_test_tdb_open_ex(const char *name,
+						 int hash_size, int tdb_flags,
+						 int open_flags, mode_t mode,
+						 const struct tdb_logging_context *log_ctx,
+						 tdb_hash_func hash_fn,
+						 const char *location)
+{
+	if (should_i_fail("tdb_open_ex", location)) {
+		errno = ENOENT;
+		return NULL;
+	}
+	return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode,
+			   log_ctx, hash_fn);
+}
+
+/* We don't need to fail this, but as library expects to be able to free()
+   dptr, we need to make sure it's talloced (see ctdb_test_free) */
+static TDB_DATA ctdb_test_tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
+{
+	TDB_DATA ret = tdb_fetch(tdb, key);
+	if (ret.dptr) {
+		ret.dptr = talloc_memdup(allocations, ret.dptr, ret.dsize);
+		if (!ret.dptr) {
+			err(1, "Could not memdup %zu bytes", ret.dsize);
+		}
+	}
+	return ret;
+}
+
+void check_allocations(void)
+{
+	talloc_free(working);
+
+	if (talloc_total_blocks(allocations) != 1) {
+		log_line(LOG_ALWAYS, "Resource leak:");
+		talloc_report_full(allocations, stdout);
+		exit(1);
+	}
+}
+
+/* This version adds one byte (for nul term) */
+void *grab_fd(int fd, size_t *size)
+{
+	size_t max = 16384;
+	int ret;
+	void *buffer = talloc_array(NULL, char, max+1);
+
+	*size = 0;
+	while ((ret = read(fd, buffer + *size, max - *size)) > 0) {
+		*size += ret;
+		if (*size == max)
+			buffer = talloc_realloc(NULL, buffer, char, max *= 2 + 1);
+	}
+	if (ret < 0) {
+		talloc_free(buffer);
+		buffer = NULL;
+	}
+	return buffer;
+}
+
+int main(int argc, char *argv[])
+{
+	int input_fd, c;
+	const char *optstr;
+	struct option *options;
+
+	allocations = talloc_named_const(NULL, 1, "ctdb-test");
+	working = talloc_named_const(NULL, 1, "ctdb-test-working");
+
+	options = get_cmdline_options();
+	optstr = get_cmdline_optstr();
+
+	while ((c = getopt_long(argc, argv, optstr, options, NULL)) != EOF) {
+		struct cmdline_option *copt = get_cmdline_option(c);
+		if (!copt)
+			errx(1, "Unknown argument");
+
+		copt->parse(&copt->opt);
+	}
+
+	if (optind == argc) {
+		log_line(LOG_DEBUG, "Disabling failtest due to stdin.");
+		failtest = false;
+		input_fd = STDIN_FILENO;
+	} else if (optind + 1 != argc)
+		errx(1, "Need a single argument: input filename");
+	else {
+		input_fd = open(argv[optind], O_RDONLY);
+		if (input_fd < 0)
+			err(1, "Opening %s", argv[optind]);
+		tui_abort_on_fail = true;
+	}
+
+	run_inits();
+	if (!tui_quiet)
+		print_license();
+
+	log_line(LOG_VERBOSE, "initialisation done");
+
+	tui_run(input_fd);
+
+	/* Everyone loves a good error haiku! */
+	if (expects_remaining())
+		errx(1, "Expectations still / "
+		     "unfulfilled remaining. / "
+		     "Testing blossoms fail.");
+	check_allocations();
+	check_databases();
+	dump_failinfo();
+
+	return EXIT_SUCCESS;
+}

Added: branches/ctdb/squeeze-backports/libctdb/test/ctdb-test.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/ctdb-test.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/ctdb-test.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,28 @@
+#ifndef __HAVE_CTDB_TEST_H
+#define __HAVE_CTDB_TEST_H
+#include <stdlib.h>
+
+/* We hang all libctdb allocations off this talloc tree. */
+extern void *allocations;
+
+void check_allocations(void);
+
+/* Our own working state gets hung off this tree. */
+extern void *working;
+
+/* The ctdb connection; created by 'connect' command. */
+struct ctdb_connection *get_ctdb(void);
+
+/* Talloc bytes from an fd until EOF.  Nul terminate. */
+void *grab_fd(int fd, size_t *size);
+
+/* Check the databases are still ok. */
+void check_databases(void);
+
+/* Save and restore databases, in case children do damage. */
+void *save_databases(void);
+void restore_databases(void *);
+
+struct ctdb_db *find_db_by_id(unsigned int id);
+
+#endif /* __HAVE_CTDB_TEST_H */

Added: branches/ctdb/squeeze-backports/libctdb/test/databases.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/databases.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/databases.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,134 @@
+/*
+   database code for libctdb
+
+   Copyright (C) Rusty Russell 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <unistd.h>
+#include <err.h>
+#include <talloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include "utils.h"
+#include "log.h"
+#include "ctdb-test.h"
+#include <tdb.h>
+#include <ctdb_protocol.h>
+
+/* FIXME */
+#define DB_PATH "/tmp/ctdbd-test/dbs/"
+
+static int check_header(TDB_DATA key, TDB_DATA data, void *unused)
+{
+	struct ctdb_ltdb_header *hdr = (void *)data.dptr;
+	if (data.dsize < sizeof(*hdr)) {
+		log_line(LOG_ALWAYS, "tdb entry '%.*s' is truncated",
+			 key.dsize, key.dptr);
+		return -1;
+	}
+	/* Currently a single-node cluster. */
+	if (hdr->dmaster != 0) {
+		log_line(LOG_ALWAYS, "tdb entry '%.*s' dmaster %u",
+			 key.dsize, key.dptr, hdr->dmaster);
+		return -1;
+	}
+	/* Currently a single-node cluster. */
+	if (hdr->laccessor != 0) {
+		log_line(LOG_ALWAYS, "tdb entry '%.*s' laccessor %u",
+			 key.dsize, key.dptr, hdr->laccessor);
+		return -1;
+	}
+	return 0;
+}
+
+static void check_database(const char *name)
+{
+	struct tdb_context *tdb = tdb_open(name, 0, TDB_DEFAULT, O_RDWR, 0);
+	if (!tdb)
+		err(1, "Opening tdb %s", name);
+
+	if (tdb_check(tdb, check_header, NULL) != 0) {
+		log_line(LOG_ALWAYS, "tdb %s is corrupt", name);
+		exit(EXIT_FAILURE);
+	}
+	tdb_close(tdb);
+}
+
+void check_databases(void)
+{
+	struct dirent *ent;
+	DIR *d = opendir(DB_PATH);
+	if (!d)
+		err(1, "Reading directory %s", DB_PATH);
+
+	while ((ent = readdir(d)) != NULL) {
+		if (strends(ent->d_name, ".tdb.0")) {
+			char *fullpath = talloc_asprintf(NULL, "%s/%s",
+							 DB_PATH, ent->d_name);
+			check_database(fullpath);
+			talloc_free(fullpath);
+		}
+	}
+	closedir(d);
+}
+
+/* FIXME: We assume we don't need locks here.  Not a solid assumption! */
+void *save_databases(void)
+{
+	struct tdb_context *tdb = tdb_open(NULL, 0, TDB_INTERNAL, 0, 0);
+	struct dirent *ent;
+	DIR *d = opendir(DB_PATH);
+	if (!d)
+		err(1, "Reading directory %s", DB_PATH);
+
+	while ((ent = readdir(d)) != NULL) {
+		if (strends(ent->d_name, ".tdb.0")) {
+			TDB_DATA data, key;
+			int fd;
+			char *fullpath = talloc_asprintf(NULL, "%s/%s",
+							 DB_PATH, ent->d_name);
+			fd = open(fullpath, O_RDONLY);
+			if (fd < 0)
+				err(1, "Saving tdb %s", fullpath);
+			data.dptr = grab_fd(fd, &data.dsize);
+			key.dptr = (void *)fullpath;
+			key.dsize = strlen(fullpath) + 1;
+			tdb_store(tdb, key, data, TDB_INSERT);
+			talloc_free(fullpath);
+			close(fd);
+		}
+	}
+	closedir(d);
+	return tdb;
+}
+
+void restore_databases(void *_tdb)
+{
+	struct tdb_context *tdb = _tdb;
+	TDB_DATA key, data;
+
+	for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) {
+		int fd = open((char *)key.dptr, O_WRONLY);
+		if (fd < 0)
+			err(1, "Restoring tdb %s", (char *)key.dptr);
+		data = tdb_fetch(tdb, key);
+		write(fd, data.dptr, data.dsize);
+		free(data.dptr);
+		close(fd);
+	}
+	tdb_close(tdb);
+}

Added: branches/ctdb/squeeze-backports/libctdb/test/expect.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/expect.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/expect.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,300 @@
+/*
+
+This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
+
+Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
+
+This file is part of nfsim.
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "tui.h"
+#include "log.h"
+#include "expect.h"
+#include <fnmatch.h>
+#include <talloc.h>
+#include "utils.h"
+
+/* Expect is used to set up expectations on logging, for automated
+ * testing. */
+struct expect {
+	struct expect *next;
+	int invert;
+	int matched;
+	char *command;
+	char *pattern;
+};
+
+static struct expect *expect;
+struct cmdstack
+{
+	struct cmdstack *prev;
+	char *command;
+};
+static struct cmdstack *current_command;
+
+/* We don't need to try to match every pattern length: we only need
+ * lengths where the next char matches. */
+static unsigned int maybe_skip(char next_char, const char *line)
+{
+	char str[2];
+
+	/* If next one is *, we can't skip any. */
+	if (next_char == '*')
+		return 1;
+
+	/* No more string? */
+	if (*line == '\0')
+		return 1;
+
+	/* Next one is space, skip up to next space. */
+	if (next_char == '\t' || next_char == ' ')
+		return strcspn(line+1, "\t ") + 1;
+
+	str[0] = next_char;
+	str[1] = '\0';
+	return strcspn(line+1, str) + 1;
+}
+
+/* Loose match for strings: whitespace can be any number of
+ * whitespace, and * matches anything.  Approximately. */
+static bool loose_match(const char *pattern, const char *line)
+{
+	/* Any whitespace in pattern matches any whitespace in line. */
+	if (*pattern == '\t' || *pattern == ' ') {
+		int i, j, pat_space, line_space;
+
+		pat_space = strspn(pattern, "\t ");
+		line_space = strspn(line, "\t ");
+
+		for (i = 1; i <= pat_space; i++)
+			for (j = 1; j <= line_space; j++)
+				if (loose_match(pattern+i, line+j))
+					return true;
+		return false;
+	}
+
+	if (*pattern == '*') {
+		int i, len = strlen(line);
+		for (i = 0; i <= len; i += maybe_skip(pattern[1],line+i))
+			if (loose_match(pattern+1, line+i))
+				return true;
+
+		return false;
+	}
+
+	if (*pattern == *line) {
+		if (*pattern == '\0')
+			return true;
+		return loose_match(pattern+1, line+1);
+	}
+
+	return false;
+}
+
+/* Pattern can't have whitespace at start and end, due to our parser.
+ * Strip ot here. */
+static bool matches(const char *pattern, const char *line)
+{
+	unsigned int len;
+
+	line += strspn(line, "\t ");
+	len = strlen(line);
+	if (len > 0 && (line[len-1] == '\t' || line[len-1] == ' ')) {
+		char trimmed[len];
+		memcpy(trimmed, line, len);
+		while (trimmed[len-1] == '\t' || trimmed[len-1] == ' ') {
+			if (len == 1)
+				break;
+			len--;
+		}
+		trimmed[len] = '\0';
+		return loose_match(pattern, trimmed);
+	}
+	return loose_match(pattern, line);
+}
+
+bool expect_log_hook(const char *line)
+{
+	struct expect *e;
+	bool ret = false;
+
+	if (current_command == NULL)
+		return false;
+
+	/* Only allow each pattern to match once, so we can easily
+	 * expect something to happen twice. */
+	for (e = expect; e; e = e->next) {
+		if (!e->matched
+		    && streq(current_command->command, e->command)
+		    && matches(e->pattern, line)) {
+			e->matched = 1;
+			ret = true;
+		}
+	}
+	return ret;
+}
+
+bool expects_remaining(void)
+{
+	return expect != NULL;
+}
+
+static void expect_pre_command(const char *command)
+{
+	struct cmdstack *new = talloc(NULL, struct cmdstack);
+	new->prev = current_command;
+	new->command = talloc_strdup(new, command);
+	current_command = new;
+}
+
+static bool expect_post_command(const char *command)
+{
+	struct expect **e, **next, *old;
+	bool ret = true;
+	struct cmdstack *oldcmd;
+
+	for (e = &expect; *e; e = next) {
+		next = &(*e)->next;
+
+		if (!streq(current_command->command, (*e)->command))
+			continue;
+
+		if (!(*e)->invert && !(*e)->matched) {
+			if (tui_abort_on_fail)
+				script_fail("Pattern '%s' did not match",
+					    (*e)->pattern);
+			log_line(LOG_VERBOSE, "Pattern '%s' did not match",
+				 (*e)->pattern);
+			ret = false;
+		} else if ((*e)->invert && (*e)->matched) {
+			if (tui_abort_on_fail)
+				script_fail("Pattern '%s' matched",
+					    (*e)->pattern);
+			log_line(LOG_VERBOSE, "Pattern '%s' matched",
+				 (*e)->pattern);
+			ret = false;
+		}
+
+		/* Unlink from list and free. */
+		old = *e;
+		*e = (*e)->next;
+		next = e;
+
+		talloc_free(old);
+	}
+
+	oldcmd = current_command;
+	current_command = current_command->prev;
+	talloc_free(oldcmd);
+	return ret;
+}
+
+static bool expect_cmd(int argc, char **argv)
+{
+	struct expect *e;
+	unsigned int i, len;
+	bool invert = false;
+
+	if (argc == 1) {
+		for (e = expect; e; e = e->next)
+			log_line(LOG_UI, "%s: %s\"%s\"",
+				 e->command,
+				 e->invert ? "! " : "",
+				 e->pattern);
+		return true;
+	}
+
+	if (argv[1] && streq(argv[1], "!")) {
+		invert = true;
+		argv++;
+		argc--;
+	}
+
+	if (argc < 3)
+		return false;
+
+	if (!tui_is_command(argv[1])) {
+		log_line(LOG_ALWAYS, "expect: %s is not a command\n",
+			 argv[1]);
+		return false;
+	}
+
+	e = talloc(NULL, struct expect);
+	e->matched = 0;
+	e->invert = invert;
+	e->next = expect;
+
+	e->command = talloc_strdup(e, argv[1]);
+
+	for (len = 0, i = 2; i < argc; i++)
+		len += strlen(argv[i])+1;
+	e->pattern = talloc_array(e, char, len + 1);
+
+	e->pattern[0] = '\0';
+	for (i = 2; i < argc; i++) {
+		if (i == 2)
+			sprintf(e->pattern+strlen(e->pattern), "%s", argv[i]);
+		else
+			sprintf(e->pattern+strlen(e->pattern), " %s", argv[i]);
+	}
+	expect = e;
+	return true;
+}
+
+static void expect_help(int argc, char **argv)
+{
+#include "generated-expect-help:expect"
+/*** XML Help:
+    <section id="c:expect">
+     <title><command>expect</command></title>
+     <para>Catch logging information for automated testing</para>
+     <cmdsynopsis>
+      <command>expect</command>
+     </cmdsynopsis>
+     <cmdsynopsis>
+      <command>expect</command>
+      <arg choice="opt">!</arg>
+      <arg choice="req"><replaceable>command</replaceable></arg>
+      <arg choice="req"><replaceable>pattern</replaceable></arg>
+     </cmdsynopsis>
+     <para><command>expect</command> will set up a set of patterns to expect in
+      logging messages for a particular command. If that command finishes
+      without matching the specified pattern, the simulator will exit with a
+      non-zero return value.  After the command is run, all expectations on that
+      command are deleted.</para>
+     <para><command>expect</command> with no arguments will print out the
+      current list of expectations, as a command and a pattern.</para>
+     <para><command>expect <replaceable>command pattern</replaceable></command>
+      will expect the specified pattern to occur the next time
+      <replaceable>command</replaceable> is invoked. If an '!' appears before
+      the command, then the expectation is negated - if the pattern appears in
+      the output, then the simulator will exit with an error
+     </para>
+     <para>The pattern itself is similar to a simple shell wildcard,
+      except whitespace is loosely matched.  The * character will
+      match any a string of any length.</para>
+     </section>
+*/
+}
+
+static void init(void)
+{
+	tui_register_command("expect", expect_cmd, expect_help);
+	tui_register_pre_post_hook(expect_pre_command, expect_post_command);
+}
+
+init_call(init);

Added: branches/ctdb/squeeze-backports/libctdb/test/expect.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/expect.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/expect.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,35 @@
+/*
+
+This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
+
+Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
+
+This file is part of nfsim.
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef __HAVE_EXPECT_H
+#define __HAVE_EXPECT_H
+
+/* Expect interface */
+void expect_before_command(const char *command);
+bool expect_log_hook(const char *line);
+void expect_after_command(void);
+
+/* Are there any expect commands unresolved? */
+bool expects_remaining(void);
+
+#endif /* __HAVE_EXPECT_H */

Added: branches/ctdb/squeeze-backports/libctdb/test/failtest.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/failtest.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/failtest.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,344 @@
+/*
+
+This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
+
+Copyright (c) 2004 Jeremy Kerr & Rusty Russell
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include "utils.h"
+#include "tui.h"
+#include "log.h"
+#include "failtest.h"
+#include "ctdb-test.h"
+#include "talloc.h"
+#include "dlinklist.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <getopt.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+static unsigned int fails = 0, excessive_fails = 2;
+unsigned int failpoints = 0;
+static const char *failtest_no_report = NULL;
+bool failtest = true;
+
+struct fail_decision {
+	struct fail_decision *next, *prev;
+	char *location;
+	unsigned int tui_line;
+	bool failed;
+};
+
+static struct fail_decision *decisions;
+
+/* Failure path to follow (initialized by --failpath). */
+static const char *failpath = NULL, *orig_failpath;
+
+/*** XML Argument:
+    <section id="a:failpath">
+     <title><option>--failpath
+      <replaceable>path</replaceable></option></title>
+     <subtitle>Replay a failure path</subtitle>
+     <para>Given a failure path, (from <option>--failtest</option>), this will
+      replay the sequence of sucesses/failures, allowing debugging.  The input
+      should be the same as the original which caused the failure.
+      </para>
+
+     <para>This testing can be slow, but allows for testing of failure
+      paths which would otherwise be very difficult to test
+     automatically.</para>
+    </section>
+*/
+static void cmdline_failpath(struct option *opt)
+{
+	extern char *optarg;
+	if (!optarg)
+		errx(1, "failtest option requires an argument");
+	orig_failpath = failpath = optarg;
+}
+cmdline_opt("failpath", 1, 0, cmdline_failpath);
+
+/*** XML Argument:
+    <section id="a:failtest-no-report">
+     <title><option>--failtest-no-report
+      <replaceable>function</replaceable></option></title>
+     <subtitle>Exclude a function from excessive failure reports</subtitle>
+
+     <para>Sometimes code deliberately ignores the failures of a
+     certain function.  This suppresses complaints about that for any
+     functions containing this name.</para> </section>
+*/
+static void cmdline_failtest_no_report(struct option *opt)
+{
+	extern char *optarg;
+	if (!optarg)
+		errx(1, "failtest-no-report option requires an argument");
+	failtest_no_report = optarg;
+}
+cmdline_opt("failtest-no-report", 1, 0, cmdline_failtest_no_report);
+
+/*** XML Argument:
+    <section id="a:no-failtest">
+     <title><option>--no-failtest</option></title>
+     <subtitle>Don't test failure cases</subtitle>
+
+     <para>This is the default in interactive mode.</para>
+    </section>
+*/
+static void cmdline_no_failtest(struct option *opt)
+{
+	failtest = false;
+}
+cmdline_opt("no-failtest", 0, 0, cmdline_no_failtest);
+
+/* Separate function to make .gdbinit easier */
+static bool failpath_fail(void)
+{
+	return true;
+}
+
+static bool do_failpath(const char *func)
+{
+	if (*failpath == '[') {
+		failpath++;
+		if (strncmp(failpath, func, strlen(func)) != 0
+		    || failpath[strlen(func)] != ']')
+			errx(1, "Failpath expected %.*s not %s\n",
+			     strcspn(failpath, "]"), failpath, func);
+		failpath += strlen(func) + 1;
+	}
+
+	if (*failpath == ':') {
+		unsigned long line;
+		char *after;
+		failpath++;
+		line = strtoul(failpath, &after, 10);
+		if (*after != ':')
+			errx(1, "Bad failure path line number %s\n",
+			     failpath);
+		if (line != tui_linenum)
+			errx(1, "Unexpected line number %lu vs %u\n",
+			     line, tui_linenum);
+		failpath = after+1;
+	}
+
+	switch ((failpath++)[0]) {
+	case 'F':
+	case 'f':
+		return failpath_fail();
+	case 'S':
+	case 's':
+		return false;
+	case 0:
+		failpath = NULL;
+		return false;
+	default:
+		errx(1, "Failpath '%c' failed to path",
+		     failpath[-1]);
+	}
+}
+
+static char *failpath_string_for_line(struct fail_decision *dec)
+{
+	char *ret = NULL;
+	struct fail_decision *i;
+
+	for (i = decisions; i; i = i->next) {
+		if (i->tui_line != dec->tui_line)
+			continue;
+		ret = talloc_asprintf_append(ret, "[%s]%c",
+					     i->location,
+					     i->failed ? 'F' : 'S');
+	}
+	return ret;
+}
+
+static char *failpath_string(void)
+{
+	char *ret = NULL;
+	struct fail_decision *i;
+
+	for (i = decisions; i; i = i->next)
+		ret = talloc_asprintf_append(ret, "[%s]:%i:%c",
+					     i->location, i->tui_line,
+					     i->failed ? 'F' : 'S');
+	return ret;
+}
+
+static void warn_failure(void)
+{
+	char *warning;
+	struct fail_decision *i;
+	int last_warning = 0;
+
+	log_line(LOG_ALWAYS, "WARNING: test ignores failures at %s",
+		 failpath_string());
+
+	for (i = decisions; i; i = i->next) {
+		if (i->failed && i->tui_line > last_warning) {
+			warning = failpath_string_for_line(i);
+			log_line(LOG_ALWAYS, " Line %i: %s",
+				 i->tui_line, warning);
+			talloc_free(warning);
+			last_warning = i->tui_line;
+		}
+	}
+}
+
+bool am_parent(void)
+{
+	struct fail_decision *i;
+
+	for (i = decisions; i; i = i->next) {
+		if (i->failed)
+			return false;
+	}
+	return true;
+}
+
+static char *make_location(const char *func, const char *caller)
+{
+	const char *afterslash;
+
+	afterslash = strrchr(caller, '/');
+	if (afterslash)
+		afterslash++;
+	else
+		afterslash = caller;
+	return talloc_asprintf(working, "%s(%s)", func, afterslash);
+}
+
+/* Should I fail at this point?  Once only: it would be too expensive
+ * to fail at every possible call. */
+bool should_i_fail_once(const char *func, const char *caller)
+{
+	char *p, *location = make_location(func, caller);
+	struct fail_decision *i;
+
+	if (failpath) {
+		p = strstr(orig_failpath ?: "", location);
+		if (p && p <= failpath
+		    && p[-1] == '[' && p[strlen(location)] == ']')
+			return false;
+
+		return do_failpath(location);
+	}
+
+	for (i = decisions; i; i = i->next)
+		if (streq(location, i->location))
+			return false;
+
+	if (should_i_fail(func, caller)) {
+		excessive_fails++;
+		return true;
+	}
+	return false;
+}
+
+/* Should I fail at this point? */
+bool should_i_fail(const char *func, const char *caller)
+{
+	pid_t child;
+	int status, pfd[2];
+	struct fail_decision *dec;
+	size_t log_size;
+	char *log;
+	char *location = make_location(func, caller);
+	void *databases;
+
+	if (failpath)
+		return do_failpath(location);
+
+	failpoints++;
+	if (!failtest)
+		return false;
+
+	/* If a testcase ignores a spuriously-inserted failure, it's
+	 * not specific enough, and we risk doing 2^n tests! */
+	if (fails > excessive_fails) {
+		static bool warned = false;
+		if (!warned++)
+			warn_failure();
+	}
+
+	dec = talloc(NULL, struct fail_decision);
+	dec->location = talloc_steal(dec, location);
+	dec->tui_line = tui_linenum;
+
+	DLIST_ADD_END(decisions, dec, struct fail_decision);
+
+	if (pipe(pfd) != 0)
+		err(1, "pipe failed for failtest!");
+
+	databases = save_databases();
+
+	fflush(stdout);
+	child = fork();
+	if (child == -1)
+		err(1, "fork failed for failtest!");
+
+	/* The child actually fails.  The script will screw up at this
+	 * point, but should not crash. */
+	if (child == 0) {
+		/* Log to parent (including stderr if things go really bad). */
+		close(pfd[0]);
+		dup2(pfd[1], STDOUT_FILENO);
+		dup2(pfd[1], STDERR_FILENO);
+		dec->failed = true;
+		if (!failtest_no_report || !strstr(func, failtest_no_report))
+			fails++;
+		return true;
+	}
+
+	dec->failed = false;
+
+	close(pfd[1]);
+	log = grab_fd(pfd[0], &log_size);
+
+	while (waitpid(child, &status, 0) < 0) {
+		if (errno != EINTR)
+			err(1, "failtest waitpid failed for child %i",
+			    (int)child);
+	}
+
+	/* If child succeeded, or mere script failure, continue. */
+	if (WIFEXITED(status) && (WEXITSTATUS(status) == EXIT_SUCCESS
+				  || WEXITSTATUS(status) == EXIT_SCRIPTFAIL)) {
+		talloc_free(log);
+		restore_databases(databases);
+		return false;
+	}
+
+	/* Reproduce child's path: leave databases for post-mortem. */
+	dec->failed = true;
+
+	log_line(LOG_ALWAYS, "Child %s %i on failure path: %s",
+		 WIFEXITED(status) ? "exited" : "signalled",
+		 WIFEXITED(status) ? WEXITSTATUS(status)
+		 : WTERMSIG(status), failpath_string());
+	log_line(LOG_ALWAYS, "Child output:\n%s", log);
+	exit(EXIT_FAILURE);
+}
+
+void dump_failinfo(void)
+{
+	log_line(LOG_VERBOSE, "Hit %u failpoints: %s",
+		 failpoints, failpath_string());
+}

Added: branches/ctdb/squeeze-backports/libctdb/test/failtest.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/failtest.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/failtest.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#ifndef FAILTEST_H
+#define FAILTEST_H
+#include <stdbool.h>
+
+bool should_i_fail_once(const char *func, const char *caller);
+bool should_i_fail(const char *func, const char *caller);
+
+bool failtest;
+
+/* Parent never has artificial failures. */
+bool am_parent(void);
+
+void dump_failinfo(void);
+
+#endif /* FAILTEST_H */

Added: branches/ctdb/squeeze-backports/libctdb/test/log.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/log.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/log.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,233 @@
+/*
+
+This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
+
+Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
+
+This file is part of nfsim.
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include "log.h"
+#include "tui.h"
+#include "utils.h"
+#include "expect.h"
+#include <string.h>
+#include <talloc.h>
+#include <err.h>
+
+static struct {
+	enum log_type	type;
+	char *		name;
+} log_names[] = {
+	{ LOG_WRITE,	"write" },
+	{ LOG_READ,	"read" },
+	{ LOG_LIB,	"lib" },
+	{ LOG_VERBOSE,	"verbose" },
+};
+
+static int typemask = ~LOG_VERBOSE;
+
+bool log_line(enum log_type type, const char *format, ...)
+{
+	va_list ap;
+	char *line;
+	bool ret;
+
+	va_start(ap, format);
+	line = talloc_vasprintf(NULL, format, ap);
+	va_end(ap);
+
+	if (!type || (type & typemask)) {
+		printf("%s\n", line);
+		fflush(stdout);
+	}
+
+	ret = expect_log_hook(line);
+	talloc_free(line);
+	return ret;
+}
+
+static void log_partial_v(enum log_type type,
+			  char *buf,
+			  unsigned bufsize,
+			  const char *format,
+			  va_list ap)
+{
+	char *ptr;
+	int len = strlen(buf);
+
+	/* write to the end of buffer */
+	if (vsnprintf(buf + len, bufsize - len - 1, format, ap)
+	    > bufsize - len - 1) {
+		errx(1, "log_line_partial buffer is full!");
+	}
+
+	ptr = buf;
+
+	/* print each bit that ends in a newline */
+	for (len = strcspn(ptr, "\n"); *(ptr + len);
+			ptr += len, len = strcspn(ptr, "\n")) {
+		log_line(type, "%.*s", len++, ptr);
+	}
+
+	/* if we've printed, copy any remaining (non-newlined)
+	   parts (including the \0) to the front of buf */
+	memmove(buf, ptr, strlen(ptr) + 1);
+}
+
+void log_partial(enum log_type type, char *buf, unsigned bufsize,
+		 const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	log_partial_v(type, buf, bufsize, format, ap);
+	va_end(ap);
+}
+
+static inline int parsetype(const char *type)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(log_names); i++)
+		if (streq(log_names[i].name, type))
+			return log_names[i].type;
+
+	return 0;
+}
+
+static bool log_admin(int argc, char **argv)
+{
+	int i;
+	int newtypemask = 0;
+
+	if (argc == 1) {
+		log_line(LOG_UI, "current log types:", typemask);
+
+		for (i = 0; i < ARRAY_SIZE(log_names); i++) {
+			if (typemask & log_names[i].type)
+				log_line(LOG_UI, "\t%s", log_names[i].name);
+		}
+		return true;
+	}
+
+	if (argc == 2) {
+		log_line(LOG_ALWAYS, "Expected =, + or - then args");
+		return false;
+	}
+
+	for (i = 2; i < argc; i++) {
+		int type;
+
+		if (!(type = parsetype(argv[i]))) {
+			log_line(LOG_ALWAYS, "no such type %s", argv[i]);
+			return false;
+		}
+		newtypemask |= type;
+	}
+
+	switch (*argv[1]) {
+	case '=':
+		typemask = newtypemask;
+		break;
+	case '-':
+		typemask &= ~newtypemask;
+		break;
+	case '+':
+		typemask |= newtypemask;
+		break;
+	default:
+		log_line(LOG_ALWAYS, "unknown modifer: %c", *argv[1]);
+		return false;
+	}
+
+	return true;
+}
+
+static void log_admin_help(int agc, char **argv)
+{
+#include "generated-log-help:log"
+/*** XML Help:
+    <section id="c:log">
+     <title><command>log</command></title>
+     <para>Manage logging settings</para>
+     <cmdsynopsis>
+      <command>log</command>
+      <group choice="opt">
+       <arg choice="plain">=</arg>
+       <arg choice="plain">+</arg>
+       <arg choice="plain">-</arg>
+      </group>
+      <arg choice="req"><replaceable>type, ...</replaceable></arg>
+     </cmdsynopsis>
+     <para>Each log message is classified into one of the following
+     types:</para>
+      <varlistentry>
+       <term>UI</term>
+       <listitem>
+        <para>Normal response from command lines.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>LIB</term>
+       <listitem>
+        <para>Logging output from libctdb</para>
+       </listitem>
+      </varlistentry>
+     <variablelist>
+      <varlistentry>
+       <term>READ</term>
+       <listitem>
+        <para>Messages from ctdbd</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>WRITE</term>
+       <listitem>
+        <para>Messages to ctdbd</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>VERBOSE</term>
+       <listitem>
+        <para>Verbose debug output</para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+
+     <para>The <command>log</command> command allows you to select
+      which messages are displayed. By default, all messages except
+      debug will be shown.</para>
+
+     <para>Without any arguments, the current logged types are listed.</para>
+
+     <para>With +, - or = character, those types will be added,
+      removed or set as the current types of messages to be logged
+      (repectively).</para>
+
+      <para>Messages generated as a result of user input are always
+      logged.  </para> </section>
+*/
+}
+
+static void log_init(void)
+{
+	if (tui_quiet)
+		typemask = 0;
+	tui_register_command("log", log_admin, log_admin_help);
+}
+
+init_call(log_init);

Added: branches/ctdb/squeeze-backports/libctdb/test/log.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/log.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/log.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,47 @@
+/*
+
+This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
+
+Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
+
+This file is part of nfsim.
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef __HAVE_LOG_H
+#define __HAVE_LOG_H
+#include <stdbool.h>
+
+enum log_type {
+	LOG_ALWAYS	= 0x00,
+	/* Packets that are written to ctdbd. */
+	LOG_WRITE	= 0x02,
+	/* Packets that are read from ctdbd. */
+	LOG_READ	= 0x04,
+	/* Logging from libctdb. */
+	LOG_LIB		= 0x08,
+	/* Logging from normal operations. */
+	LOG_UI		= 0x10,
+	/* Verbose debugging. */
+	LOG_VERBOSE	= 0x20,
+};
+
+/* Adds a \n for convenient logging.  Returns true if it was expected. */
+bool log_line(enum log_type type, const char *format, ...);
+/* Builds up buffer and prints out line at a time. */
+void log_partial(enum log_type type, char *buf, unsigned bufsize,
+		 const char *format, ...);
+#endif /* __HAVE_LOG_H */

Added: branches/ctdb/squeeze-backports/libctdb/test/readrecordlock.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/readrecordlock.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/readrecordlock.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,197 @@
+#include "utils.h"
+#include "log.h"
+#include "tui.h"
+#include "ctdb-test.h"
+#include <ctdb.h>
+#include <tdb.h>
+#include <talloc.h>
+#include <dlinklist.h>
+#include <errno.h>
+
+struct lock {
+	struct lock *next, *prev;
+	struct ctdb_db *db;
+	struct ctdb_lock *lock;
+	unsigned int id;
+};
+
+static unsigned int lock_id;
+static struct lock *locks;
+
+static void readrecordlock_help(int argc, char **argv)
+{
+#include "generated-readrecordlock-help:readrecordlock"
+/*** XML Help:
+    <section id="c:readrecordlock">
+     <title><command>readrecordlock</command></title>
+     <para>Read and lock a record in a ctdb database</para>
+     <cmdsynopsis>
+      <command>readrecordlock</command>
+      <arg choice="req"><replaceable>db-id</replaceable></arg>
+      <arg choice="req"><replaceable>key</replaceable></arg>
+     </cmdsynopsis>
+
+     <para>Read and lock a record.  Prints the record, and a 1-based
+     sequential handle on success, which should be handed to
+     <command>releaselock</command>
+     </para>
+     </section>
+*/
+}
+
+static void releaselock_help(int argc, char **argv)
+{
+#include "generated-readrecordlock-help:releaselock"
+/*** XML Help:
+    <section id="c:releaselock">
+     <title><command>releaselock</command></title>
+     <para>Unlock a record in a ctdb database</para>
+     <cmdsynopsis>
+      <command>releaselock</command>
+      <arg choice="req"><replaceable>db-id</replaceable></arg>
+      <arg choice="req"><replaceable>lock-id</replaceable></arg>
+     </cmdsynopsis>
+
+     <para>Unlock a record successfully locked by
+     <command>readrecordlock</command>.  </para>
+
+     </section>
+*/
+}
+
+static void writerecord_help(int argc, char **argv)
+{
+#include "generated-readrecordlock-help:writerecord"
+/*** XML Help:
+    <section id="c:writerecord">
+     <title><command>writerecord</command></title>
+     <para>Write to a locked record in a ctdb database</para>
+     <cmdsynopsis>
+      <command>writerecord</command>
+      <arg choice="req"><replaceable>db-id</replaceable></arg>
+      <arg choice="req"><replaceable>lock-id</replaceable></arg>
+      <arg choice="req"><replaceable>data</replaceable></arg>
+     </cmdsynopsis>
+
+     <para>Once a record is locked with
+     <command>readrecordlock</command>, you can write to it. </para>
+     </section>
+*/
+}
+
+static int lock_destructor(struct lock *lock)
+{
+	ctdb_release_lock(lock->db, lock->lock);
+	DLIST_REMOVE(locks, lock);
+	return 0;
+}
+
+static bool releaselock(int argc, char **argv)
+{
+	struct ctdb_db *db;
+	struct lock *lock;
+
+	if (argc != 3) {
+		log_line(LOG_ALWAYS, "Need database number and lock number");
+		return false;
+	}
+
+	db = find_db_by_id(atoi(argv[1]));
+	if (!db) {
+		log_line(LOG_ALWAYS, "Unknown db number %s", argv[1]);
+		return false;
+	}
+
+	for (lock = locks; lock; lock = lock->next) {
+		if (lock->id == atoi(argv[2]))
+			break;
+	}
+	if (!lock) {
+		log_line(LOG_ALWAYS, "Unknown lock number %s", argv[2]);
+		return false;
+	}
+	talloc_free(lock);
+	return true;
+}
+
+static bool writerecord(int argc, char **argv)
+{
+	struct ctdb_db *db;
+	struct lock *lock;
+	TDB_DATA data;
+
+	if (argc != 4) {
+		log_line(LOG_ALWAYS, "Need db-id, lock-id and data");
+		return false;
+	}
+
+	db = find_db_by_id(atoi(argv[1]));
+	if (!db) {
+		log_line(LOG_ALWAYS, "Unknown db number %s", argv[1]);
+		return false;
+	}
+
+	for (lock = locks; lock; lock = lock->next) {
+		if (lock->id == atoi(argv[2]))
+			break;
+	}
+	if (!lock) {
+		log_line(LOG_ALWAYS, "Unknown lock number %s", argv[2]);
+		return false;
+	}
+
+	data.dptr = (unsigned char *)argv[3];
+	data.dsize = strlen(argv[3]);
+
+	if (!ctdb_writerecord(db, lock->lock, data)) {
+		log_line(LOG_UI, "writerecordlock: failed %s", strerror(errno));
+		return false;
+	}
+	return true;
+}
+
+static bool readrecordlock(int argc, char **argv)
+{
+	struct lock *lock = talloc(working, struct lock);
+	TDB_DATA key, data;
+
+	if (!get_ctdb()) {
+		log_line(LOG_ALWAYS, "No ctdb connection");
+		return false;
+	}
+	if (argc != 3) {
+		log_line(LOG_ALWAYS, "Need db-id and key");
+		return false;
+	}
+
+	lock->db = find_db_by_id(atoi(argv[1]));
+	if (!lock->db) {
+		log_line(LOG_ALWAYS, "Unknown db number %s", argv[1]);
+		return false;
+	}
+
+	key.dptr = (unsigned char *)argv[2];
+	key.dsize = strlen(argv[2]);
+
+	lock->lock = ctdb_readrecordlock(get_ctdb(), lock->db, key, &data);
+	if (!lock->lock) {
+		log_line(LOG_UI, "readrecordlock: failed %s", strerror(errno));
+		return false;
+	}
+	lock->id = ++lock_id;
+	DLIST_ADD(locks, lock);
+	talloc_set_destructor(lock, lock_destructor);
+
+	log_line(LOG_UI, "lock %u: data '%.*s'",
+		 lock->id, data.dsize, (char *)data.dptr);
+	return true;
+}
+
+static void readrecordlock_init(void)
+{
+	tui_register_command("readrecordlock",
+			     readrecordlock, readrecordlock_help);
+	tui_register_command("releaselock", releaselock, releaselock_help);
+	tui_register_command("writerecord", writerecord, writerecord_help);
+}
+init_call(readrecordlock_init);

Added: branches/ctdb/squeeze-backports/libctdb/test/run.sh
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/run.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/run.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,83 @@
+#! /bin/sh
+
+set -e
+
+CTDBD_DIR=/tmp/ctdbd-test
+VALGRIND="valgrind -q --error-exitcode=111"
+
+if [ x"$1" = x--no-valgrind ]; then
+    VALGRIND=""
+    shift
+fi
+
+if pidof ctdbd > /dev/null; then
+    echo ctdbd already running.  Please kill it. >&2
+    exit 1
+fi
+
+cleanup()
+{
+    killall ctdbd
+}
+
+# Default is to run all tests.
+if [ $# = 0 ]; then
+    set tests/*
+fi
+
+# Build ctdb, and build ctdb-test
+make --quiet -C ../..
+echo Building ctdb-test...
+make --quiet
+
+rm -rf $CTDBD_DIR
+mkdir -p $CTDBD_DIR $CTDBD_DIR/dbs $CTDBD_DIR/dbs/persistent $CTDBD_DIR/dbs/state $CTDBD_DIR/event.d
+
+if lsmod | grep -q dummy; then
+    :
+else
+    echo Installing dummy0 network module...
+    sudo modprobe dummy
+fi
+
+echo 10.199.199.1/24 dummy0 > $CTDBD_DIR/addresses
+cat > $CTDBD_DIR/event.d/01.print <<EOF
+#! /bin/sh
+
+echo "Script invoked with args \$@" >> $CTDBD_DIR/eventscripts.log
+EOF
+chmod a+x $CTDBD_DIR/event.d/01.print
+
+echo Running ctdbd with logging to $CTDBD_DIR/log...
+../../bin/ctdbd --logfile=$CTDBD_DIR/log --public-addresses=$CTDBD_DIR/addresses --dbdir=$CTDBD_DIR/dbs --reclock=$CTDBD_DIR/reclock --dbdir-persistent=$CTDBD_DIR/dbs/persistent --dbdir-state=$CTDBD_DIR/dbs/state --event-script-dir=$CTDBD_DIR/event.d
+
+trap cleanup EXIT
+
+echo Waiting for ctdbd to be happy...
+i=0
+while true; do
+    ../../bin/ctdb status > $CTDBD_DIR/status
+    if ! grep -q UNHEALTHY $CTDBD_DIR/status; then
+	break
+    fi
+    sleep 1
+    i=`expr $i + 1`
+    if [ $i = 40 ]; then
+	echo ctdbd failed to start: >&2
+	tail -n 20 $CTDBD_DIR/log >&2
+	exit 1
+    fi
+done
+
+for test; do
+    echo -n Running $test...
+    if $VALGRIND ./ctdb-test --quiet $test > $CTDBD_DIR/test-out 2>&1; then
+	echo success.
+    else
+	echo failure:
+	cat $CTDBD_DIR/test-out
+	exit 1
+    fi
+done
+
+echo Success!


Property changes on: branches/ctdb/squeeze-backports/libctdb/test/run.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/libctdb/test/tests/attachdb1.txt
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tests/attachdb1.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tests/attachdb1.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,8 @@
+connect
+# This is just a sanity check
+expect attachdb attached: 1
+attachdb test.tdb false
+expect attachdb attached: 2
+attachdb test2.tdb false
+detachdb 2
+detachdb 1

Added: branches/ctdb/squeeze-backports/libctdb/test/tests/connect1.txt
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tests/connect1.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tests/connect1.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,3 @@
+# Simple connect, disconnect
+connect
+disconnect

Added: branches/ctdb/squeeze-backports/libctdb/test/tests/connect2.txt
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tests/connect2.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tests/connect2.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,3 @@
+# Simple connect with explicit path, then disconnect
+connect /tmp/ctdb.socket
+disconnect

Added: branches/ctdb/squeeze-backports/libctdb/test/tests/lockrecord1.txt
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tests/lockrecord1.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tests/lockrecord1.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,8 @@
+connect
+# This is just a sanity check
+expect attachdb attached: 1
+attachdb test.tdb false
+# This is just a sanity check
+expect readrecordlock lock 1: data ''
+readrecordlock 1 testkey
+releaselock 1 1

Added: branches/ctdb/squeeze-backports/libctdb/test/tests/lockrecord2.txt
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tests/lockrecord2.txt	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tests/lockrecord2.txt	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+connect
+# This is just a sanity check
+expect attachdb attached: 1
+attachdb test.tdb false
+# This is just a sanity check
+expect readrecordlock lock 1: data ''
+readrecordlock 1 testkey
+writerecord 1 1 test-contents
+releaselock 1 1
+
+expect readrecordlock lock 2: data 'test-contents'
+readrecordlock 1 testkey
+releaselock 1 2

Added: branches/ctdb/squeeze-backports/libctdb/test/tools/create-links
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tools/create-links	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tools/create-links	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Create docbook-xml links
+
+# most things will be under this path.
+DOCB=/usr/share/sgml/docbook
+
+# potential location for xhtml/docbook.xsl
+XSLDIRS="$DOCB/xsl-stylesheets* $DOCB/stylesheet/xsl/nwalsh"
+
+# potential location for docbookx.dtd
+DTDDIRS="$DOCB/xml-dtd* $DOCB/dtd/xml/*"
+
+# look for a file (arg 1) in a set of dirs (arg 2). If it exists, create a link
+# (arg 3), in the current directory to the dir.
+condlink() {
+	file=$1
+	dirs=$2
+	link=$3
+
+	for d in $dirs
+	do
+		if [ -f $d/$file ]
+		then
+			dir=$d
+			break
+		fi
+	done
+
+	if [ -z "$dir" ]
+	then
+		echo Docbook support not found.  See README.  Faking it. >&2
+		exit 1
+	else
+		ln -sfn "$dir" "$link"
+	fi
+}
+
+condlink "xhtml/docbook.xsl" "$XSLDIRS" "link-xhtml"
+condlink "docbookx.dtd" "$DTDDIRS" "link-dtd"


Property changes on: branches/ctdb/squeeze-backports/libctdb/test/tools/create-links
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/libctdb/test/tools/extract-help
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tools/extract-help	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tools/extract-help	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,10 @@
+#! /bin/sh
+# Extract XML help from .c file.
+
+FILE=$1
+LINE=`expr $2 + 1`
+
+END=`tail -n +$LINE $1 | fgrep -n '*/' | cut -d: -f1 | head -n +1`
+END=`expr $END - 1`
+
+tail -n +$LINE $1 | head -n $END


Property changes on: branches/ctdb/squeeze-backports/libctdb/test/tools/extract-help
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/libctdb/test/tools/gen-help
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tools/gen-help	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tools/gen-help	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,52 @@
+#! /bin/bash
+
+# We could have multiple occurances.  Create all of them.
+FILE=$1
+
+TMPF=`mktemp /tmp/gen-help.XXXXXX`
+trap "rm -f $TMPF*" EXIT
+cmdsed='s,.*<command>[ 	]*\([^ 	]*\)[ 	]*</command>.*,\1,p'
+
+STARTLINE=1
+for LINE in `fgrep -n '/*** XML Help:' < $FILE | cut -d: -f1`; do
+    if [ -L tools/link-dtd ]; then
+	echo '<?xml version="1.0"?>' > $TMPF
+	echo '<!DOCTYPE article PUBLIC "-//OASIS//DTD Docbook XML V4.1.2//EN"' \
+	    >> $TMPF
+	echo '"'`pwd`'/tools/link-dtd/docbookx.dtd">' >> $TMPF
+	echo '<article><section>' >> $TMPF
+	tools/extract-help $FILE $LINE >> $TMPF
+	echo '</section></article>' >> $TMPF
+
+	tr '\n' ' ' < $TMPF | sed -e 's/[[:space:]]\{2,\}/ /g' |
+        xsltproc tools/text.xsl - | fold -w80 -s > $TMPF.txt
+
+	COMMAND=`sed -n "$cmdsed" < $TMPF | head -n +1`
+	COMMAND_FILE=generated-`basename $FILE .c`-help:$COMMAND
+	#echo Creating $COMMAND_FILE
+
+        # Output description, in quotes.
+	echo 'log_line(LOG_ALWAYS,' > $COMMAND_FILE
+
+	TXTSTART=`grep -n '^  1\.1\.' $TMPF.txt | cut -d: -f1`
+	tail -n +`expr $TXTSTART + 2` $TMPF.txt | while read -r TXTLINE; do
+	    echo "$TXTLINE" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' \
+		-e 's/$/\\n"/' >> $COMMAND_FILE
+	done
+	echo ');' >> $COMMAND_FILE
+    else
+	tools/extract-help $FILE $LINE > $TMPF
+
+	COMMAND=`sed -n "$cmdsed" < $TMPF | head -n +1`
+	COMMAND_FILE=generated-`basename $FILE .c`-help:$COMMAND
+	echo Faking up $COMMAND_FILE
+
+	echo 'log_line(LOG_ALWAYS,' > $COMMAND_FILE
+	sed 's/<arg [^>]*>/   /;s/<[^>]*>//g' < $TMPF |
+	    sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$/\\n"/' \
+		>> $COMMAND_FILE
+	echo ');' >> $COMMAND_FILE
+    fi
+
+    STARTLINE=$LINE
+done


Property changes on: branches/ctdb/squeeze-backports/libctdb/test/tools/gen-help
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/libctdb/test/tools/gen-usage
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tools/gen-usage	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tools/gen-usage	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,56 @@
+#! /bin/sh
+
+# read a list of C files with inline XML usage given on the command line, and
+# write a usage function on stdout
+
+tmpf=`mktemp /tmp/gen-help.XXXXXX`
+trap "rm -f $tmpf*" EXIT
+quote() {
+    sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$/\\n"/'
+}
+
+cat <<EOF
+#include <stdio.h>
+#include "utils.h"
+
+void print_usage(void)
+{
+	fprintf(stderr,
+"Usage: ctdb-test [options]\n"
+"Options available:\n"
+"\n"
+EOF
+
+for file in "$@"
+do
+    for line in `fgrep -n '/*** XML Argument:' < $file | cut -d: -f1`;
+    do
+	if [ -L tools/link-dtd ]; then
+
+	    cat > $tmpf <<EOF
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Docbook XML V4.1.2//EN"
+"`pwd`/tools/link-dtd/docbookx.dtd">
+<article>
+EOF
+	    tools/extract-help $file $line >> $tmpf
+	    echo '</article>' >> $tmpf
+
+	    tr '\n' ' ' < $tmpf | sed -e 's/[[:space:]]\{2,\}/ /g' |
+		xsltproc tools/usage.xsl - | fold -w80 -s > $tmpf.txt
+
+	    quote < $tmpf.txt
+	else
+	    # if we don't have docbook, just strip out the tags and grab
+	    # the first two lines
+	    tools/extract-help $file $line > $tmpf
+	    sed 's/<arg [^>]*>/   /;s/<[^>]*>//g;' < $tmpf | head -3 | quote
+	fi
+
+    done
+done
+
+cat <<EOF
+);
+}
+EOF


Property changes on: branches/ctdb/squeeze-backports/libctdb/test/tools/gen-usage
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/libctdb/test/tools/text.xsl
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tools/text.xsl	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tools/text.xsl	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,111 @@
+<?xml version="1.0"?>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0">
+ <xsl:output method="text"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="/">
+  <xsl:apply-templates select="article"/>
+ </xsl:template>
+
+ <xsl:template match="article">
+  <xsl:apply-templates select="section"/><xsl:text>
+</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="section">
+  <xsl:apply-templates select="title|para|cmdsynopsis|section"/>
+ </xsl:template>
+
+ <xsl:template match="title">
+  <xsl:apply-templates/><xsl:text>
+</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="subtitle">
+  <xsl:apply-templates/><xsl:text>
+</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="command|filename|varname|computeroutput|constant">
+  <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="option">
+  <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="screen">
+  <xsl:text>
+</xsl:text><xsl:apply-templates/><xsl:text>
+</xsl:text>
+ </xsl:template>
+
+
+ <xsl:template match="arg">
+  <xsl:choose>
+   <xsl:when test="@choice='opt'">
+    <xsl:text> [</xsl:text><xsl:apply-templates/><xsl:text>]</xsl:text>
+   </xsl:when>
+   <xsl:otherwise>
+    <xsl:text> </xsl:text><xsl:apply-templates/>
+   </xsl:otherwise>
+  </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="para">
+  <xsl:text>
+</xsl:text>
+<xsl:apply-templates/><xsl:text>
+</xsl:text>
+</xsl:template>
+
+ <xsl:template match="cmdsynopsis">
+  <xsl:text>
+</xsl:text>
+  <xsl:apply-templates select="command|sbr|arg"/><xsl:text>
+</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="synopfragmentref">
+  <xsl:variable name="target" select="id(@linkend)"/>
+  <xsl:apply-templates select="$target"/>
+ </xsl:template>
+
+ <xsl:template match="synopfragment">
+  <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="group">
+  <xsl:text>{ </xsl:text><xsl:for-each select="arg">
+   <xsl:apply-templates/>
+   <xsl:if test="position() != last()"><xsl:text> | </xsl:text></xsl:if>
+  </xsl:for-each><xsl:text> }</xsl:text>
+ </xsl:template>
+
+
+ <xsl:template match="replaceable">{<xsl:apply-templates/>}</xsl:template>
+
+
+ <xsl:template match="sbr">
+  <xsl:text>
+</xsl:text>
+</xsl:template>
+
+ <xsl:template match="text()"><xsl:value-of select="."/></xsl:template>
+
+ <xsl:template match="node()">
+  <xsl:message terminate="yes">Unknown node <xsl:value-of select="name()"/>
+</xsl:message>
+ </xsl:template>
+
+ <xsl:template match="simplelist">
+  <xsl:for-each select="member">
+   <xsl:apply-templates/>
+   <xsl:if test="position() != last()"><xsl:text>, </xsl:text></xsl:if>
+  </xsl:for-each>
+ </xsl:template>
+
+
+</xsl:stylesheet>

Added: branches/ctdb/squeeze-backports/libctdb/test/tools/usage.xsl
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tools/usage.xsl	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tools/usage.xsl	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0">
+ <xsl:output method="text"/>
+ <xsl:strip-space elements="*"/>
+ <xsl:include href="text.xsl"/>
+
+ <xsl:template match="section">
+  <xsl:apply-templates select="title"/>
+  <xsl:text>    </xsl:text><xsl:apply-templates select="subtitle"/>
+ </xsl:template>
+
+ <xsl:template match="para">
+  <xsl:apply-templates/>
+ </xsl:template>
+
+</xsl:stylesheet>

Added: branches/ctdb/squeeze-backports/libctdb/test/tui.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tui.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tui.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,460 @@
+/*
+
+This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
+
+Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
+
+This file is part of nfsim.
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "tui.h"
+#include "log.h"
+#include "ctdb-test.h"
+#include "utils.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+#include <assert.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <talloc.h>
+#include <dlinklist.h>
+
+int tui_echo_commands;
+int tui_abort_on_fail;
+int tui_quiet;
+int tui_linenum = 1;
+char *extension_path;
+static bool stop;
+
+struct command {
+	struct command *next, *prev;
+	char	name[TUI_MAX_CMD_LEN+1];
+	bool	(*handler)(int, char **);
+	void	(*helpfn) (int, char **);
+};
+
+struct pre_post_hook {
+	struct pre_post_hook *next, *prev;
+	void	(*pre)(const char *);
+	bool	(*post)(const char *);
+};
+
+static struct command *commands;
+static struct pre_post_hook *pre_post_hooks;
+
+static bool tui_exit(int argc, char **argv)
+{
+	stop = true;
+	return true;
+}
+
+static bool tui_argtest(int argc, char **argv)
+{
+	int i;
+
+	for (i = 0; i < argc; i++)
+		log_line(LOG_UI, "argv[%d]: \"%s\"", i, argv[i]);
+
+	return true;
+}
+
+static inline struct command *find_command(const char *name)
+{
+	struct command *cmd;
+	for (cmd = commands; cmd; cmd = cmd->next)
+		if (!strcmp(name, cmd->name))
+			return cmd;
+
+	return NULL;
+}
+
+bool tui_is_command(const char *name)
+{
+	return find_command(name) != NULL;
+}
+
+static void do_pre_commands(const char *cmd)
+{
+	struct pre_post_hook *i;
+	for (i = pre_post_hooks; i; i = i->next)
+		if (i->pre)
+			i->pre(cmd);
+}
+
+static bool do_post_commands(const char *cmd)
+{
+	struct pre_post_hook *i;
+	bool ret = true;
+
+	for (i = pre_post_hooks; i; i = i->next)
+		if (i->post && !i->post(cmd))
+			ret = false;
+	return ret;
+}
+
+static bool tui_help(int argc, char **argv)
+{
+	struct command *cmd;
+
+	if (argc == 1) {
+		log_line(LOG_UI, "CTDB tester\n"
+		"help is available on the folowing commands:");
+		for (cmd = commands; cmd; cmd = cmd->next) {
+			if (cmd->helpfn)
+				log_line(LOG_UI, "\t%s", cmd->name);
+		}
+	} else {
+		if (!(cmd = find_command(argv[1]))) {
+			log_line(LOG_ALWAYS, "No such command '%s'", argv[1]);
+			return false;
+		}
+		if (!cmd->helpfn) {
+			log_line(LOG_UI, "No help for the '%s' function",
+				argv[1]);
+			return false;
+		}
+		cmd->helpfn(argc-1, argv+1);
+	}
+	return true;
+
+
+}
+
+static void tui_help_help(int argc, char **argv)
+{
+#include "generated-tui-help:help"
+/*** XML Help:
+    <section id="c:help">
+     <title><command>help</command></title>
+     <para>Displays general help, or help for a specified command</para>
+     <cmdsynopsis>
+      <command>help</command>
+      <arg choice="opt">command</arg>
+     </cmdsynopsis>
+     <para>With no arguments, <command>help</command> will show general system
+      help, and list the available commands. If an argument is specified, then
+      <command>help</command> will show help for that command, if
+      available.</para>
+    </section>
+*/
+}
+
+static void tui_exit_help(int argc, char **argv)
+{
+#include "generated-tui-help:exit"
+/*** XML Help:
+    <section id="c:exit">
+     <title><command>exit</command>,
+     <command>quit</command></title>
+     <para>Exit the simulator</para>
+     <cmdsynopsis>
+      <command>exit</command>
+     </cmdsynopsis>
+     <cmdsynopsis>
+      <command>quit</command>
+     </cmdsynopsis>
+
+     <para>The <command>exit</command> and <command>quit</command>
+      commands are synonomous.  They both exit the simulator.
+     </para>
+    </section>
+ */
+}
+
+void script_fail(const char *fmt, ...)
+{
+	char *str;
+	va_list arglist;
+
+	log_line(LOG_ALWAYS, "Script failed at line %i: ", tui_linenum);
+
+	va_start(arglist, fmt);
+	str = talloc_vasprintf(NULL, fmt, arglist);
+	va_end(arglist);
+
+	log_line(LOG_ALWAYS, "%s", str);
+	talloc_free(str);
+
+	check_allocations();
+	check_databases();
+	exit(EXIT_SCRIPTFAIL);
+}
+
+bool tui_do_command(int argc, char *argv[], bool abort)
+{
+	struct command *cmd;
+	bool ret = true;
+
+	if ((cmd = find_command(argv[0]))) {
+		do_pre_commands(cmd->name);
+		if (!cmd->handler(argc, argv)) {
+			/* Abort on UNEXPECTED failure. */
+			if (!log_line(LOG_UI, "%s: command failed", argv[0])
+			    && abort)
+				script_fail("%s failed", argv[0]);
+			ret = false;
+		}
+		if (!do_post_commands(cmd->name))
+			ret = false;
+		return ret;
+	}
+
+	if (abort)
+		script_fail("%s not found", argv[0]);
+
+	log_line(LOG_ALWAYS, "%s: command not found", argv[0]);
+	return false;
+}
+
+/**
+ * backslash-escape a binary data block into a newly allocated
+ * string
+ *
+ * @param src a pointer to the data block
+ * @param src_len the length of the data block
+ * @return NULL if out of memory, or a pointer to the allocated escaped
+ *    string, which is terminated with a '\0' character
+ */
+static char *escape(const char *src, size_t src_len)
+{
+	static const char hexbuf[]= "0123456789abcdef";
+	char *dest, *p;
+	size_t i;
+
+	/* src_len * 4 is always safe, it's the longest escape
+	   sequence for all characters */
+	dest = talloc_array(src, char, src_len * 4 + 1);
+	p = dest;
+
+	for (i = 0; i < src_len; i++) {
+		if (src[i] == '\n') {
+			*p++ = '\\';
+			*p++ = 'n';
+		} else if (src[i] == '\r') {
+			*p++ = '\\';
+			*p++ = 'r';
+		} else if (src[i] == '\0') {
+			*p++ = '\\';
+			*p++ = '0';
+		} else if (src[i] == '\t') {
+			*p++ = '\\';
+			*p++ = 't';
+		} else if (src[i] == '\\') {
+			*p++ = '\\';
+			*p++ = '\\';
+		} else if (src[i] & 0x80 || (src[i] & 0xe0) == 0) {
+			*p++ = '\\';
+			*p++ = 'x';
+			*p++ = hexbuf[(src[i] >> 4) & 0xf];
+			*p++ = hexbuf[src[i] & 0xf];
+		} else
+			*p++ = src[i];
+	}
+
+	*p++ = 0;
+	return dest;
+}
+
+/* Process `command`: update off to point to tail backquote */
+static char *backquote(char *line, unsigned int *off)
+{
+	char *end, *cmdstr, *str;
+	FILE *cmdfile;
+	size_t used, len, i;
+	int status;
+
+	/* Skip first backquote, look for next one. */
+	(*off)++;
+	end = strchr(line + *off, '`');
+	if (!end)
+		script_fail("no matching \"`\" found");
+
+	len = end - (line + *off);
+	cmdstr = talloc_asprintf(line, "PATH=%s; %.*s",
+				 extension_path, (int)len, line + *off);
+	cmdfile = popen(cmdstr, "r");
+	if (!cmdfile)
+		script_fail("failed to popen '%s': %s\n",
+			    cmdstr, strerror(errno));
+
+       /* Jump to backquote. */
+       *off += len;
+
+	/* Read command output. */
+	used = 0;
+	len = 1024;
+	str = talloc_array(line, char, len);
+
+	while ((i = fread(str + used, 1, len - used, cmdfile)) != 0) {
+		used += i;
+		if (used == len) {
+			if (len > 1024*1024)
+				script_fail("command '%s' output too long\n",
+					    cmdstr);
+			len *= 2;
+			str = talloc_realloc(line, str, char, len);
+		}
+	}
+	status = pclose(cmdfile);
+	if (status == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
+		script_fail("command '%s' failed\n", cmdstr);
+
+	return escape(str, used);
+}
+
+static char *append_char(char **argv, unsigned int argc, char c)
+{
+	if (!argv[argc])
+		return talloc_asprintf(argv, "%c", c);
+	return talloc_asprintf_append(argv[argc], "%c", c);
+}
+
+static char *append_string(char **argv, unsigned int argc, const char *str)
+{
+	if (!argv[argc])
+		return talloc_asprintf(argv, "%s", str);
+	return talloc_asprintf_append(argv[argc], "%s", str);
+}
+
+static void process_line(char *line, unsigned int off)
+{
+	unsigned int argc, i;
+	char **argv;
+
+	if (tui_echo_commands)
+		printf("%u:%s\n", tui_linenum, line + off);
+
+	/* Talloc argv off line so commands can use it for auto-cleanup. */
+	argv = talloc_zero_array(line, char *, TUI_MAX_ARGS+1);
+	argc = 0;
+	for (i = off; line[i]; i++) {
+		if (isspace(line[i])) {
+			/* If anything in this arg, move to next. */
+			if (argv[argc])
+				argc++;
+		} else if (line[i] == '`') {
+			char *inside = backquote(line, &i);
+			argv[argc] = append_string(argv, argc, inside);
+		} else {
+			/* If it is a comment, stop before we process `` */
+			if (!argv[0] && line[i] == '#')
+				goto out;
+
+			argv[argc] = append_char(argv, argc, line[i]);
+		}
+	}
+
+	if (argv[0]) {
+		if (argv[argc])
+			argv[++argc] = NULL;
+		tui_do_command(argc, argv, tui_abort_on_fail);
+	}
+
+out:
+	tui_linenum++;
+	return;
+}
+
+static void readline_process_line(char *line)
+{
+	char *talloc_line;
+	if (!line) {
+		stop = true;
+		return;
+	}
+
+	add_history(line);
+
+	/* Readline isn't talloc-aware, so copy string: functions can
+	 * hang temporary variables off this. */
+	talloc_line = talloc_strdup(NULL, line);
+	process_line(talloc_line, 0);
+	talloc_free(talloc_line);
+}
+
+static void run_whole_file(int fd)
+{
+	char *file, *p;
+	size_t size, len;
+
+	file = grab_fd(fd, &size);
+	if (!file)
+		err(1, "Grabbing file");
+
+	for (p = file; p < file + size; p += len+1) {
+		len = strcspn(p, "\n");
+		p[len] = '\0';
+		process_line(file, p - file);
+	}
+}
+
+void tui_run(int fd)
+{
+	tui_register_command("exit", tui_exit, tui_exit_help);
+	tui_register_command("quit", tui_exit, tui_exit_help);
+	tui_register_command("q", tui_exit, tui_exit_help);
+	tui_register_command("test", tui_argtest, NULL);
+	tui_register_command("help", tui_help, tui_help_help);
+
+	if (fd == STDIN_FILENO) {
+		stop = false;
+		rl_callback_handler_install(tui_quiet ? "" : "> ",
+					    readline_process_line);
+		while (!stop)
+			rl_callback_read_char();
+		rl_callback_handler_remove();
+		if (!tui_quiet)
+			printf("\n");
+	} else
+		run_whole_file(fd);
+}
+
+int tui_register_pre_post_hook(void (*pre)(const char *),
+			       bool (*post)(const char *))
+{
+	struct pre_post_hook *h;
+
+	h = talloc(NULL, struct pre_post_hook);
+	h->pre = pre;
+	h->post = post;
+	DLIST_ADD(pre_post_hooks, h);
+	return 0;
+}
+
+int tui_register_command(const char *command,
+			 bool (*handler)(int, char **),
+			 void (*helpfn)(int, char **))
+{
+	struct command *cmd;
+
+	assert(strlen(command) < TUI_MAX_CMD_LEN);
+
+	cmd = talloc(NULL, struct command);
+	strncpy(cmd->name, command, TUI_MAX_CMD_LEN);
+	cmd->handler = handler;
+	cmd->helpfn  = helpfn;
+
+	DLIST_ADD(commands, cmd);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/libctdb/test/tui.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/tui.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/tui.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,54 @@
+/*
+
+This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
+
+Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
+
+This file is part of nfsim.
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef __HAVE_TUI_H
+#define __HAVE_TUI_H
+
+#include <stdbool.h>
+
+#define TUI_MAX_CMD_LEN		1024
+#define TUI_MAX_ARGS		128
+
+int tui_register_command(const char *command,
+			 bool (*handler)(int argc, char **argv),
+			 void (*helpfn)(int argc, char **argv));
+
+int tui_register_pre_post_hook(void (*pre)(const char *),
+			       bool (*post)(const char *));
+
+void tui_run(int fd);
+
+bool tui_do_command(int argc, char *argv[], bool abort);
+
+/* Is this a valid command?  Sanity check for expect. */
+bool tui_is_command(const char *name);
+
+/* A script test failed (a command failed with -e, or an expect failed). */
+void script_fail(const char *fmt, ...) __attribute__((noreturn));
+
+extern int tui_echo_commands;
+extern int tui_abort_on_fail;
+extern int tui_quiet;
+extern int tui_linenum;
+
+#endif /* __HAVE_TUI_H */

Added: branches/ctdb/squeeze-backports/libctdb/test/utils.h
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/test/utils.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/test/utils.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,86 @@
+/*
+
+This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
+
+Copyright (c) 2003,2004 Rusty Russell
+
+This file is part of nfsim.
+
+nfsim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+nfsim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with nfsim; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef _UTILS_H
+#define _UTILS_H
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+/* Is A == B ? */
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+/* Does A start with B ? */
+#define strstarts(a,b) (strncmp((a),(b),strlen(b)) == 0)
+
+/* Does A end in B ? */
+static inline bool strends(const char *a, const char *b)
+{
+	if (strlen(a) < strlen(b))
+		return false;
+
+	return streq(a + strlen(a) - strlen(b), b);
+}
+
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
+
+/* Paste two tokens together. */
+#define ___cat(a,b) a ## b
+#define __cat(a,b) ___cat(a,b)
+
+/* Try to give a unique identifier: this comes close, iff used as static. */
+#define __unique_id(stem) __cat(__cat(__uniq,stem),__LINE__)
+
+enum exitcodes {
+	/* EXIT_SUCCESS, EXIT_FAILURE is in stdlib.h */
+	EXIT_SCRIPTFAIL = EXIT_FAILURE + 1,
+};
+
+/* init code */
+typedef void (*initcall_t)(void);
+#define init_call(fn) \
+	static initcall_t __initcall_##fn \
+	__attribute__((__unused__)) \
+	__attribute__((__section__("init_call"))) = &fn
+
+/* distributed command line options */
+struct cmdline_option
+{
+       struct option opt;
+       void (*parse)(struct option *opt);
+}  __attribute__((aligned(64)));	/* align it to 64 for 64bit arch,
+ * <rusty> LaF0rge: space is cheap.  A comment might be nice. */
+
+#define cmdline_opt(_name, _has_arg, _c, _fn)                                \
+       static struct cmdline_option __cat(__cmdlnopt_,__unique_id(_fn))      \
+       __attribute__((__unused__))                                           \
+       __attribute__((__section__("cmdline")))                               \
+       = { .opt = { .name = _name, .has_arg = _has_arg, .val = _c },         \
+	   .parse = _fn }
+
+/* In generated-usage.c */
+void print_usage(void);
+
+#endif /* _UTILS_H */

Added: branches/ctdb/squeeze-backports/libctdb/tst.c
===================================================================
--- branches/ctdb/squeeze-backports/libctdb/tst.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/libctdb/tst.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,404 @@
+/*
+ * Example program to demonstrate the libctdb api
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This program needs to be linked with libtdb and libctdb
+ * (You need these packages installed: libtdb libtdb-devel
+ *  ctdb and ctdb-devel)
+ *
+ * This program can then be compiled using
+ *    gcc -o tst tst.c -ltdb -lctdb
+ *
+ *
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+#include <stdbool.h>
+#include <syslog.h>
+#include <tdb.h>
+#include <ctdb.h>
+#include <ctdb_protocol.h>
+
+TDB_DATA key;
+
+
+char *ctdb_addr_to_str(ctdb_sock_addr *addr)
+{
+	static char cip[128] = "";
+
+	switch (addr->sa.sa_family) {
+	case AF_INET:
+		inet_ntop(addr->ip.sin_family, &addr->ip.sin_addr, cip, sizeof(cip));
+		break;
+	case AF_INET6:
+		inet_ntop(addr->ip6.sin6_family, &addr->ip6.sin6_addr, cip, sizeof(cip));
+		break;
+	default:
+		printf("ERROR, unknown family %u\n", addr->sa.sa_family);
+	}
+
+	return cip;
+}
+
+void print_nodemap(struct ctdb_node_map *nodemap)
+{
+	int i;
+
+	printf("number of nodes:%d\n", nodemap->num);
+	for (i=0;i<nodemap->num;i++) {
+		printf("Node:%d Address:%s Flags:%s%s%s%s%s%s\n",
+			nodemap->nodes[i].pnn,
+			ctdb_addr_to_str(&nodemap->nodes[i].addr),
+			nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED?"DISCONNECTED ":"",
+			nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY?"UNHEALTHY ":"",
+			nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED?"ADMIN DISABLED ":"",
+			nodemap->nodes[i].flags&NODE_FLAGS_BANNED?"BANNED ":"",
+			nodemap->nodes[i].flags&NODE_FLAGS_DELETED?"DELETED ":"",
+			nodemap->nodes[i].flags&NODE_FLAGS_STOPPED?"STOPPED ":"");
+	}
+}
+
+void msg_h(struct ctdb_connection *ctdb, uint64_t srvid, TDB_DATA data, void *private_data)
+{
+	printf("Message received on port %llx : %s\n", srvid, data.dptr);
+}
+
+void rip_h(struct ctdb_connection *ctdb, uint64_t srvid, TDB_DATA data, void *private_data)
+{
+	printf("RELEASE IP message for %s\n", data.dptr);
+}
+
+void tip_h(struct ctdb_connection *ctdb, uint64_t srvid, TDB_DATA data, void *private_data)
+{
+	printf("TAKE IP message for %s\n", data.dptr);
+}
+
+static void gnm_cb(struct ctdb_connection *ctdb,
+		   struct ctdb_request *req, void *private)
+{
+	bool status;
+	struct ctdb_node_map *nodemap;
+
+	status = ctdb_getnodemap_recv(ctdb, req, &nodemap);
+	ctdb_request_free(req);
+	if (!status) {
+		printf("Error reading NODEMAP\n");
+		return;
+	}
+	printf("ASYNC response to getnodemap:\n");
+	print_nodemap(nodemap);
+	ctdb_free_nodemap(nodemap);
+}
+
+void print_ips(struct ctdb_all_public_ips *ips)
+{
+	int i;
+	
+	printf("Num public ips:%d\n", ips->num);
+	for (i=0; i<ips->num;i++) {
+		printf("%s    hosted on node %d\n",
+			ctdb_addr_to_str(&ips->ips[i].addr),
+			ips->ips[i].pnn);
+	}
+}
+
+static void ips_cb(struct ctdb_connection *ctdb,
+		   struct ctdb_request *req, void *private)
+{
+	bool status;
+	struct ctdb_all_public_ips *ips;
+
+	status = ctdb_getpublicips_recv(ctdb, req, &ips);
+	ctdb_request_free(req);
+	if (!status) {
+		printf("Error reading PUBLIC IPS\n");
+		return;
+	}
+	printf("ASYNC response to getpublicips:\n");
+	print_ips(ips);
+	ctdb_free_publicips(ips);
+}
+
+static void pnn_cb(struct ctdb_connection *ctdb,
+		   struct ctdb_request *req, void *private)
+{
+	bool status;
+	uint32_t pnn;
+
+	status = ctdb_getpnn_recv(ctdb, req, &pnn);
+	ctdb_request_free(req);
+	if (!status) {
+		printf("Error reading PNN\n");
+		return;
+	}
+	printf("ASYNC RESPONSE TO GETPNN:  pnn:%d\n", pnn);
+}
+
+static void rm_cb(struct ctdb_connection *ctdb,
+		  struct ctdb_request *req, void *private)
+{
+	bool status;
+	uint32_t rm;
+
+	status = ctdb_getrecmaster_recv(ctdb, req, &rm);
+	ctdb_request_free(req);
+	if (!status) {
+		printf("Error reading RECMASTER\n");
+		return;
+	}
+
+	printf("GETRECMASTER ASYNC: recmaster:%d\n", rm);
+}
+
+/*
+ * example on how to first read(non-existing recortds are implicitely created
+ * on demand) a record and change it in the callback.
+ * This forms the atom for the read-modify-write cycle.
+ *
+ * Pure read, or pure write are just special cases of this cycle.
+ */
+static void rrl_cb(struct ctdb_db *ctdb_db,
+		   struct ctdb_lock *lock, TDB_DATA outdata, void *private)
+{
+	TDB_DATA data;
+	char tmp[256];
+	bool *rrl_cb_called = private;
+
+	*rrl_cb_called = true;
+
+	if (!lock) {
+		printf("rrl_cb returned error\n");
+		return;
+	}
+
+	printf("rrl size:%d data:%.*s\n", outdata.dsize,
+	       outdata.dsize, outdata.dptr);
+	if (outdata.dsize == 0) {
+		tmp[0] = 0;
+	} else {
+		strcpy(tmp, outdata.dptr);
+	}
+	strcat(tmp, "*");
+
+	data.dptr  = tmp;
+	data.dsize = strlen(tmp) + 1;
+	if (!ctdb_writerecord(ctdb_db, lock, data))
+		printf("Error writing data!\n");
+
+	/* Release the lock as quickly as possible */
+	ctdb_release_lock(ctdb_db, lock);
+
+	printf("Wrote new record : %s\n", tmp);
+
+}
+
+static bool registered = false;
+void message_handler_cb(struct ctdb_connection *ctdb,
+			struct ctdb_request *req, void *private)
+{
+	if (!ctdb_set_message_handler_recv(ctdb, req)) {
+		err(1, "registering message");
+	}
+	ctdb_request_free(req);
+	printf("Message handler registered\n");
+	registered = true;
+}
+
+static int traverse_callback(struct ctdb_connection *ctdb_connection, struct ctdb_db *ctdb_db, int status, TDB_DATA key, TDB_DATA data, void *private_data)
+{
+	if (status == TRAVERSE_STATUS_FINISHED) {
+		printf("Traverse finished\n");
+		return 0;
+	}
+	if (status == TRAVERSE_STATUS_ERROR) {
+		printf("Traverse failed\n");
+		return 1;
+	}
+
+	printf("traverse callback   status:%d\n", status);
+	printf("key: %d [%s]\n", key.dsize, key.dptr);
+	printf("data:%d [%s]\n", data.dsize, data.dptr);
+
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct ctdb_connection *ctdb_connection;
+	struct ctdb_request *handle;
+	struct ctdb_db *ctdb_db_context;
+	struct ctdb_node_map *nodemap;
+	struct pollfd pfd;
+	uint32_t recmaster;
+	TDB_DATA msg;
+	bool rrl_cb_called = false;
+	uint64_t srvid;
+
+	ctdb_log_level = LOG_DEBUG;
+	ctdb_connection = ctdb_connect("/tmp/ctdb.socket",
+				       ctdb_log_file, stderr);
+	if (!ctdb_connection)
+		err(1, "Connecting to /tmp/ctdb.socket");
+
+	pfd.fd = ctdb_get_fd(ctdb_connection);
+
+	srvid = CTDB_SRVID_TEST_RANGE|55;
+	handle = ctdb_set_message_handler_send(ctdb_connection, srvid,
+					       msg_h, NULL,
+					       message_handler_cb, &srvid);
+	if (handle == NULL) {
+		printf("Failed to register message port\n");
+		exit(10);
+	}
+
+	/* Hack for testing: this makes sure registrations went out. */
+	while (!registered) {
+		ctdb_service(ctdb_connection, POLLIN|POLLOUT);
+	}
+
+	handle = ctdb_set_message_handler_send(ctdb_connection,
+					       CTDB_SRVID_RELEASE_IP,
+					       rip_h, NULL,
+					       message_handler_cb, NULL);
+	if (handle == NULL) {
+		printf("Failed to register message port for RELEASE IP\n");
+		exit(10);
+	}
+
+	handle = ctdb_set_message_handler_send(ctdb_connection,
+					       CTDB_SRVID_TAKE_IP,
+					       tip_h, NULL,
+					       message_handler_cb, NULL);
+	if (handle == NULL) {
+		printf("Failed to register message port for TAKE IP\n");
+		exit(10);
+	}
+
+	msg.dptr="HelloWorld";
+	msg.dsize = strlen(msg.dptr);
+
+	srvid = CTDB_SRVID_TEST_RANGE|55;
+	if (!ctdb_send_message(ctdb_connection, 0, srvid, msg)) {
+		printf("Failed to send message. Aborting\n");
+		exit(10);
+	}
+
+	handle = ctdb_getrecmaster_send(ctdb_connection, 0, rm_cb, NULL);
+	if (handle == NULL) {
+		printf("Failed to send get_recmaster control\n");
+		exit(10);
+	}
+
+	ctdb_db_context = ctdb_attachdb(ctdb_connection, "test_test.tdb",
+					false, 0);
+	if (!ctdb_db_context) {
+		printf("Failed to attach to database\n");
+		exit(10);
+	}
+
+	/*
+	 * SYNC call with callback to read the recmaster
+	 * calls the blocking sync function.
+	 * Avoid this mode for performance critical tasks
+	 */
+	if (!ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster)) {
+		printf("Failed to receive response to getrecmaster\n");
+		exit(10);
+	}
+	printf("GETRECMASTER SYNC: recmaster:%d\n", recmaster);
+
+
+	handle = ctdb_getpnn_send(ctdb_connection, CTDB_CURRENT_NODE,
+				  pnn_cb, NULL);
+	if (handle == NULL) {
+		printf("Failed to send get_pnn control\n");
+		exit(10);
+	}
+
+	/* In the non-contended case the callback might be invoked
+	 * immediately, before ctdb_readrecordlock_async() returns.
+	 * In the contended case the callback will be invoked later.
+	 *
+	 * Normally an application would not care whether the callback
+	 * has already been invoked here or not, but if the application
+	 * needs to know, it can use the *private_data pointer
+	 * to pass data through to the callback and back.
+	 */
+	if (!ctdb_readrecordlock_async(ctdb_db_context, key,
+				       rrl_cb, &rrl_cb_called)) {
+		printf("Failed to send READRECORDLOCK\n");
+		exit(10);
+	}
+	if (!rrl_cb_called) {
+		printf("READRECORDLOCK is async\n");
+	}
+
+	/*
+	 * Read the nodemap from a node (async)
+	 */
+	handle = ctdb_getnodemap_send(ctdb_connection, CTDB_CURRENT_NODE,
+				  gnm_cb, NULL);
+	if (handle == NULL) {
+		printf("Failed to send get_nodemap control\n");
+		exit(10);
+	}
+
+	/*
+	 * Read the list of public ips from a node (async)
+	 */
+	handle = ctdb_getpublicips_send(ctdb_connection, CTDB_CURRENT_NODE,
+				  ips_cb, NULL);
+	if (handle == NULL) {
+		printf("Failed to send getpublicips control\n");
+		exit(10);
+	}
+
+	/*
+	 * Read the nodemap from a node (sync)
+	 */
+	if (!ctdb_getnodemap(ctdb_connection, CTDB_CURRENT_NODE,
+			     &nodemap)) {
+		printf("Failed to receive response to getrecmaster\n");
+		exit(10);
+	}
+	printf("SYNC response to getnodemap:\n");
+	print_nodemap(nodemap);
+	ctdb_free_nodemap(nodemap);
+
+	printf("Traverse the test_test.tdb database\n");
+	ctdb_traverse_async(ctdb_db_context, traverse_callback, NULL);
+
+	for (;;) {
+
+	  pfd.events = ctdb_which_events(ctdb_connection);
+	  if (poll(&pfd, 1, -1) < 0) {
+	    printf("Poll failed");
+	    exit(10);
+	  }
+	  if (ctdb_service(ctdb_connection, pfd.revents) < 0) {
+		  err(1, "Failed to service");
+	  }
+	}
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/packaging/RPM/ctdb.spec.in
===================================================================
--- branches/ctdb/squeeze-backports/packaging/RPM/ctdb.spec.in	                        (rev 0)
+++ branches/ctdb/squeeze-backports/packaging/RPM/ctdb.spec.in	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,915 @@
+%define initdir %{_sysconfdir}/init.d
+Name: ctdb
+Summary: Clustered TDB
+Vendor: Samba Team
+Packager: Samba Team <samba at samba.org>
+Version: @VERSION@
+Release: 1
+Epoch: 0
+License: GNU GPL version 3
+Group: System Environment/Daemons
+URL: http://ctdb.samba.org/
+
+Source: ctdb-%{version}.tar.gz
+
+Prereq: /bin/mktemp /usr/bin/killall
+Prereq: fileutils sed /etc/init.d
+
+Provides: ctdb = %{version}
+
+Prefix: /usr
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+
+%description
+ctdb is the clustered database used by samba
+
+
+#######################################################################
+
+
+
+%prep
+%setup -q
+# setup the init script and sysconfig file
+%setup -T -D -n ctdb-%{version} -q
+
+%build
+
+## check for ccache
+if ccache -h >/dev/null 2>&1 ; then
+	CC="ccache gcc"
+else
+	CC="gcc"
+fi
+
+export CC
+
+## always run autogen.sh
+./autogen.sh
+
+CFLAGS="$RPM_OPT_FLAGS $EXTRA -O0 -D_GNU_SOURCE -DCTDB_VERS=\"%{version}-%{release}\"" ./configure \
+	--prefix=%{_prefix} \
+	--sysconfdir=%{_sysconfdir} \
+	--mandir=%{_mandir} \
+	--localstatedir="/var"
+
+make docdir=%{_docdir} showflags
+make docdir=%{_docdir}
+
+%install
+# Clean up in case there is trash left from a previous build
+rm -rf $RPM_BUILD_ROOT
+
+# Create the target build directory hierarchy
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/init.d
+
+make DESTDIR=$RPM_BUILD_ROOT docdir=%{_docdir} install
+
+install -m644 config/ctdb.sysconfig $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/ctdb
+install -m755 config/ctdb.init $RPM_BUILD_ROOT%{initdir}/ctdb
+
+mkdir -p $RPM_BUILD_ROOT%{_docdir}/ctdb/tests/bin
+install -m755 tests/bin/ctdb_transaction $RPM_BUILD_ROOT%{_docdir}/ctdb/tests/bin
+
+# Remove "*.old" files
+find $RPM_BUILD_ROOT -name "*.old" -exec rm -f {} \;
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+#######################################################################
+## Files section                                                     ##
+#######################################################################
+
+%files
+%defattr(-,root,root)
+
+%config(noreplace) %{_sysconfdir}/sysconfig/ctdb
+%config(noreplace) %{_sysconfdir}/ctdb/notify.sh
+%config(noreplace) %{_sysconfdir}/ctdb/ctdb-crash-cleanup.sh
+%config(noreplace) %{_sysconfdir}/ctdb/functions
+%attr(755,root,root) %{initdir}/ctdb
+
+%{_docdir}/ctdb/README.eventscripts
+%{_docdir}/ctdb/recovery-process.txt
+%{_sysconfdir}/ctdb/events.d/00.ctdb
+%{_sysconfdir}/ctdb/events.d/01.reclock
+%{_sysconfdir}/ctdb/events.d/10.interface
+%{_sysconfdir}/ctdb/events.d/13.per_ip_routing
+%{_sysconfdir}/ctdb/events.d/11.natgw
+%{_sysconfdir}/ctdb/events.d/11.routing
+%{_sysconfdir}/ctdb/events.d/20.multipathd
+%{_sysconfdir}/ctdb/events.d/31.clamd
+%{_sysconfdir}/ctdb/events.d/40.fs_use
+%{_sysconfdir}/ctdb/events.d/40.vsftpd
+%{_sysconfdir}/ctdb/events.d/41.httpd
+%{_sysconfdir}/ctdb/events.d/50.samba
+%{_sysconfdir}/ctdb/events.d/60.nfs
+%{_sysconfdir}/ctdb/events.d/60.ganesha
+%{_sysconfdir}/ctdb/events.d/62.cnfs
+%{_sysconfdir}/ctdb/events.d/70.iscsi
+%{_sysconfdir}/ctdb/events.d/91.lvs
+%{_sysconfdir}/ctdb/statd-callout
+%{_sysconfdir}/ctdb/interface_modify.sh
+%{_sbindir}/ctdbd
+%{_bindir}/ctdb
+%{_bindir}/smnotify
+%{_bindir}/ping_pong
+%{_bindir}/ltdbtool
+%{_bindir}/ctdb_diagnostics
+%{_bindir}/onnode
+%{_mandir}/man1/ctdb.1.gz
+%{_mandir}/man1/ctdbd.1.gz
+%{_mandir}/man1/onnode.1.gz
+%{_mandir}/man1/ltdbtool.1.gz
+%{_mandir}/man1/ping_pong.1.gz
+%{_libdir}/pkgconfig/ctdb.pc
+
+%{_docdir}/ctdb/tests/bin/ctdb_transaction
+
+%package devel
+Summary: CTDB developmnet libraries
+Group: Development
+
+%description devel
+development libraries for ctdb
+
+%files devel
+%defattr(-,root,root)
+%{_includedir}/ctdb.h
+%{_includedir}/ctdb_client.h
+%{_includedir}/ctdb_protocol.h
+%{_includedir}/ctdb_private.h
+%{_includedir}/ctdb_typesafe_cb.h
+%{_libdir}/libctdb.a
+
+%changelog
+* Thu Sep 1 2011 : Version 1.11
+ - Major updates.
+* Tue May 25 2010 : Version 1.10
+ - New version 1.10
+* Tue May 25 2010 : Version 1.9
+ - Lots of changes
+* Wed Mar 25 2010 : Version 1.0.114
+ - Lots of changes from Metze
+* Wed Jan 13 2010 : Version 1.0.113
+ - Incorrect use of dup2() could cause ctdb to spin eating 100% cpu.
+* Tue Jan 12 2010 : Version 1.0.112
+  - Revert the use of wbinfo --ping-dc as it is proving too unreliable.
+  - Minor testsuite changes.
+* Fri Dec 18 2009 : Version 1.0.111
+ - Fix a logging bug when an eventscript is aborted that could cause a crash.
+ - Add back cb_status that was lost in a previous commit.
+* Fri Dec 18 2009 : Version 1.0.110
+ - Metxe: fix for filedescriptor leak in the new eventscript code.
+ - Rusty: fix for a crash bug in the eventscript code.
+* Thu Dec 17 2009 : Version 1.0.109
+ - Massive eventscript updates. (bz58828)
+ - Nice the daemon instead of using realtime scheduler, also use mlockall() to
+   reduce the risk of blockign due to paging.
+ - Workarounds for valgrind when forking once for each script. Valgrind consumes
+   massive cpu when terminating the scripts on virtual systems.
+ - Sync the tdb library with upstream, and use the new TDB_DISALLOW_NESTING flag.
+ - Add new command "ctdb dumpdbbackup"
+ - Start using the new tdb check framework to validate tdb files upon startup.
+ - A new framework where we can control health for individual tdb databases.
+ - Fix a crash bug in the logging code.
+ - New transaction code for persistent databases.
+ - Various other smaller fixes.
+* Mon Dec 7 2009 : Version 1.0.108
+ - Transaction updates from Michael Adam.
+ - Use the new wbinfo --ping-dc instead of -p in the eventscript for samba
+   the check if winbindd is ok.
+ - Add a better "process-exist" for samba so it will automatically
+   reap smbd's on stopped and banned nodes to reclaim subrecords.
+   This will be done a bit differently in the next release.
+ - Use a statically allocated buffer for the 'first-time' capture buffer
+   to reduce the pressure on malloc/free.
+* Wed Dec 2 2009 : Version 1.0.107
+ - fix for rusty to solve a double-free that can happen when there are
+   multiple packets queued and the connection is destroyed before
+   all packets are processed.
+* Tue Dec 1 2009 : Version 1.0.106
+ - Buildscript changes from Michael Adam
+ - Dont do a full recovery when there is a mismatch detected for ip addresses,
+   just do a less disruptive ip-reallocation
+ - When starting ctdbd, wait until all initial recoveries have finished 
+   before we issue the "startup" event.
+   So dont start services or monitoring until the cluster has
+   stabilized.
+ - Major eventscript overhaul by Ronnie, Rusty and Martins and fixes of a few
+   bugs found.
+* Thu Nov 19 2009 : Version 1.0.105
+ - Fix a bug where we could SEGV if multiple concurrent "ctdb eventscript ..."
+   are used and some of them block.
+ - Monitor the daemon from the syslog child process so we shutdown cleanly when
+   the main daemon terminates.
+ - Add a 500k line ringbuffer in memory where all log messages are stored.
+ - Add a "ctdb getlog <level>" command to pull log messages from the in memory
+   ringbuffer.
+ - From martin : fixes to cifs and nfs autotests
+ - from michael a : fix a bashism in 11.natgw
+* Fri Nov 6 2009 : Version 1.0.104
+ - Suggestion from Metze, we can now use killtcp to kill local connections
+   for nfs so change the killtcp script to kill both directions of an NFS
+   connection.
+   We used to deliberately only kill one direction in these cases due to
+   limitations.
+ - Suggestion from christian Ambach, when using natgw, try to avoid using a
+   UNHEALTHY node as the natgw master.
+ - From Michael Adam: Fix a SEGV bug in the recent change to the eventscripts
+   to allow the timeout to apply to each individual script.
+ - fix a talloc bug in teh vacuuming code that produced nasty valgrind
+   warnings.
+ - From Rusty: Set up ulimit to create core files for ctdb, and spawned
+   processes by default. This is useful for debugging and testing but can be
+   disabled by setting CTDB_SUPRESS_COREFILE=yes in the sysconfig file.
+ - Remove the wbinfo -t check from the startup check that winbindd is happy.
+ - Enhance the test for bond devices so we also check if the sysadmin have
+   disabled all slave devices using "ifdown".
+* Tue Nov 3 2009 : Version 1.0.103
+ - Dont use vacuuming on persistent databases
+ - Michael A : transaction updates to persistent databases
+ - Dont activate service automatically when installing the RPM. Leave this to the admin.
+ - Create a child process to send all log messages to, to prevent a hung/slow syslogd
+   from blocking the main daemon. In this case, discard log messages instead and let the child
+   process block.
+ - Michael A: updates to log messages
+* Thu Oct 29 2009 : Version 1.0.102
+ - Wolfgang: fix for the vacuuming code
+ - Wolfgang: stronger tests for persistent database filename tests
+ - Improve the log message when we refuse to startup since wbinfo -t fails
+   to make it easier to spot in the log.
+ - Update the uptime command output and the man page to indicate that
+   "time since last ..." if from either the last recovery OR the last failover
+ - Michael A: transaction updates
+* Wed Oct 28 2009 : Version 1.0.101
+ - create a separate context for non-monitoring events so they dont interfere with the monitor event
+ - make sure to return status 0 in teh callback when we abort an event
+* Wed Oct 28 2009 : Version 1.0.100
+ - Change eventscript handling to allow EventScriptTimeout for each individual script instead of for all scripts as a whole.
+ - Enhanced logging from the eventscripts, log the name and the duration for each script as it finishes.
+ - Add a check to use wbinfo -t for the startup event of samba
+ - TEMP: allow clients to attach to databases even when teh node is in recovery mode
+ - dont run the monitor event as frequently after an event has failed
+ - DEBUG: in the eventloops, check the local time and warn if the time changes backward or rapidly forward
+ - From Metze, fix a bug where recovery master becoming unhealthy did not trigger an ip failover.
+ - Disable the multipath script by default
+ - Automatically re-activate the reclock checking if the reclock file is specified at runtime. Update manpage to reflect this.
+ - Add a mechanism where samba can register a SRVID and if samba unexpectedly disconnects, a message will be broadcasted to all other samba daemons.
+ - Log the pstree on hung scripts to a file in /tmp isntead of /var/log/messages
+ - change ban count before unhealthy/banned to 10
+* Thu Oct 22 2009 : Version 1.0.99
+ - Fix a SEGV in the new db priority code.
+ - From Wolfgang : eliminate a ctdb_fatal() if there is a dmaster violation detected.
+ - During testing we often add/delete eventscripts at runtime. This could cause an eventscript to fail and mark the node unhealthy if an eventscript was deleted while we were listing the names. Handle the errorcode and make sure the node does not becomne unhealthy in this case.
+ - Lower the debuglevel for the messages when ctdb creates a filedescruiptor so we dont spam the logs with these messages.
+ - Dont have the RPM automatically restart ctdb
+ - Volker : add a missing transaction_cancel() in the handling of persistent databases
+ - Treat interfaces with the anme ethX* as bond devices in 10.interfaces so we do the correct test for if they are up or not.
+* Tue Oct 20 2009 : Version 1.0.98
+ - Fix for the vacuuming database from Wolfgang M
+ - Create a directory where the test framework can put temporary overrides
+   to variables and functions.
+ - Wait a lot longer before shutting down the node when the reclock file
+   is incorrectly configured, and log where it is configured.
+ - Try to avoid running the "monitor" event when databases are frozen.
+ - Add logging for every time we create a filedescriptor so we can trap
+   fd leaks.
+* Thu Oct 14 2009 : Version 1.0.97
+ - From martins : update onnode.
+   Update onnode to allow specifying an alternative nodes file from
+   the command line and also to be able to specify hostnames on the
+   list of targets :
+   onnode host1,host2,...   
+* Tue Oct 13 2009 : Version 1.0.96
+ - Add more debugging output when eventscripts have trouble. Print a 
+   "pstree -p" to the log when scripts have hung.
+ - Update the initscript,  only print the "No reclock file used" warning
+   when we do "service ctdb start", dont also print them for all other
+   actions.
+ - When changing between unhealthy/healthy state, push a request to the
+   recovery master to perform an ip reallocation   instead of waiting for the
+   recovery master to pull and check the state change.
+ - Fix a bug in the new db-priority handling where a pre-.95 recovery master
+   could no longer lock the databases on a post-.95 daemon.
+ - Always create the nfs state directories during the "monitor" event.
+   This makes it easier to configure and enable nfs at runtime.
+ - From Volker, forward-port a simper deadlock avoiding patch from the 1.0.82
+   branch. This is a simpler versionof the "db priority lock order" patch
+   that went into 1.0.95, and will be kept for a few versions until samba
+   has been updated to use the functionality from 1.0.95.
+* Mon Oct 12 2009 : Version 1.0.95
+ - Add database priorities. Allow samba to set the priority of databases
+   and lock the databases in priority order during recovery
+   to avoid a deadlock when samba locks one database then blocks indefinitely
+   while waiting for the second databaso to become locked.
+ - Be aggressive and ban nodes where the recovery transaction start call
+   fails.
+* Thu Oct 10 2009 : Version 1.0.94
+ - Be very aggressive and quickly ban nodes that can not freeze their databases
+* Tue Oct 8 2009 : Version 1.0.93
+ - When adding an ip, make sure to update this assignment on all nodes
+   so it wont show up as -1 on other nodes.
+ - When adding an ip and immediately deleting it, it was possible that
+   the daemon would crash accessing already freed memory.
+   Readjust the memory hierarchy so the destructors are called in the right order.
+ - Add a handshake to the recovery daemon to eliminate some rare cases where
+   addip/delip might cause a recovery to occur.
+ - updated onnode documenation from Martin S
+ - Updates to the natgw eventscript to allow disabling natgw at runtime
+* Fri Oct 2 2009 : Version 1.0.92
+ - Test updates and merge from martin
+ - Add notification for "startup"
+ - Add documentation for notification
+ - from martin, a fix for restarting vsftpd in the eventscript
+* Tue Sep 29 2009 : Version 1.0.91
+ - New vacuum and repack design from Wolgang Mueller.
+ - Add a new eventscript 01.reclock that will first mark a node unhealthy and later ban the node if the reclock file can not be accessed.
+ - Add machinereadable output to the ctdb getreclock command
+ - merge transaction updates from Michael Adam
+ - In the new banning code, reset the culprit count to 0 for all nodes that could successfully compelte a full recovery.
+ - dont mark the recovery master as a ban culprit because a node in the cluster needs a recovery. this happens naturally when using ctdb recover command so dont make this cause a node to be banned.
+* Sat Sep 12 2009 : Version 1.0.90
+ - Be more forgiving for eventscripts that hang during startup
+ - Fix for a banning bug in the new banning logic
+* Thu Sep 3 2009 : Version 1.0.89
+ - Make it possible to manage winbind independently of samba.
+ - Add new prototype banning code
+ - Overwrite the vsftpd state file instead of appending. This eliminates
+   annoying errors in the log.
+ - Redirect some iptables commands to dev null
+ - From Michael A, explicitely set the broadcast when we takeover a public ip
+ - Remove a reclock file check we no longer need
+ - Skip any persistent database files ending in .bak
+* Mon Aug 17 2009 : Version 1.0.88
+ - Add a new state for eventscripts : DISABLED.
+   Add two new commands "ctdb enablescript/disablescript" to enable/disable
+   eventscripts at runtime.
+ - Bugfixes for TDB from rusty.
+ - Merge/Port changes from upstream TDB library by rusty.
+ - Additional new tests from MartinS. Tests for stop/continue.
+ - Initial patch to rework vacuuming/repacking process from Wolfgang Mueller.
+ - Updates from Michael Adam for persistent writes.
+ - Updates from MartinS to handle the new STOPPED bit in the test framework.
+ - Make it possible to enable/disable the RECMASTER and LMASTER roles
+   at runtime. Add two new commands 
+   "ctdb setlmasterrole/setrecmasterrole on/off"
+ - Make it possible to enable/disable the natgw feature at runtime. Add
+   the command "ctdb setnatgwstate on/off"
+* Fri Jul 17 2009 : Version 1.0.87
+ - Add a new event "stopped" that is called when a node is stopped.
+ - Documentation of the STOPPED flag and the stop/continue commands
+ - Make it possible to start a node in STOPPED mode.
+ - Add a new node flag : STOPPED and commands "ctdb stop" "ctdb continue"
+   These commands are similar to "diasble/enable" but will also remove the node from the vnnmap, while disable only fails all ip addresses over.
+ - tests for NFS , CIFS by martins
+ - major updates to the init script by martins
+ - Send gratious arps with a 1.1 second stride instead of a 1 second stride to workaround interesting "features" of common linux stacks.
+ - Various test enhancements from martins:
+   - additional other tests
+   - add tests for grat arp generation, ping during failover, ssh and failover
+   - New/updated tcp tickle tests and supprot functions
+   - provide better debugging when a test fails
+   - make ctdbd restarts more reliable in the tests
+   - update the "wait bar" to  make the wait progress in tests more obvious
+   - various cleanups
+ - when dispatching a message to a handler, make the message a real talloc object so that we can reparent the object in the tallic hierarchy.
+ - document the ipreallocate command
+ - Updates to enable/disable to use the ipreallocate command to block until the following ipreallocation has completed.
+ - Update the main daemon and the tools to allow debug level to be a string instead of an integer.
+ - Update the sysconfig file to show using string literals instead of numeric values for the debuglevels used.
+ - If no debuglevel is specific, make "ctdb setdebug" show the available options.
+ - When trying to allocate network packets, add explicit checks if the network transport has been shutdown before trying and failing, to make log messages easier to read. Add this extra check and logging to every plave packets are allocated.
+* Tue Jun 30 2009 : Version 1.0.86
+ - Do not access the reclock at all if VerifyRecoveryLock is zero, not even try to probe it.
+ - Allow setting the reclock file as "", which means that no reclock file at all should be used.
+ - Document that a reclock file is no longer required, but that it is dangerous.
+ - Add a control that can be used to set/clear/change the reclock file in the daemon during runtime.
+ - Update the recovery daemon to poll whether a reclock file should be sued and if so which file at runtime in each monitoring cycle.
+ - Automatically disable VerifyRecoveryLock everytime a user changes the location of the reclock file.
+ - do not allow the VerifyRecoveryLock to be set using ctdb setvar if there is no recovery lock file specified.
+ - Add two commands "ctdb getreclock" and "ctdb setreclock" to modify the reclock file.
+* Tue Jun 23 2009 : Version 1.0.85
+ - From William Jojo : Dont use getopt on AIX
+ - Make it possible to use "ctdb listnodes" also when the daemon is not running
+ - Provide machinereadable output to "ctdb listnodes"
+ - Dont list DELETED nodes in the ctdb listnodes output
+ - Try to avoid causing a recovery for the average case when adding/deleting/moving an ip
+ - When banning a node, drop the IPs on that node only and not all nodes.
+ - Add tests for NFS and CIFS tickles
+ - Rename 99.routing to 11.routing so it executes before NFS and LVS scripts
+ - Increase the default timeout before we deem an unresponsive recovery daemon hung and shutdown
+ - Reduce the reclock timout to 5 seconds
+ - Spawn a child process in the recovery daemon ot check the reclock file to
+   avoid blocking the process if the underlying filesystem is unresponsive
+ - fix for filedescriptor leak when a child process timesout
+ - Dont log errors if waitpid() returns -1
+ - Onnode updates by Martins
+ - Test and initscript cleanups from Martin S
+* Tue Jun 2 2009 : Version 1.0.84
+ - Fix a bug in onnode that could not handle dead nodes
+* Tue Jun 2 2009 : Version 1.0.83
+ - Document how to remove a ndoe from a running cluster.
+ - Hide all deleted nodes from ctdb output.
+ - Lower the loglevel on some eventscript related items
+ - Dont queue packets to deleted nodes
+ - When building initial vnnmap, ignode any nonexisting nodes
+ - Add a new nodestate : DELETED that is used when deleting a node from an
+   existing cluster.
+ - dont remove the ctdb socket when shutting down. This prevents a race in the
+   initscripts when restarting ctdb quickly after stopping it.
+ - TDB nesting reworked.
+ - Remove obsolete ipmux
+ - From Flavio Carmo Junior: Add eventscript and documentation for ClamAV antivirus engine
+ - From Sumit Bose: fix the regex in the test to handle the new ctdb
+   statistics output that was recently added.
+ - change the socket type we use for grauitious arps from the obsolete
+   AF_INET/SOCK_PACKET to instead use PF_PACKET/SOCK_RAW.
+ - Check return codes for some functions, from Sumit Bose, based on codereview by Jim Meyering.
+ - Sumit Bose: Remove structure memeber node_list_file that is no longer used.
+ - Sumit Bose: fix configure warning for netfilter.h
+ - Updates to the webpages by Volker.
+ - Remove error messages about missing /var/log/log.ctdb file from ctdb_diagnostics.sh from christian Ambach
+ - Additional error logs if hte eventscript switching from dameon to client mode fails.
+ - track how long it takes for ctdbd and the recovery daemon to perform the rec-lock fcntl() lock attemt and show this in the ctdb statistics output.
+* Thu May 14 2009 : Version 1.0.82
+ - Update the "ctdb lvsmaster" command to return -1 on error.
+ - Add a -Y flag to "ctdb lvsmaster"
+ - RHEL5 apache leaks semaphores when crashing. Add semaphore cleanup to the 
+   41.httpd eventscript and try to restart apache when it has crashed.
+ - Fixes to some tests
+ - Add a -o option to "onnode" which will redirect all stdout to a file for
+   each of the nodes.
+ - Add a natgw and a lvs node specifier to onnode so that we can use 
+   "onnode natgw ..."
+ - Assign the natgw address to lo instead of the private network so it can also
+   be used where private and public networks are the same.
+ - Add GPL boilerplates to two missing scripts.
+ - Change the natgw prefix NATGW_ to CTDB_NATGW_
+* Fri May 8 2009 : Version 1.0.81
+ - use smbstatus -np instead of smbstatus -n in the 50.samba eventscript 
+   since this avoids performing an expensive traverse on the locking and brlock
+   databases.
+ - make ctdb automatically terminate all traverse child processes clusterwide
+   associated to a client application that terminates before the traversal is
+   completed.
+ - From Sumit Bose : fixes to AC_INIT handling.
+ - From Michael Adam, add Tridge's "ping_pong" tool the the ctdb distro since 
+   this is very useful for testing the backend filesystem.
+ - From Sumit bose, add support for additional 64 bit platforms.
+ - Add a link from the webpage to Michael Adams SambaXP paper on CTDB.
+* Fri May 1 2009 : Version 1.0.80
+ - change init shutdown level to 01 for ctdb so it stops before any of the other services
+ - if we can not pull a database from a remote node during recovery, mark that node as a culprit so it becomes banned
+ - increase the loglevel when we volunteer to drop all ip addresses after beeing in recovery mode for too long. Make this timeout tuneable with "RecoveryDropAllIPs" and have it default to 60 seconds
+ - Add a new flag TDB_NO_NESTING to the tdb layer to prevent nested transactions which ctdb does not use and does not expect. Have ctdb set this flag to prevent nested transactions from occuring.
+ - dont unconditionally kill off ctdb and restrat it on "service ctdb start". Fail "service ctdb start" with an error if ctdb is already running.
+ - Add a new tunable "VerifyRecoveryLock" that can be set to 0 to prevent the main ctdb daemon to verify that the recovery master has locked the reclock file correctly before allowing it to set the recovery mode to active.
+ - fix a cosmetic bug with ctdb statistics where certain counters could become negative.
+* Wed Apr 8 2009 : Version 1.0.79
+ - From Mathieu Parent: add a ctdb pkgconfig file
+ - Fix bug 6250
+ - add a funciton remove_ip to safely remove an ip from an interface, taking care to workaround an issue with linux alias interfaces.
+ - Update the natgw eventscript to use the safe remove_ip() function
+ - fix a bug in the eventscript child process that would cause the socket to be removed.
+ - dont verify nodemap on banned nodes during cluster monitoring
+ - Update the dodgy SeqnumInterval to have ms resolution
+* Tue Mar 31 2009 : Version 1.0.78
+ - Add a notify mechanism so we can send snmptraps/email to external management systems when the node becomes unhealthy
+ - include 11.natgw eventscript in thew install so that the NATGW feature works
+* Tue Mar 31 2009 : Version 1.0.77
+ - Update the 99.routing eventscript to also try to add the routes (back) during a releaseip event. Similar to the reasons why we must add addresses back during releaseip in 10.interfaces
+* Wed Mar 24 2009 : Version 1.0.76
+ - Add a debugging command "xpnn" which can print the pnn of the node even when ctdbd is not running.
+ - Redo the NATGW implementation to allow multiple disjoing NATGW groups in the same cluster.
+* Tue Mar 24 2009 : Version 1.0.75
+ - Various updates to LVS
+ - Fix a bug in the killtcp control where we did not set the port correctly
+ - add a new "ctdb scriptstatus" command that shows the status of the eventrscripts.
+* Mon Mar 16 2009 : Version 1.0.74
+ - Fixes to AIX from C Cowan.
+ - Fixes to ctdb_diagnostics so we collect correct GPFS data
+ - Fixes to the net conf list command in ctdb_diagnostics
+ - Check the static-routes file IFF it exists in ctdb_diagnostics
+* Wed Mar 4 2009 : Version 1.0.73
+ - Add possibility to disable the check of shares for NFS and Samba
+ - From Sumit Bose, fix dependencies so make -j works
+* Wed Feb 18 2009 : Version 1.0.72
+ - Updates to test scripts by martin s
+ - Adding a COPYING file
+ - Use netstat to check for services and ports and fallback to netcat
+   only if netstat is unavailable.
+* Mon Feb 2 2009 : Version 1.0.71
+ - Additional ipv6 fixes from Michael Adams
+* Fri Jan 16 2009 : Version 1.0.70
+ - IPv6 support is completed. this is backward compatible with ipv4-only
+   systems. To use IPv6 with samba and ctdb you need current GIT of samba 3.3
+   or michael adams samba-ctdeb branch.
+ - Many enhancements to the build system and scripts to make it more SUSE
+   friendly by Michael Adams.
+ - Change of how the naming of the package is structured. We are now
+   using "1.0.70" as a release and "-1" as the revision instead of as
+   previously using "1.0" as release and ".70" as the revision.
+   By Michael Adams.
+* Thu Dec 18 2008 : Version 1.0.69
+ - Various fixes to scripts by M Adam
+ - Dont call ctdb_fatal() when the transport is down during shutdown
+* Fri Dec 12 2008 : Version 1.0.68
+ - Fixes for monitoring of interfaces status from Michael Adam.
+ - Use -q instead of >/dev/null for grep to enhance readability of the
+   scripts from Michael Adam.
+ - Update to the "ctdb recover" command. This command now block until the
+   has completed. This makes it much easier to use in scripts and avoids
+   the common workaround :
+      ctdb recover
+      ... loop while waiting for recovery completes ...
+      continue ...
+ - Add a CTDB_TIMEOUT variable. If set, this variable provides an automatic
+   timeout for "ctdb <command>", similar to using -T <timeout>
+ - Set a unique errorcode for "ctdb <command>" when it terminates due to a 
+   timeout so that scripts can distinguish between a hung command and what was
+   just a failure.
+ - Update "ctdb ban/unban" so that if the cluster is in recovery these commands
+   blocks and waits until after recovery is complete before the perform the
+   ban/unban operation. This is necessary since the recovery process can cause
+   nodes to become automatically unbanned.
+ - Update "ctdb ban/unban" to block until the recovery that will follow shortly
+   after this command has completed.
+   This makes it much easier to use in scripts and avoids the common
+   workaround :
+      ctdb ban/unban
+      ... loop while waiting for recovery completes ...
+      continue ...
+ - Bugfix for the new flags handling in 1.0.67. Abort and restart monitoring
+   if we failed to get proper nodemaps from a remote node instead of
+   dereferencing a null pointer.
+ - If ctdbd was explicitely started with the '--socket' argument, make
+   ctdbd automatically set CTDB_SOCKET to the specified argument.
+   This ensures that eventscripts spawned by the ctdb daemon will default to
+   using the same socket and talk to the correct daemon.
+   This primarily affects running multiple daemons on the same host and where 
+   you want each instance of ctdb daemons have their eventscripts talk to the
+   "correct" daemon.
+ - Update "ctdb ping" to return an error code if the ping fail so that it
+   can be used in scripts.
+ - Update to how to synchronize management of node flags across the cluster.
+* Thu Dec 3 2008 : Version 1.0.67
+ - Add a document describing the recovery process.
+ - Fix a bug in "ctdb setdebug" where it would refuse to set a negative
+   debug level.
+ - Print the list of literals for debug names if an invalid one was given
+   to "ctdb setdebug"
+ - Redesign how "ctdb reloadnodes" works and reduce the amont of tcp teardowns
+   used during this event.
+ - Make it possible to delete a public ip from all nodes at once using
+   "ctdb delip -n all"
+* Mon Nov 24 2008 : Version 1.0.66
+ - Allow to change the recmaster even when we are not frozen.
+ - Remove two redundant SAMBA_CHECK variables from the sysconf example
+ - After a node failure it can take very long before some lock operations
+   ctdb needs to perform are allowed/works with gpfs again. Workaround this
+   by treating a hang/timeout as success.
+ - Dont override CTDB_BASE is fet in the shell already
+ - Always send keepalive packets regardless of whether the link is idle or not.
+ - Rewrite the disable/enable flag update logic to prevent a race between 
+   "ctdb disable/enable" and the recovery daemon when updating the flags to 
+   all nodes.
+* Thu Nov 13 2008 : Version 1.0.65
+ - Update the sysconfig example: The default debug level is 2 (NOTICE) and not
+   0 (ERROR)
+ - Add support for a CTDB_SOCKET environment variable for the ctdb command
+   line tool. If set, this overrides the default socket the ctdb tool will
+   use.
+ - Add logging of high latency operations.
+* Mon Oct 22 2008 : Version 1.0.64
+ - Add a context and a timed event so that once we have been in recovery for
+   too long we drop all public addresses.
+* Mon Oct 20 2008 : Version 1.0.63
+ - Remove logging of "periodic cleanup ..." in 50.samba
+ - When we reload a nodes file, we must detect this and reload the file also
+   in the recovery daemon before we try to dereference somethoung beyond the end
+   of the nodes array.
+* Thu Oct 16 2008 : Version 1.0.62
+ - Allow multiple eventscritps using the same prefix number.
+   It is undefined which order scripts with the same prefix will execute in.
+* Wed Oct 15 2008 : Version 1.0.61
+ - Use "route add -net" instead of "ip route add" when adding routes in 99.routing
+ - lower the loglevel os several debug statements
+ - check the status returned from ctdb_ctrl_get_tickles() before we try to print them out to the screen.
+ - install a new eventscript 20.multipathd whoich can be used to monitor that multipath devices are healthy
+* Wed Oct 15 2008 : Version 1.0.60
+ - Verify that nodes we try to ban/unban are reachable and print an error othervise.
+ - Update the client and server sides of TAKEIP/RELEASEIP/GETPUBLICIPS and GETNODEMAP to fall back to the old style ipv4-only controls if the new ipv4/ipv6 controls fail. This allows an ipv4/v6 enabled ctdb daemon to interoperate with earlier ipv4-only versions of the daemons.
+ - From Mathieu Parent : log debian systems log the package versions in ctdb diagnostics
+ - From Mathieu Parent : specify logdir location for debian (this patch was later reversed)
+ - From Michael Adams : allow # comments in nodes/public_addresses files
+* Tue Oct 7 2008 : Version 1.0.59
+ - Updated "reloadnodes" logic. Instead of bouncing the entire tcp layer it is sufficient to just close and reopen all outgoing tcp connections.
+ - New eventscript 99.routing which can be used to re-attach routes to public interfaces after a takeip event. (routes may be deleted by the kernel when we release an ip)
+ - IDR tree fix from Jim Houston
+ - Better handling of critical events if the local clock is suddenly changed forward by a lot.
+ - Fix three slow memory leaks in the recovery daemon
+ - New ctdb command : ctdb recmaster   which prints the pnn of the recmaster
+ - Onnode enhancements from Martin S : "healthy" and "connected" are now possible nodespecifiers
+ - From Martin S : doc fixes
+ - lowering some debug levels for some nonvital informational messages
+ - Make the daemon daemon monitoring stronger and allow ctdbd to detect a hung
+   recovery daemon.
+ - From C Cowan : patches to compile ipv6 under AIX
+ - zero out some structs to keep valgrind happy
+* Wed Aug 27 2008 : Version 1.0.58
+ - revert the name change tcp_tcp_client back to tcp_control_tcp so
+   samba can build.
+ - Updates to the init script from Abhijith Das <adas at redhat.com>
+* Mon Aug 25 2008 : Version 1.0.57
+ - initial support for IPv6
+* Mon Aug 11 2008 : Version 1.0.56
+ - fix a memory leak in the recovery daemon.
+* Mon Aug 11 2008 : Version 1.0.55
+ - Fix the releaseip message we seond to samba.
+* Fri Aug 8 2008 : Version 1.0.54
+ - fix a looping error in the transaction code
+ - provide a more detailed error code for persistent store errors
+   so clients can make more intelligent choices on how to try to recover
+* Thu Aug 7 2008 : Version 1.0.53
+ - Remove the reclock.pnn file   it can cause gpfs to fail to umount
+ - New transaction code
+* Mon Aug 4 2008 : Version 1.0.52
+ - Send an explicit gratious arp when starting sending the tcp tickles.
+ - When doing failover, issue a killtcp to non-NFS/non-CIFS clients
+   so that they fail quickly. NFS and CIFS already fail and recover 
+   quickly.
+ - Update the test scripts to handle CTRL-C to kill off the test.
+* Mon Jul 28 2008 : Version 1.0.51
+ - Strip off the vlan tag from bond devices before we check in /proc
+   if the interface is up or not.
+ - Use testparm in the background in the scripts to allow probing
+   that the shares do exist.
+ - Fix a bug in the logging code to handle multiline entries better
+ - Rename private elements from private to private_data
+* Fri Jul 18 2008 : Version 1.0.50
+ - Dont assume that just because we can establish a TCP connection
+   that we are actually talking to a functioning ctdb daemon.
+   So dont mark the node as CONNECTED just because the tcp handshake
+   was successful.
+ - Dont try to set the recmaster to ourself during elections for those
+   cases we know this will fail. To remove some annoying benign but scary
+   looking entries from the log.
+ - Bugfix for eventsystem for signal handling that could cause a node to
+   hang.
+* Thu Jul 17 2008 : Version 1.0.49
+ - Update the safe persistent update fix to work with unpatched samba
+   servers.
+* Thu Jul 17 2008 : Version 1.0.48
+ - Update the spec file.
+ - Do not start new user-triggered eventscripts if we are already
+   inside recovery mode.
+ - Add two new controls to start/cancel a persistent update.
+   A client such as samba can use these to tell ctdbd that it will soon
+   be writing directly to the persistent database tdb file. So if
+   samba is -9ed before it has eitehr done the persistent_store or
+   canceled the operation, ctdb knows that the persistent databases
+   'may' be out of sync and therefore a full blown recovery is called for.
+ - Add two new options :
+   CTDB_SAMBA_SKIP_CONF_CHECK and CTDB_SAMBA_CHECK_PORTS that can be used
+   to override what checks to do when monitoring samba health.
+   We can no longer use the smbstatus, net or testparm commands to check
+   if samba or its config is healthy since these commands may block
+   indefinitely and thus can not be used in scripts.
+* Fri Jul 11 2008 : Version 1.0.47
+ - Fix a double free bug where if a user striggered (ctdb eventscript)
+   hung and while the timeout handler was being processed a new user
+   triggered eventscript was started we would free state twice.
+ - Rewrite of onnode and associated documentation.
+* Thu Jul 10 2008 : Version 1.0.46
+ - Document both the LVS:cingle-ip-address and the REMOTE-NODE:wan-accelerator
+   capabilities.
+ - Add commands "ctdb pnn", "ctdb lvs", "ctdb lvsmaster".
+ - LVS improvements. LVS is the single-ip-address mode for a ctdb cluster.
+ - Fixes to supress rpmlint warnings
+ - AXI compile fixes.
+ - Change \s to [[:space:]] in some scripts. Not all RHEL5 packages come
+   with a egrep that handles \s   even same version but different arch.
+ - Revert the change to NFS restart. CTDB should NOT attempt to restart
+   failed services.
+ - Rewrite of the waitpid() patch to use the eventsystem for handling
+   signals.
+* Tue Jul 8 2008 : Version 1.0.45
+ - Try to restart the nfs service if it has failed to respond 3 times in a row.
+ - waitpid() can block if the child does not respond promptly to SIGTERM.
+   ignore all SIGCHILD signals by setting SIGCHLD to SIG_DEF.
+   get rid of all calls to waitpid().
+ - make handling of eventscripts hanging more liberal.
+   only consider the script to have failed and making the node unhealthy
+   IF the eventscript terminated wiht an error
+   OR the eventscript hung 5 or more times in a row
+* Mon Jul 7 2008 : Version 1.0.44
+ - Add a CTDB_VALGRIND option to /etc/sysconfig/ctdb to make it start
+   ctdb under valgrind. Logs go to /var/log/ctdb_valgrind.PID
+ - Add a hack to show the control opcode that caused uninitialized data
+   in the valgrind output by encoding the opcode as the line number.
+ - Initialize structures and allocated memory in various places in
+   ctdb to make it valgrind-clean and remove all valgrind errors/warnings.
+ - If/when we destroy a lockwait child, also make sure we cancel any pending transactions
+ - If a transaction_commit fails, delete/cancel any pending transactions and
+   return an error instead of calling ctdb_fatal()
+ - When running ctdb under valgrind, make sure we run it with --nosetsched and also
+   ensure that we do not use mem-mapped i/o when accessing the tdb's.
+ - zero out ctdb->freeze_handle when we free/destroy a freeze-child.
+   This prevent a heap corruption/ctdb crash bug that could trigger
+   if the freeze child times out.
+ - we dont need to explicitely thaw the databases from the recovery daemon
+   since this is done implicitely when we restore the recovery mode back to normal.
+ - track when we start and stop a recovery. Add the 'time it took to complete the
+   recovery' to the 'ctdb uptime' output.
+   Ensure by tracking the start/stop recovery timestamps that we do not
+   check that the ip allocation is consistend from inside the recovery daemon
+   while a different node (recovery master) is performing a recovery.
+   This prevent a race that could cause a full recovery to trigger if the
+   'ctdb disable/enable' commands took very long.
+ - The freeze child indicates to the master daemon that all databases are locked
+   by writing data to the pipe shared with the master daemon.
+   This write sometimes fail and thus the master daemon never notices that the databases
+   are locked cvausing long timeouts and extra recoveries.
+   Check that the write is successful and try the write again if it failed.
+ - In each node, verify that the recmaster have the right node flags for us
+   and force a push of our flags to the recmaster if wrong.
+* Tue Jul 1 2008 : Version 1.0.43
+ - Updates and bugfixes to the specfile to keep rpmlint happy
+ - Force a global flags update after each recovery event.
+ - Verify that the recmaster agrees with our node flags and update the
+   recmaster othervise.
+ - When writing back to the parent from a freeze-child across the pipe,
+   loop over the write in case the write failed with an error  othervise
+   the parent will never be notified tha the child has completed the operation.
+ - Automatically thaw all databases when recmaster marks us as being in normal
+   mode instead of recovery mode.
+* Fri Jun 13 2008 : Version 1.0.42
+ - When event scripts have hung/timedout more than EventScriptBanCount times
+   in a row the node will ban itself.
+ - Many updates to persistent write tests and the test scripts.
+* Wed May 28 2008 : Version 1.0.41
+ - Reactivate the safe writes to persistent databases and solve the
+   locking issues. Locking issues are solved the only possible way,
+   by using a child process to do the writes.  Expensive and slow but... . 
+* Tue May 27 2008 : Version 1.0.40
+ - Read the samba sysconfig file from the 50.samba eventscript
+ - Fix some emmory hierarchical bugs in the persistent write handling
+* Thu May 22 2008 : Version 1.0.39
+ - Moved a CTDB_MANAGES_NFS, CTDB_MANAGES_ISCSI and CTDB_MANAGES_CSFTPD
+   into /etc/sysconfig/ctdb
+ - Lowered some debug messages to not fill the logfile with entries
+   that normally occur in the default configuration.
+* Fri May 16 2008 : Version 1.0.38
+ - Add machine readable output support to "ctdb getmonmode"
+ - Lots of tweaks and enhancements if the event scripts are "slow"
+ - Merge from tridge: an attempt to break the chicken-and-egg deadlock that
+   net conf introduces if used from an eventscript.
+ - Enhance tickles so we can tickle an ipv6 connection.
+ - Start adding ipv6 support : create a new container to replace sockaddr_in.
+ - Add a checksum routine for ipv6/tcp
+ - When starting up ctdb, let the init script do a tdbdump on all
+   persistent databases and verify that they are good (i.e. not corrupted).
+ - Try to use "safe transactions" when writing to a persistent database
+   that was opened with the TDB_NOSYNC flag. If we can get the transaction
+   thats great, if we cant  we have to write anyway since we cant block here.
+* Mon May 12 2008 : Version 1.0.37
+ - When we shutdown ctdb we close the transport down before we run the 
+   "shutdown" eventscripts. If ctdb decides to send a packet to a remote node
+   after we have shutdown the transport but before we have shutdown ctdbd
+   itself this could lead to a SEGV instead of a clean shutdown. Fix.
+ - When using the "exportfs" command to extract which NFS export directories
+   to monitor,  exportfs violates the "principle of least surprise" and
+   sometimes report a single export line as two lines of text output
+   causing the monitoring to fail.
+* Fri May 9 2008 : Version 1.0.36
+ - fix a memory corruption bug that could cause the recovery daemon to crash.
+ - fix a bug with distributing public ip addresses during recovery.
+   If the node that is the recovery master did NOT use public addresses,
+   then it assumed that no other node in the cluster used them either and
+   thus skipped the entire step of reallocating public addresses.
+* Wed May 7 2008 : Version 1.0.35
+ - During recovery, when we define the new set of lmasters (vnnmap)
+   only consider those nodes that have the can-be-lmaster capability
+   when we create the vnnmap. unless there are no nodes available which
+   supports this capability in which case we allow the recmaster to
+   become lmaster capable (temporarily).
+ - Extend the async framework so that we can use paralell async calls
+   to controls that return data.
+ - If we do not have the "can be recmaster" capability, make sure we will
+   lose any recmaster elections, unless there are no nodes available that
+   have the capability, in which case we "take/win" the election anyway.
+ - Close and reopen the reclock pnn file at regular intervals.
+   Make it a non-fatal event if we occasionally fail to open/read/write
+   to this file.
+ - Monitor that the recovery daemon is still running from the main ctdb
+   daemon and shutdown the main daemon when recovery daemon has terminated.
+ - Add a "ctdb getcapabilities" command to read the capabilities off a node.
+ - Define two new capabilities : can be recmaster and can be lmaster
+   and default both capabilities to YES.
+ - Log denied tcp connection attempts with DEBUG_ERR and not DEBUG_WARNING
+* Thu Apr 24 2008 : Version 1.0.34
+ - When deleting a public ip from a node, try to migrate the ip to a different
+   node first.
+ - Change catdb to produce output similar to tdbdump
+ - When adding a new public ip address, if this ip does not exist yet in
+   the cluster, then grab the ip on the local node and activate it.
+ - When a node disagrees with the recmaster on WHO is the recmaster, then
+   mark that node as a recovery culprit so it will eventually become
+   banned.
+ - Make ctdb eventscript support the -n all argument.
+* Thu Apr 10 2008 : Version 1.0.33
+ - Add facilities to include site local adaptations to the eventscript
+   by /etc/ctdb/rc.local which will be read by all eventscripts.
+ - Add a "ctdb version" command.
+ - Secure the domain socket with proper permissions from Chris Cowan
+ - Bugfixes for AIX from Chris Cowan
+* Wed Apr 02 2008 : Version 1.0.32
+ - Add a control to have a node execute the eventscripts with arbitrary
+   command line arguments.
+ - Add a control "rddumpmemory" that will dump the talloc memory allocations
+   for the recovery daemon.
+ - Decorate the talloc memdump to produce better and easier memory leak
+   tracking. 
+ - Update the RHEL5 iscsi tgtd scripts to allow one iscsi target for each
+   public address.
+ - Add two new controls "addip/delip" that can be used to add/remove public
+   addresses to a node at runtime. After using these controls a "ctdb recover"
+   ir required to make the changes take.
+ - Fix a couple of slow memory leaks.
+* Tue Mar 25 2008 : Version 1.0.31
+ - Add back controls to disable/enable monitoring on a node.
+ - Fix a memory leak where we used to attach CALL data to the ctdb structure
+   when performing a local call. Memory which would be lost if the call was
+   aborted.
+ - Reduce the loglevel for the log output when someone connects to a non
+   public ip address for samba.
+ - Redo and optimize the vacuuming process to send only one control to each
+   other node containing all records to be vacuumed instead of one
+   control per node per record.
+* Tue Mar 04 2008 : Version 1.0.30
+ - Update documentation cor new commands and tuneables
+ - Add machinereadable output to the ip,uptime and getdebug commands
+ - Add a moveip command to manually failover/failback public ips
+ - Add NoIPFallback tuneable that prevents ip address failback
+ - Use file locking inside the CFS as alternative to verify when other nodes
+   Are connected/disconnected to be able to recover from split network
+ - Add DisableWhenUnhealthy tunable
+ - Add CTDB_START_AS_DISABLED sysconfig param
+ - Add --start-as-disabled flag to ctdb
+ - Add ability to monitor for OOM condition
+* Thu Feb 21 2008 : Version 1.0.29
+ - Add a new command to make expansion of an existing cluster easier
+ - Fix bug with references to freed objects in the ctdb structure
+ - Propagate debuglevel changes to the recovery daemon
+ - Merge patches to event scripts from Mathieu Parent :
+ - MP: Simulate "service" on systems which do not provide this tool
+ - MP: Set correct permissions for events.d/README
+ - Add nice helper functions to start/stop nfs from the event scripts
+* Fri Feb 08 2008 : Version 1.0.28
+ - Fix a problem where we tried to use ethtool on non-ethernet interfaces
+ - Warn if the ipvsadm packege is missing when LVS is used
+ - Dont use absolute pathnames in some of the event scripts
+ - Fix for persistent tdbs growing inifinitely.
+* Wed Feb 06 2008 : Version 1.0.27
+ - Add eventscript for iscsi
+* Thu Jan 31 2008 : Version 1.0.26
+ - Fix crashbug in tdb transaction code
+* Tue Jan 29 2008 : Version 1.0.25
+ - added async recovery code
+ - make event scripts more portable
+ - fixed ctdb dumpmemory
+ - more efficient tdb allocation code
+ - improved machine readable ctdb status output
+ - added ctdb uptime
+* Wed Jan 16 2008 : Version 1.0.24
+ - added syslog support
+ - documentation updates
+* Wed Jan 16 2008 : Version 1.0.23
+ - fixed a memory leak in the recoveryd
+ - fixed a corruption bug in the new transaction code
+ - fixed a case where an packet for a disconnected client could be processed
+ - added http event script
+ - updated documentation
+* Thu Jan 10 2008 : Version 1.0.22
+ - auto-run vacuum and repack ops
+* Wed Jan 09 2008 : Version 1.0.21
+ - added ctdb vacuum and ctdb repack code
+* Sun Jan 06 2008 : Version 1.0.20
+ - new transaction based recovery code
+* Sat Jan 05 2008 : Version 1.0.19
+ - fixed non-master bug
+ - big speedup in recovery for large databases
+ - lots of changes to improve tdb and ctdb for high churn databases
+* Thu Dec 27 2007 : Version 1.0.18
+ - fixed crash bug in monitor_handler
+* Tue Dec 04 2007 : Version 1.0.17
+ - fixed bugs related to ban/unban of nodes
+ - fixed a race condition that could lead to monitoring being permanently disabled,
+   which would lead to long recovery times
+ - make deterministic IPs the default
+ - fixed a bug related to continuous recovery 
+ - added a debugging option --node-ip

Added: branches/ctdb/squeeze-backports/packaging/RPM/makerpms.sh
===================================================================
--- branches/ctdb/squeeze-backports/packaging/RPM/makerpms.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/packaging/RPM/makerpms.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,123 @@
+#!/bin/sh
+#
+# makerpms.sh  -  build RPM packages from the git sources
+#
+# Copyright (C) John H Terpstra 1998-2002
+# Copyright (C) Gerald (Jerry) Carter 2003
+# Copyright (C) Jim McDonough 2007
+# Copyright (C) Andrew Tridgell 2007
+# Copyright (C) Michael Adam 2008-2009
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# The following allows environment variables to override the target directories
+#   the alternative is to have a file in your home directory calles .rpmmacros
+#   containing the following:
+#   %_topdir  /home/mylogin/redhat
+#
+# Note: Under this directory rpm expects to find the same directories that are under the
+#   /usr/src/redhat directory
+#
+
+EXTRA_OPTIONS="$1"
+
+DIRNAME=$(dirname $0)
+TOPDIR=${DIRNAME}/../..
+
+SPECDIR=`rpm --eval %_specdir`
+SRCDIR=`rpm --eval %_sourcedir`
+
+SPECFILE="ctdb.spec"
+SPECFILE_IN="ctdb.spec.in"
+RPMBUILD="rpmbuild"
+
+# We use tags and determine the version, as follows:
+# ctdb-0.9.1  (First release of 0.9).
+# ctdb-0.9.23 (23rd minor release of the 112 version)
+#
+# If we're not directly on a tag, this is a devel release; we append
+# .0.<patchnum>.<checksum>.devel to the release.
+TAG=`git describe`
+case "$TAG" in
+    ctdb-*)
+	TAG=${TAG##ctdb-}
+	case "$TAG" in
+	    *-*-g*) # 0.9-168-ge6cf0e8
+		# Not exactly on tag: devel version.
+		VERSION=`echo "$TAG" | sed 's/\([^-]\+\)-\([0-9]\+\)-\(g[0-9a-f]\+\)/\1.0.\2.\3.devel/'`
+		;;
+	    *)
+		# An actual release version
+		VERSION=$TAG
+		;;
+	esac
+	;;
+    *)
+	echo Invalid tag "$TAG" >&2
+	exit 1
+	;;
+esac
+
+sed -e s/@VERSION@/$VERSION/g \
+	< ${DIRNAME}/${SPECFILE_IN} \
+	> ${DIRNAME}/${SPECFILE}
+
+VERSION=$(grep ^Version ${DIRNAME}/${SPECFILE} | sed -e 's/^Version:\ \+//')
+
+if echo | gzip -c --rsyncable - > /dev/null 2>&1 ; then
+	GZIP="gzip -9 --rsyncable"
+else
+	GZIP="gzip -9"
+fi
+
+pushd ${TOPDIR}
+echo -n "Creating ctdb-${VERSION}.tar.gz ... "
+git archive --prefix=ctdb-${VERSION}/ HEAD | ${GZIP} > ${SRCDIR}/ctdb-${VERSION}.tar.gz
+RC=$?
+popd
+echo "Done."
+if [ $RC -ne 0 ]; then
+        echo "Build failed!"
+        exit 1
+fi
+
+# At this point the SPECDIR and SRCDIR vaiables must have a value!
+
+##
+## copy additional source files
+##
+cp -p ${DIRNAME}/${SPECFILE} ${SPECDIR}
+
+##
+## Build
+##
+echo "$(basename $0): Getting Ready to build release package"
+
+case ${EXTRA_OPTIONS} in
+	*-b*)
+		BUILD_TARGET=""
+		;;
+	*)
+		BUILD_TARGET="-ba"
+		;;
+esac
+
+
+${RPMBUILD} ${BUILD_TARGET} --clean --rmsource ${EXTRA_OPTIONS} ${SPECDIR}/${SPECFILE} || exit 1
+
+echo "$(basename $0): Done."
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/packaging/RPM/makerpms.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/packaging/maketarball.sh
===================================================================
--- branches/ctdb/squeeze-backports/packaging/maketarball.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/packaging/maketarball.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,120 @@
+#!/bin/sh
+#
+# maketarball.sh - create a tarball from the git branch HEAD
+#
+# Copyright (C) Michael Adam 2009
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Create CTDB source tarball of the current git branch HEAD.
+# The version is extracted from the spec file...
+# The first extra argument will be added as an additional version.
+#
+
+DIRNAME=$(dirname $0)
+TOPDIR=${DIRNAME}/..
+
+TAR_PREFIX_TMP="ctdb-tmp"
+SPECFILE=/tmp/${TAR_PREFIX_TMP}/packaging/RPM/ctdb.spec
+SPECFILE_IN=${SPECFILE}.in
+
+EXTRA_SUFFIX="$1"
+
+# if no githash was specified on the commandline,
+# then use the current head
+if test x"$GITHASH" = "x" ; then
+	GITHASH="$(git log --pretty=format:%h -1)"
+fi
+
+GITHASH_SUFFIX=".${GITHASH}"
+if test "x$USE_GITHASH" = "xno" ; then
+	GITHASH_SUFFIX=""
+fi
+
+if echo | gzip -c --rsyncable - > /dev/null 2>&1 ; then
+	GZIP="gzip -9 --rsyncable"
+else
+	GZIP="gzip -9"
+fi
+
+pushd ${TOPDIR}
+echo "Creating tarball ... "
+git archive --prefix=${TAR_PREFIX_TMP}/ ${GITHASH} | ( cd /tmp ; tar xf - )
+RC=$?
+popd
+if [ $RC -ne 0 ]; then
+	echo "Error calling git archive."
+	exit 1
+fi
+
+sed -e s/GITHASH/${GITHASH_SUFFIX}/g \
+	< ${SPECFILE_IN} \
+	> ${SPECFILE}
+
+VERSION=$(grep ^Version ${SPECFILE} | sed -e 's/^Version:\ \+//')${GITHASH_SUFFIX}
+
+if [ "x${EXTRA_SUFFIX}" != "x" ]; then
+	VERSION="${VERSION}-${EXTRA_SUFFIX}"
+fi
+
+TAR_PREFIX="ctdb-${VERSION}"
+TAR_BASE="ctdb-${VERSION}"
+
+pushd /tmp/${TAR_PREFIX_TMP}
+./autogen.sh
+RC=$?
+popd
+if [ $RC -ne 0 ]; then
+	echo "Error calling autogen.sh."
+	exit 1
+fi
+
+if test "x${DEBIAN_MODE}" = "xyes" ; then
+	TAR_PREFIX="ctdb-${VERSION}.orig"
+	TAR_BASE="ctdb_${VERSION}.orig"
+	rm -rf /tmp/${TAR_PREFIX_TMP}/lib/popt
+fi
+
+TAR_BALL=${TAR_BASE}.tar
+TAR_GZ_BALL=${TAR_BALL}.gz
+
+mv /tmp/${TAR_PREFIX_TMP} /tmp/${TAR_PREFIX}
+
+pushd /tmp
+tar cf ${TAR_BALL} ${TAR_PREFIX}
+RC=$?
+if [ $RC -ne 0 ]; then
+	popd
+        echo "Creation of tarball failed."
+        exit 1
+fi
+
+${GZIP} ${TAR_BALL}
+RC=$?
+if [ $RC -ne 0 ]; then
+	popd
+        echo "Zipping tarball failed."
+        exit 1
+fi
+
+rm -rf ${TAR_PREFIX}
+
+popd
+
+mv /tmp/${TAR_GZ_BALL} .
+
+echo "Done."
+exit 0


Property changes on: branches/ctdb/squeeze-backports/packaging/maketarball.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/server/ctdb_banning.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_banning.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_banning.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,164 @@
+/* 
+   ctdb banning code
+
+   Copyright (C) Ronnie Sahlberg  2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/time.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_client.h"
+#include "../include/ctdb_private.h"
+
+
+static void
+ctdb_ban_node_event(struct event_context *ev, struct timed_event *te, 
+			       struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+
+	DEBUG(DEBUG_ERR,("Banning timedout\n"));
+	ctdb->nodes[ctdb->pnn]->flags &= ~NODE_FLAGS_BANNED;
+
+	if (ctdb->banning_ctx != NULL) {
+		talloc_free(ctdb->banning_ctx);
+		ctdb->banning_ctx = NULL;
+	}
+}
+
+int32_t ctdb_local_node_got_banned(struct ctdb_context *ctdb)
+{
+	uint32_t i;
+
+	/* make sure we are frozen */
+	DEBUG(DEBUG_NOTICE,("This node has been banned - forcing freeze and recovery\n"));
+
+	/* Reset the generation id to 1 to make us ignore any
+	   REQ/REPLY CALL/DMASTER someone sends to us.
+	   We are now banned so we shouldnt service database calls
+	   anymore.
+	*/
+	ctdb->vnn_map->generation = INVALID_GENERATION;
+
+	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb_start_freeze(ctdb, i) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to freeze db priority %u\n", i));
+		}
+	}
+	ctdb_release_all_ips(ctdb);
+	ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+
+	return 0;
+}
+
+int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_ban_time *bantime = (struct ctdb_ban_time *)indata.dptr;
+
+	DEBUG(DEBUG_INFO,("SET BAN STATE\n"));
+
+	if (bantime->pnn != ctdb->pnn) {
+		if (bantime->pnn < 0 || bantime->pnn >= ctdb->num_nodes) {
+			DEBUG(DEBUG_ERR,(__location__ " ERROR: Invalid ban request. PNN:%d is invalid. Max nodes %d\n", bantime->pnn, ctdb->num_nodes));
+			return -1;
+		}
+		if (bantime->time == 0) {
+			DEBUG(DEBUG_INFO,("unbanning node %d\n", bantime->pnn));
+			ctdb->nodes[bantime->pnn]->flags &= ~NODE_FLAGS_BANNED;
+		} else {
+			DEBUG(DEBUG_INFO,("banning node %d\n", bantime->pnn));
+			if (ctdb->tunable.enable_bans == 0) {
+				DEBUG(DEBUG_INFO,("Bans are disabled - ignoring ban of node %u\n", bantime->pnn));
+				return 0;
+			}
+
+			ctdb->nodes[bantime->pnn]->flags |= NODE_FLAGS_BANNED;
+		}
+		return 0;
+	}
+
+	if (ctdb->banning_ctx != NULL) {
+		talloc_free(ctdb->banning_ctx);
+		ctdb->banning_ctx = NULL;
+	}
+
+	if (bantime->time == 0) {
+		DEBUG(DEBUG_ERR,("Unbanning this node\n"));
+		ctdb->nodes[bantime->pnn]->flags &= ~NODE_FLAGS_BANNED;
+		return 0;
+	}
+
+	if (ctdb->tunable.enable_bans == 0) {
+		DEBUG(DEBUG_ERR,("Bans are disabled - ignoring ban of node %u\n", bantime->pnn));
+		return 0;
+	}
+
+	ctdb->banning_ctx = talloc(ctdb, struct ctdb_ban_time);
+	if (ctdb->banning_ctx == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " ERROR Failed to allocate new banning state\n"));
+		return -1;
+	}
+	*((struct ctdb_ban_time *)(ctdb->banning_ctx)) = *bantime;
+
+
+	DEBUG(DEBUG_ERR,("Banning this node for %d seconds\n", bantime->time));
+	ctdb->nodes[bantime->pnn]->flags |= NODE_FLAGS_BANNED;
+
+	event_add_timed(ctdb->ev, ctdb->banning_ctx, timeval_current_ofs(bantime->time,0), ctdb_ban_node_event, ctdb);
+	if (bantime->pnn == ctdb->pnn) {
+		return ctdb_local_node_got_banned(ctdb);
+	}
+
+	return 0;
+}
+
+int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata)
+{
+	struct ctdb_ban_time *bantime;
+
+	bantime = talloc(outdata, struct ctdb_ban_time);
+	CTDB_NO_MEMORY(ctdb, bantime);
+
+	if (ctdb->banning_ctx != NULL) {
+		*bantime = *(struct ctdb_ban_time *)(ctdb->banning_ctx);
+	} else {
+		bantime->pnn = ctdb->pnn;
+		bantime->time = 0;
+	}
+
+	outdata->dptr  = (uint8_t *)bantime;
+	outdata->dsize = sizeof(struct ctdb_ban_time);
+
+	return 0;
+}
+
+/* Routine to ban ourselves for a while when trouble strikes. */
+void ctdb_ban_self(struct ctdb_context *ctdb)
+{
+	TDB_DATA data;
+	struct ctdb_ban_time bantime;
+
+	bantime.pnn  = ctdb->pnn;
+	bantime.time = ctdb->tunable.recovery_ban_period;
+
+	data.dsize = sizeof(bantime);
+	data.dptr  = (uint8_t *)&bantime;
+
+	ctdb_control_set_ban_state(ctdb, data);
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_call.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_call.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_call.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1421 @@
+/* 
+   ctdb_call protocol code
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+  see http://wiki.samba.org/index.php/Samba_%26_Clustering for
+  protocol design and packet details
+*/
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/util/dlinklist.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "../include/ctdb_private.h"
+
+/*
+  find the ctdb_db from a db index
+ */
+ struct ctdb_db_context *find_ctdb_db(struct ctdb_context *ctdb, uint32_t id)
+{
+	struct ctdb_db_context *ctdb_db;
+
+	for (ctdb_db=ctdb->db_list; ctdb_db; ctdb_db=ctdb_db->next) {
+		if (ctdb_db->db_id == id) {
+			break;
+		}
+	}
+	return ctdb_db;
+}
+
+/*
+  a varient of input packet that can be used in lock requeue
+*/
+static void ctdb_call_input_pkt(void *p, struct ctdb_req_header *hdr)
+{
+	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
+	ctdb_input_pkt(ctdb, hdr);
+}
+
+
+/*
+  send an error reply
+*/
+static void ctdb_send_error(struct ctdb_context *ctdb, 
+			    struct ctdb_req_header *hdr, uint32_t status,
+			    const char *fmt, ...) PRINTF_ATTRIBUTE(4,5);
+static void ctdb_send_error(struct ctdb_context *ctdb, 
+			    struct ctdb_req_header *hdr, uint32_t status,
+			    const char *fmt, ...)
+{
+	va_list ap;
+	struct ctdb_reply_error *r;
+	char *msg;
+	int msglen, len;
+
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " Failed to send error. Transport is DOWN\n"));
+		return;
+	}
+
+	va_start(ap, fmt);
+	msg = talloc_vasprintf(ctdb, fmt, ap);
+	if (msg == NULL) {
+		ctdb_fatal(ctdb, "Unable to allocate error in ctdb_send_error\n");
+	}
+	va_end(ap);
+
+	msglen = strlen(msg)+1;
+	len = offsetof(struct ctdb_reply_error, msg);
+	r = ctdb_transport_allocate(ctdb, msg, CTDB_REPLY_ERROR, len + msglen, 
+				    struct ctdb_reply_error);
+	CTDB_NO_MEMORY_FATAL(ctdb, r);
+
+	r->hdr.destnode  = hdr->srcnode;
+	r->hdr.reqid     = hdr->reqid;
+	r->status        = status;
+	r->msglen        = msglen;
+	memcpy(&r->msg[0], msg, msglen);
+
+	ctdb_queue_packet(ctdb, &r->hdr);
+
+	talloc_free(msg);
+}
+
+
+/**
+ * send a redirect reply
+ *
+ * The logic behind this function is this:
+ *
+ * A client wants to grab a record and sends a CTDB_REQ_CALL packet
+ * to its local ctdb (ctdb_request_call). If the node is not itself
+ * the record's DMASTER, it first redirects the packet to  the
+ * record's LMASTER. The LMASTER then redirects the call packet to
+ * the current DMASTER. But there is a race: The record may have
+ * been migrated off the DMASTER while the redirected packet is
+ * on the wire (or in the local queue). So in case the record has
+ * migrated off the new destinaton of the call packet, instead of
+ * going back to the LMASTER to get the new DMASTER, we try to
+ * reduce rountrips by first chasing the record a couple of times
+ * before giving up the direct chase and finally going back to the
+ * LMASTER (again). Note that this works because auf this: When
+ * a record is migrated off a node, then the new DMASTER is stored
+ * in the record's copy on the former DMASTER.
+ *
+ * The maximum number of attempts for direct chase to make before
+ * going back to the LMASTER is configurable by the tunable
+ * "MaxRedirectCount".
+ */
+static void ctdb_call_send_redirect(struct ctdb_context *ctdb, 
+				    TDB_DATA key,
+				    struct ctdb_req_call *c, 
+				    struct ctdb_ltdb_header *header)
+{
+	
+	uint32_t lmaster = ctdb_lmaster(ctdb, &key);
+	if (ctdb->pnn == lmaster) {
+		c->hdr.destnode = header->dmaster;
+	} else if ((c->hopcount % ctdb->tunable.max_redirect_count) == 0) {
+		c->hdr.destnode = lmaster;
+	} else {
+		c->hdr.destnode = header->dmaster;
+	}
+	c->hopcount++;
+	ctdb_queue_packet(ctdb, &c->hdr);
+}
+
+
+/*
+  send a dmaster reply
+
+  caller must have the chainlock before calling this routine. Caller must be
+  the lmaster
+*/
+static void ctdb_send_dmaster_reply(struct ctdb_db_context *ctdb_db,
+				    struct ctdb_ltdb_header *header,
+				    TDB_DATA key, TDB_DATA data,
+				    uint32_t new_dmaster,
+				    uint32_t reqid)
+{
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	struct ctdb_reply_dmaster *r;
+	int ret, len;
+	TALLOC_CTX *tmp_ctx;
+
+	if (ctdb->pnn != ctdb_lmaster(ctdb, &key)) {
+		DEBUG(DEBUG_ALERT,(__location__ " Caller is not lmaster!\n"));
+		return;
+	}
+
+	header->dmaster = new_dmaster;
+	ret = ctdb_ltdb_store(ctdb_db, key, header, data);
+	if (ret != 0) {
+		ctdb_fatal(ctdb, "ctdb_send_dmaster_reply unable to update dmaster");
+		return;
+	}
+
+	if (ctdb->methods == NULL) {
+		ctdb_fatal(ctdb, "ctdb_send_dmaster_reply cant update dmaster since transport is down");
+		return;
+	}
+
+	/* put the packet on a temporary context, allowing us to safely free
+	   it below even if ctdb_reply_dmaster() has freed it already */
+	tmp_ctx = talloc_new(ctdb);
+
+	/* send the CTDB_REPLY_DMASTER */
+	len = offsetof(struct ctdb_reply_dmaster, data) + key.dsize + data.dsize + sizeof(uint32_t);
+	r = ctdb_transport_allocate(ctdb, tmp_ctx, CTDB_REPLY_DMASTER, len,
+				    struct ctdb_reply_dmaster);
+	CTDB_NO_MEMORY_FATAL(ctdb, r);
+
+	r->hdr.destnode  = new_dmaster;
+	r->hdr.reqid     = reqid;
+	r->rsn           = header->rsn;
+	r->keylen        = key.dsize;
+	r->datalen       = data.dsize;
+	r->db_id         = ctdb_db->db_id;
+	memcpy(&r->data[0], key.dptr, key.dsize);
+	memcpy(&r->data[key.dsize], data.dptr, data.dsize);
+	memcpy(&r->data[key.dsize+data.dsize], &header->flags, sizeof(uint32_t));
+
+	ctdb_queue_packet(ctdb, &r->hdr);
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  send a dmaster request (give another node the dmaster for a record)
+
+  This is always sent to the lmaster, which ensures that the lmaster
+  always knows who the dmaster is. The lmaster will then send a
+  CTDB_REPLY_DMASTER to the new dmaster
+*/
+static void ctdb_call_send_dmaster(struct ctdb_db_context *ctdb_db, 
+				   struct ctdb_req_call *c, 
+				   struct ctdb_ltdb_header *header,
+				   TDB_DATA *key, TDB_DATA *data)
+{
+	struct ctdb_req_dmaster *r;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	int len;
+	uint32_t lmaster = ctdb_lmaster(ctdb, key);
+
+	if (ctdb->methods == NULL) {
+		ctdb_fatal(ctdb, "Failed ctdb_call_send_dmaster since transport is down");
+		return;
+	}
+
+	if (data->dsize != 0) {
+		header->flags |= CTDB_REC_FLAG_MIGRATED_WITH_DATA;
+	}
+
+	if (lmaster == ctdb->pnn) {
+		ctdb_send_dmaster_reply(ctdb_db, header, *key, *data, 
+					c->hdr.srcnode, c->hdr.reqid);
+		return;
+	}
+	
+	len = offsetof(struct ctdb_req_dmaster, data) + key->dsize + data->dsize
+			+ sizeof(uint32_t);
+	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_DMASTER, len, 
+				    struct ctdb_req_dmaster);
+	CTDB_NO_MEMORY_FATAL(ctdb, r);
+	r->hdr.destnode  = lmaster;
+	r->hdr.reqid     = c->hdr.reqid;
+	r->db_id         = c->db_id;
+	r->rsn           = header->rsn;
+	r->dmaster       = c->hdr.srcnode;
+	r->keylen        = key->dsize;
+	r->datalen       = data->dsize;
+	memcpy(&r->data[0], key->dptr, key->dsize);
+	memcpy(&r->data[key->dsize], data->dptr, data->dsize);
+	memcpy(&r->data[key->dsize + data->dsize], &header->flags, sizeof(uint32_t));
+
+	header->dmaster = c->hdr.srcnode;
+	if (ctdb_ltdb_store(ctdb_db, *key, header, *data) != 0) {
+		ctdb_fatal(ctdb, "Failed to store record in ctdb_call_send_dmaster");
+	}
+	
+	ctdb_queue_packet(ctdb, &r->hdr);
+
+	talloc_free(r);
+}
+
+/*
+  called when a CTDB_REPLY_DMASTER packet comes in, or when the lmaster
+  gets a CTDB_REQUEST_DMASTER for itself. We become the dmaster.
+
+  must be called with the chainlock held. This function releases the chainlock
+*/
+static void ctdb_become_dmaster(struct ctdb_db_context *ctdb_db,
+				struct ctdb_req_header *hdr,
+				TDB_DATA key, TDB_DATA data,
+				uint64_t rsn, uint32_t record_flags)
+{
+	struct ctdb_call_state *state;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	struct ctdb_ltdb_header header;
+	int ret;
+
+	DEBUG(DEBUG_DEBUG,("pnn %u dmaster response %08x\n", ctdb->pnn, ctdb_hash(&key)));
+
+	ZERO_STRUCT(header);
+	header.rsn = rsn + 1;
+	header.dmaster = ctdb->pnn;
+	header.flags = record_flags;
+
+	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
+
+	if (state) {
+		if (state->call->flags & CTDB_CALL_FLAG_VACUUM_MIGRATION) {
+			/*
+			 * We temporarily add the VACUUM_MIGRATED flag to
+			 * the record flags, so that ctdb_ltdb_store can
+			 * decide whether the record should be stored or
+			 * deleted.
+			 */
+			header.flags |= CTDB_REC_FLAG_VACUUM_MIGRATED;
+		}
+	}
+
+	if (ctdb_ltdb_store(ctdb_db, key, &header, data) != 0) {
+		ctdb_fatal(ctdb, "ctdb_reply_dmaster store failed\n");
+
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+		return;
+	}
+
+
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_become_dmaster from node %u\n",
+			 ctdb->pnn, hdr->reqid, hdr->srcnode));
+
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+		return;
+	}
+
+	if (key.dsize != state->call->key.dsize || memcmp(key.dptr, state->call->key.dptr, key.dsize)) {
+		DEBUG(DEBUG_ERR, ("Got bogus DMASTER packet reqid:%u from node %u. Key does not match key held in matching idr.\n", hdr->reqid, hdr->srcnode));
+
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+		return;
+	}
+
+	if (hdr->reqid != state->reqid) {
+		/* we found a record  but it was the wrong one */
+		DEBUG(DEBUG_ERR, ("Dropped orphan in ctdb_become_dmaster with reqid:%u\n from node %u", hdr->reqid, hdr->srcnode));
+
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+		return;
+	}
+
+	ctdb_call_local(ctdb_db, state->call, &header, state, &data, true);
+
+	ret = ctdb_ltdb_unlock(ctdb_db, state->call->key);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+	}
+
+	state->state = CTDB_CALL_DONE;
+	if (state->async.fn) {
+		state->async.fn(state);
+	}
+}
+
+
+
+/*
+  called when a CTDB_REQ_DMASTER packet comes in
+
+  this comes into the lmaster for a record when the current dmaster
+  wants to give up the dmaster role and give it to someone else
+*/
+void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_req_dmaster *c = (struct ctdb_req_dmaster *)hdr;
+	TDB_DATA key, data, data2;
+	struct ctdb_ltdb_header header;
+	struct ctdb_db_context *ctdb_db;
+	uint32_t record_flags = 0;
+	size_t len;
+	int ret;
+
+	key.dptr = c->data;
+	key.dsize = c->keylen;
+	data.dptr = c->data + c->keylen;
+	data.dsize = c->datalen;
+	len = offsetof(struct ctdb_req_dmaster, data) + key.dsize + data.dsize
+			+ sizeof(uint32_t);
+	if (len <= c->hdr.length) {
+		record_flags = *(uint32_t *)&c->data[c->keylen + c->datalen];
+	}
+
+	ctdb_db = find_ctdb_db(ctdb, c->db_id);
+	if (!ctdb_db) {
+		ctdb_send_error(ctdb, hdr, -1,
+				"Unknown database in request. db_id==0x%08x",
+				c->db_id);
+		return;
+	}
+	
+	/* fetch the current record */
+	ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, key, &header, hdr, &data2,
+					   ctdb_call_input_pkt, ctdb, False);
+	if (ret == -1) {
+		ctdb_fatal(ctdb, "ctdb_req_dmaster failed to fetch record");
+		return;
+	}
+	if (ret == -2) {
+		DEBUG(DEBUG_INFO,(__location__ " deferring ctdb_request_dmaster\n"));
+		return;
+	}
+
+	if (ctdb_lmaster(ctdb, &key) != ctdb->pnn) {
+		DEBUG(DEBUG_ALERT,("pnn %u dmaster request to non-lmaster lmaster=%u gen=%u curgen=%u\n",
+			 ctdb->pnn, ctdb_lmaster(ctdb, &key), 
+			 hdr->generation, ctdb->vnn_map->generation));
+		ctdb_fatal(ctdb, "ctdb_req_dmaster to non-lmaster");
+	}
+
+	DEBUG(DEBUG_DEBUG,("pnn %u dmaster request on %08x for %u from %u\n", 
+		 ctdb->pnn, ctdb_hash(&key), c->dmaster, c->hdr.srcnode));
+
+	/* its a protocol error if the sending node is not the current dmaster */
+	if (header.dmaster != hdr->srcnode) {
+		DEBUG(DEBUG_ALERT,("pnn %u dmaster request for new-dmaster %u from non-master %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u keyval=0x%08x\n",
+			 ctdb->pnn, c->dmaster, hdr->srcnode, header.dmaster, ctdb_hash(&key),
+			 ctdb_db->db_id, hdr->generation, ctdb->vnn_map->generation,
+			 (unsigned long long)c->rsn, (unsigned long long)header.rsn, c->hdr.reqid,
+			 (key.dsize >= 4)?(*(uint32_t *)key.dptr):0));
+		if (header.rsn != 0 || header.dmaster != ctdb->pnn) {
+			DEBUG(DEBUG_ERR,("ctdb_req_dmaster from non-master. Force a recovery.\n"));
+
+			ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+			ctdb_ltdb_unlock(ctdb_db, key);
+			return;
+		}
+	}
+
+	if (header.rsn > c->rsn) {
+		DEBUG(DEBUG_ALERT,("pnn %u dmaster request with older RSN new-dmaster %u from %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u\n",
+			 ctdb->pnn, c->dmaster, hdr->srcnode, header.dmaster, ctdb_hash(&key),
+			 ctdb_db->db_id, hdr->generation, ctdb->vnn_map->generation,
+			 (unsigned long long)c->rsn, (unsigned long long)header.rsn, c->hdr.reqid));
+	}
+
+	/* use the rsn from the sending node */
+	header.rsn = c->rsn;
+
+	/* store the record flags from the sending node */
+	header.flags = record_flags;
+
+	/* check if the new dmaster is the lmaster, in which case we
+	   skip the dmaster reply */
+	if (c->dmaster == ctdb->pnn) {
+		ctdb_become_dmaster(ctdb_db, hdr, key, data, c->rsn, record_flags);
+	} else {
+		ctdb_send_dmaster_reply(ctdb_db, &header, key, data, c->dmaster, hdr->reqid);
+
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+	}
+}
+
+
+/*
+  called when a CTDB_REQ_CALL packet comes in
+*/
+void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_req_call *c = (struct ctdb_req_call *)hdr;
+	TDB_DATA data;
+	struct ctdb_reply_call *r;
+	int ret, len;
+	struct ctdb_ltdb_header header;
+	struct ctdb_call *call;
+	struct ctdb_db_context *ctdb_db;
+
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " Failed ctdb_request_call. Transport is DOWN\n"));
+		return;
+	}
+
+
+	ctdb_db = find_ctdb_db(ctdb, c->db_id);
+	if (!ctdb_db) {
+		ctdb_send_error(ctdb, hdr, -1,
+				"Unknown database in request. db_id==0x%08x",
+				c->db_id);
+		return;
+	}
+
+	call = talloc(hdr, struct ctdb_call);
+	CTDB_NO_MEMORY_FATAL(ctdb, call);
+
+	call->call_id  = c->callid;
+	call->key.dptr = c->data;
+	call->key.dsize = c->keylen;
+	call->call_data.dptr = c->data + c->keylen;
+	call->call_data.dsize = c->calldatalen;
+	call->reply_data.dptr  = NULL;
+	call->reply_data.dsize = 0;
+
+	/* determine if we are the dmaster for this key. This also
+	   fetches the record data (if any), thus avoiding a 2nd fetch of the data 
+	   if the call will be answered locally */
+
+	ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, call->key, &header, hdr, &data,
+					   ctdb_call_input_pkt, ctdb, False);
+	if (ret == -1) {
+		ctdb_send_error(ctdb, hdr, ret, "ltdb fetch failed in ctdb_request_call");
+		return;
+	}
+	if (ret == -2) {
+		DEBUG(DEBUG_INFO,(__location__ " deferred ctdb_request_call\n"));
+		return;
+	}
+
+	/* Dont do READONLY if we dont have a tracking database */
+	if ((c->flags & CTDB_WANT_READONLY) && !ctdb_db->readonly) {
+		c->flags &= ~CTDB_WANT_READONLY;
+	}
+
+	if (header.flags & CTDB_REC_RO_REVOKE_COMPLETE) {
+		header.flags &= ~(CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY|CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_REVOKE_COMPLETE);
+		if (ctdb_ltdb_store(ctdb_db, call->key, &header, data) != 0) {
+			ctdb_fatal(ctdb, "Failed to write header with cleared REVOKE flag");
+		}
+		/* and clear out the tracking data */
+		if (tdb_delete(ctdb_db->rottdb, call->key) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to clear out trackingdb record\n"));
+		}
+	}
+
+	/* if we are revoking, we must defer all other calls until the revoke
+	 * had completed.
+	 */
+	if (header.flags & CTDB_REC_RO_REVOKING_READONLY) {
+		talloc_free(data.dptr);
+		ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+
+		if (ctdb_add_revoke_deferred_call(ctdb, ctdb_db, call->key, hdr, ctdb_call_input_pkt, ctdb) != 0) {
+			ctdb_fatal(ctdb, "Failed to add deferred call for revoke child");
+		}
+		talloc_free(call);
+		return;
+	}
+
+	/* if we are not the dmaster and are not hosting any delegations,
+	   then send a redirect to the requesting node */
+	if ((header.dmaster != ctdb->pnn) 
+	    && (!(header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) ) {
+		talloc_free(data.dptr);
+		ctdb_call_send_redirect(ctdb, call->key, c, &header);
+
+		ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+		return;
+	}
+
+	if ( (!(c->flags & CTDB_WANT_READONLY))
+	&& (header.flags & (CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY)) ) {
+		header.flags   |= CTDB_REC_RO_REVOKING_READONLY;
+		if (ctdb_ltdb_store(ctdb_db, call->key, &header, data) != 0) {
+			ctdb_fatal(ctdb, "Failed to store record with HAVE_DELEGATIONS set");
+		}
+		ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+
+		if (ctdb_start_revoke_ro_record(ctdb, ctdb_db, call->key, &header, data) != 0) {
+			ctdb_fatal(ctdb, "Failed to start record revoke");
+		}
+		talloc_free(data.dptr);
+
+		if (ctdb_add_revoke_deferred_call(ctdb, ctdb_db, call->key, hdr, ctdb_call_input_pkt, ctdb) != 0) {
+			ctdb_fatal(ctdb, "Failed to add deferred call for revoke child");
+		}
+		talloc_free(call);
+
+		return;
+	}		
+
+	/* If this is the first request for delegation. bump rsn and set
+	 * the delegations flag
+	 */
+	if ((c->flags & CTDB_WANT_READONLY)
+	&&  (c->callid == CTDB_FETCH_WITH_HEADER_FUNC)
+	&&  (!(header.flags & CTDB_REC_RO_HAVE_DELEGATIONS))) {
+		header.rsn     += 3;
+		header.flags   |= CTDB_REC_RO_HAVE_DELEGATIONS;
+		if (ctdb_ltdb_store(ctdb_db, call->key, &header, data) != 0) {
+			ctdb_fatal(ctdb, "Failed to store record with HAVE_DELEGATIONS set");
+		}
+	}
+	if ((c->flags & CTDB_WANT_READONLY) 
+	&&  (call->call_id == CTDB_FETCH_WITH_HEADER_FUNC)) {
+		TDB_DATA tdata;
+
+		tdata = tdb_fetch(ctdb_db->rottdb, call->key);
+		if (ctdb_trackingdb_add_pnn(ctdb, &tdata, c->hdr.srcnode) != 0) {
+			ctdb_fatal(ctdb, "Failed to add node to trackingdb");
+		}
+		if (tdb_store(ctdb_db->rottdb, call->key, tdata, TDB_REPLACE) != 0) {
+			ctdb_fatal(ctdb, "Failed to store trackingdb data");
+		}
+		free(tdata.dptr);
+
+		ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+
+		len = offsetof(struct ctdb_reply_call, data) + data.dsize + sizeof(struct ctdb_ltdb_header);
+		r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CALL, len, 
+					    struct ctdb_reply_call);
+		CTDB_NO_MEMORY_FATAL(ctdb, r);
+		r->hdr.destnode  = c->hdr.srcnode;
+		r->hdr.reqid     = c->hdr.reqid;
+		r->status        = 0;
+		r->datalen       = data.dsize + sizeof(struct ctdb_ltdb_header);
+		header.rsn      -= 2;
+		header.flags   |= CTDB_REC_RO_HAVE_READONLY;
+		header.flags   &= ~CTDB_REC_RO_HAVE_DELEGATIONS;
+		memcpy(&r->data[0], &header, sizeof(struct ctdb_ltdb_header));
+
+		if (data.dsize) {
+			memcpy(&r->data[sizeof(struct ctdb_ltdb_header)], data.dptr, data.dsize);
+		}
+
+		ctdb_queue_packet(ctdb, &r->hdr);
+
+		talloc_free(r);
+		return;
+	}
+
+	CTDB_UPDATE_STAT(ctdb, max_hop_count, c->hopcount);
+
+	/* Try if possible to migrate the record off to the caller node.
+	 * From the clients perspective a fetch of the data is just as 
+	 * expensive as a migration.
+	 */
+	if (c->hdr.srcnode != ctdb->pnn) {
+		if (ctdb_db->transaction_active) {
+			DEBUG(DEBUG_INFO, (__location__ " refusing migration"
+			      " of key %s while transaction is active\n",
+			      (char *)call->key.dptr));
+		} else {
+			DEBUG(DEBUG_DEBUG,("pnn %u starting migration of %08x to %u\n",
+				 ctdb->pnn, ctdb_hash(&(call->key)), c->hdr.srcnode));
+			ctdb_call_send_dmaster(ctdb_db, c, &header, &(call->key), &data);
+			talloc_free(data.dptr);
+
+			ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+			}
+			return;
+		}
+	}
+
+	ret = ctdb_call_local(ctdb_db, call, &header, hdr, &data, true);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_call_local failed\n"));
+		call->status = -1;
+	}
+
+	ret = ctdb_ltdb_unlock(ctdb_db, call->key);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+	}
+
+	len = offsetof(struct ctdb_reply_call, data) + call->reply_data.dsize;
+	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CALL, len, 
+				    struct ctdb_reply_call);
+	CTDB_NO_MEMORY_FATAL(ctdb, r);
+	r->hdr.destnode  = hdr->srcnode;
+	r->hdr.reqid     = hdr->reqid;
+	r->status        = call->status;
+	r->datalen       = call->reply_data.dsize;
+	if (call->reply_data.dsize) {
+		memcpy(&r->data[0], call->reply_data.dptr, call->reply_data.dsize);
+	}
+
+	ctdb_queue_packet(ctdb, &r->hdr);
+
+	talloc_free(r);
+}
+
+/*
+  called when a CTDB_REPLY_CALL packet comes in
+
+  This packet comes in response to a CTDB_REQ_CALL request packet. It
+  contains any reply data from the call
+*/
+void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;
+	struct ctdb_call_state *state;
+
+	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " reqid %u not found\n", hdr->reqid));
+		return;
+	}
+
+	if (hdr->reqid != state->reqid) {
+		/* we found a record  but it was the wrong one */
+		DEBUG(DEBUG_ERR, ("Dropped orphaned call reply with reqid:%u\n",hdr->reqid));
+		return;
+	}
+
+
+	/* read only delegation processing */
+	/* If we got a FETCH_WITH_HEADER we should check if this is a ro
+	 * delegation since we may need to update the record header
+	 */
+	if (state->c->callid == CTDB_FETCH_WITH_HEADER_FUNC) {
+		struct ctdb_db_context *ctdb_db = state->ctdb_db;
+		struct ctdb_ltdb_header *header = (struct ctdb_ltdb_header *)&c->data[0];
+		struct ctdb_ltdb_header oldheader;
+		TDB_DATA key, data, olddata;
+		int ret;
+
+		if (!(header->flags & CTDB_REC_RO_HAVE_READONLY)) {
+			goto finished_ro;
+			return;
+		}
+
+		key.dsize = state->c->keylen;
+		key.dptr  = state->c->data;
+		ret = ctdb_ltdb_lock_requeue(ctdb_db, key, hdr,
+				     ctdb_call_input_pkt, ctdb, False);
+		if (ret == -2) {
+			return;
+		}
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to get lock in ctdb_reply_call\n"));
+			return;
+		}
+
+		ret = ctdb_ltdb_fetch(ctdb_db, key, &oldheader, state, &olddata);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Failed to fetch old record in ctdb_reply_call\n"));
+			ctdb_ltdb_unlock(ctdb_db, key);
+			goto finished_ro;
+		}			
+
+		if (header->rsn <= oldheader.rsn) {
+			ctdb_ltdb_unlock(ctdb_db, key);
+			goto finished_ro;
+		}
+
+		if (c->datalen < sizeof(struct ctdb_ltdb_header)) {
+			DEBUG(DEBUG_ERR,(__location__ " Got FETCH_WITH_HEADER reply with too little data: %d bytes\n", c->datalen));
+			ctdb_ltdb_unlock(ctdb_db, key);
+			goto finished_ro;
+		}
+
+		data.dsize = c->datalen - sizeof(struct ctdb_ltdb_header);
+		data.dptr  = &c->data[sizeof(struct ctdb_ltdb_header)];
+		ret = ctdb_ltdb_store(ctdb_db, key, header, data);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Failed to store new record in ctdb_reply_call\n"));
+			ctdb_ltdb_unlock(ctdb_db, key);
+			goto finished_ro;
+		}			
+
+		ctdb_ltdb_unlock(ctdb_db, key);
+	}
+finished_ro:
+
+	state->call->reply_data.dptr = c->data;
+	state->call->reply_data.dsize = c->datalen;
+	state->call->status = c->status;
+
+	talloc_steal(state, c);
+
+	state->state = CTDB_CALL_DONE;
+	if (state->async.fn) {
+		state->async.fn(state);
+	}
+}
+
+
+/*
+  called when a CTDB_REPLY_DMASTER packet comes in
+
+  This packet comes in from the lmaster response to a CTDB_REQ_CALL
+  request packet. It means that the current dmaster wants to give us
+  the dmaster role
+*/
+void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_reply_dmaster *c = (struct ctdb_reply_dmaster *)hdr;
+	struct ctdb_db_context *ctdb_db;
+	TDB_DATA key, data;
+	uint32_t record_flags = 0;
+	size_t len;
+	int ret;
+
+	ctdb_db = find_ctdb_db(ctdb, c->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_reply_dmaster\n", c->db_id));
+		return;
+	}
+	
+	key.dptr = c->data;
+	key.dsize = c->keylen;
+	data.dptr = &c->data[key.dsize];
+	data.dsize = c->datalen;
+	len = offsetof(struct ctdb_reply_dmaster, data) + key.dsize + data.dsize
+		+ sizeof(uint32_t);
+	if (len <= c->hdr.length) {
+		record_flags = *(uint32_t *)&c->data[c->keylen + c->datalen];
+	}
+
+	ret = ctdb_ltdb_lock_requeue(ctdb_db, key, hdr,
+				     ctdb_call_input_pkt, ctdb, False);
+	if (ret == -2) {
+		return;
+	}
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get lock in ctdb_reply_dmaster\n"));
+		return;
+	}
+
+	ctdb_become_dmaster(ctdb_db, hdr, key, data, c->rsn, record_flags);
+}
+
+
+/*
+  called when a CTDB_REPLY_ERROR packet comes in
+*/
+void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_reply_error *c = (struct ctdb_reply_error *)hdr;
+	struct ctdb_call_state *state;
+
+	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_reply_error\n",
+			 ctdb->pnn, hdr->reqid));
+		return;
+	}
+
+	if (hdr->reqid != state->reqid) {
+		/* we found a record  but it was the wrong one */
+		DEBUG(DEBUG_ERR, ("Dropped orphaned error reply with reqid:%u\n",hdr->reqid));
+		return;
+	}
+
+	talloc_steal(state, c);
+
+	state->state  = CTDB_CALL_ERROR;
+	state->errmsg = (char *)c->msg;
+	if (state->async.fn) {
+		state->async.fn(state);
+	}
+}
+
+
+/*
+  destroy a ctdb_call
+*/
+static int ctdb_call_destructor(struct ctdb_call_state *state)
+{
+	DLIST_REMOVE(state->ctdb_db->ctdb->pending_calls, state);
+	ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);
+	return 0;
+}
+
+
+/*
+  called when a ctdb_call needs to be resent after a reconfigure event
+*/
+static void ctdb_call_resend(struct ctdb_call_state *state)
+{
+	struct ctdb_context *ctdb = state->ctdb_db->ctdb;
+
+	state->generation = ctdb->vnn_map->generation;
+
+	/* use a new reqid, in case the old reply does eventually come in */
+	ctdb_reqid_remove(ctdb, state->reqid);
+	state->reqid = ctdb_reqid_new(ctdb, state);
+	state->c->hdr.reqid = state->reqid;
+
+	/* update the generation count for this request, so its valid with the new vnn_map */
+	state->c->hdr.generation = state->generation;
+
+	/* send the packet to ourselves, it will be redirected appropriately */
+	state->c->hdr.destnode = ctdb->pnn;
+
+	ctdb_queue_packet(ctdb, &state->c->hdr);
+	DEBUG(DEBUG_NOTICE,("resent ctdb_call\n"));
+}
+
+/*
+  resend all pending calls on recovery
+ */
+void ctdb_call_resend_all(struct ctdb_context *ctdb)
+{
+	struct ctdb_call_state *state, *next;
+	for (state=ctdb->pending_calls;state;state=next) {
+		next = state->next;
+		ctdb_call_resend(state);
+	}
+}
+
+/*
+  this allows the caller to setup a async.fn 
+*/
+static void call_local_trigger(struct event_context *ev, struct timed_event *te, 
+		       struct timeval t, void *private_data)
+{
+	struct ctdb_call_state *state = talloc_get_type(private_data, struct ctdb_call_state);
+	if (state->async.fn) {
+		state->async.fn(state);
+	}
+}	
+
+
+/*
+  construct an event driven local ctdb_call
+
+  this is used so that locally processed ctdb_call requests are processed
+  in an event driven manner
+*/
+struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db, 
+					     struct ctdb_call *call,
+					     struct ctdb_ltdb_header *header,
+					     TDB_DATA *data)
+{
+	struct ctdb_call_state *state;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	int ret;
+
+	state = talloc_zero(ctdb_db, struct ctdb_call_state);
+	CTDB_NO_MEMORY_NULL(ctdb, state);
+
+	talloc_steal(state, data->dptr);
+
+	state->state = CTDB_CALL_DONE;
+	state->call  = talloc(state, struct ctdb_call);
+	CTDB_NO_MEMORY_NULL(ctdb, state->call);
+	*(state->call) = *call;
+	state->ctdb_db = ctdb_db;
+
+	ret = ctdb_call_local(ctdb_db, state->call, header, state, data, true);
+
+	event_add_timed(ctdb->ev, state, timeval_zero(), call_local_trigger, state);
+
+	return state;
+}
+
+
+/*
+  make a remote ctdb call - async send. Called in daemon context.
+
+  This constructs a ctdb_call request and queues it for processing. 
+  This call never blocks.
+*/
+struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctdb_db, 
+						     struct ctdb_call *call, 
+						     struct ctdb_ltdb_header *header)
+{
+	uint32_t len;
+	struct ctdb_call_state *state;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " Failed send packet. Transport is down\n"));
+		return NULL;
+	}
+
+	state = talloc_zero(ctdb_db, struct ctdb_call_state);
+	CTDB_NO_MEMORY_NULL(ctdb, state);
+	state->call = talloc(state, struct ctdb_call);
+	CTDB_NO_MEMORY_NULL(ctdb, state->call);
+
+	state->reqid = ctdb_reqid_new(ctdb, state);
+	state->ctdb_db = ctdb_db;
+	talloc_set_destructor(state, ctdb_call_destructor);
+
+	len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;
+	state->c = ctdb_transport_allocate(ctdb, state, CTDB_REQ_CALL, len, 
+					   struct ctdb_req_call);
+	CTDB_NO_MEMORY_NULL(ctdb, state->c);
+	state->c->hdr.destnode  = header->dmaster;
+
+	/* this limits us to 16k outstanding messages - not unreasonable */
+	state->c->hdr.reqid     = state->reqid;
+	state->c->flags         = call->flags;
+	state->c->db_id         = ctdb_db->db_id;
+	state->c->callid        = call->call_id;
+	state->c->hopcount      = 0;
+	state->c->keylen        = call->key.dsize;
+	state->c->calldatalen   = call->call_data.dsize;
+	memcpy(&state->c->data[0], call->key.dptr, call->key.dsize);
+	memcpy(&state->c->data[call->key.dsize], 
+	       call->call_data.dptr, call->call_data.dsize);
+	*(state->call)              = *call;
+	state->call->call_data.dptr = &state->c->data[call->key.dsize];
+	state->call->key.dptr       = &state->c->data[0];
+
+	state->state  = CTDB_CALL_WAIT;
+	state->generation = ctdb->vnn_map->generation;
+
+	DLIST_ADD(ctdb->pending_calls, state);
+
+	ctdb_queue_packet(ctdb, &state->c->hdr);
+
+	return state;
+}
+
+/*
+  make a remote ctdb call - async recv - called in daemon context
+
+  This is called when the program wants to wait for a ctdb_call to complete and get the 
+  results. This call will block unless the call has already completed.
+*/
+int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call)
+{
+	while (state->state < CTDB_CALL_DONE) {
+		event_loop_once(state->ctdb_db->ctdb->ev);
+	}
+	if (state->state != CTDB_CALL_DONE) {
+		ctdb_set_error(state->ctdb_db->ctdb, "%s", state->errmsg);
+		talloc_free(state);
+		return -1;
+	}
+
+	if (state->call->reply_data.dsize) {
+		call->reply_data.dptr = talloc_memdup(call,
+						      state->call->reply_data.dptr,
+						      state->call->reply_data.dsize);
+		call->reply_data.dsize = state->call->reply_data.dsize;
+	} else {
+		call->reply_data.dptr = NULL;
+		call->reply_data.dsize = 0;
+	}
+	call->status = state->call->status;
+	talloc_free(state);
+	return 0;
+}
+
+
+/* 
+   send a keepalive packet to the other node
+*/
+void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode)
+{
+	struct ctdb_req_keepalive *r;
+	
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " Failed to send keepalive. Transport is DOWN\n"));
+		return;
+	}
+
+	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_KEEPALIVE,
+				    sizeof(struct ctdb_req_keepalive), 
+				    struct ctdb_req_keepalive);
+	CTDB_NO_MEMORY_FATAL(ctdb, r);
+	r->hdr.destnode  = destnode;
+	r->hdr.reqid     = 0;
+	
+	CTDB_INCREMENT_STAT(ctdb, keepalive_packets_sent);
+
+	ctdb_queue_packet(ctdb, &r->hdr);
+
+	talloc_free(r);
+}
+
+
+
+struct revokechild_deferred_call {
+	struct ctdb_context *ctdb;
+	struct ctdb_req_header *hdr;
+	deferred_requeue_fn fn;
+	void *ctx;
+};
+
+struct revokechild_handle {
+	struct revokechild_handle *next, *prev;
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	struct fd_event *fde;
+	int status;
+	int fd[2];
+	pid_t child;
+	TDB_DATA key;
+};
+
+struct revokechild_requeue_handle {
+	struct ctdb_context *ctdb;
+	struct ctdb_req_header *hdr;
+	deferred_requeue_fn fn;
+	void *ctx;
+};
+
+static void deferred_call_requeue(struct event_context *ev, struct timed_event *te, 
+		       struct timeval t, void *private_data)
+{
+	struct revokechild_requeue_handle *requeue_handle = talloc_get_type(private_data, struct revokechild_requeue_handle);
+
+	requeue_handle->fn(requeue_handle->ctx, requeue_handle->hdr);
+	talloc_free(requeue_handle);
+}
+
+static int deferred_call_destructor(struct revokechild_deferred_call *deferred_call)
+{
+	struct ctdb_context *ctdb = deferred_call->ctdb;
+	struct revokechild_requeue_handle *requeue_handle = talloc(ctdb, struct revokechild_requeue_handle);
+	struct ctdb_req_call *c = (struct ctdb_req_call *)deferred_call->hdr;
+
+	requeue_handle->ctdb = ctdb;
+	requeue_handle->hdr  = deferred_call->hdr;
+	requeue_handle->fn   = deferred_call->fn;
+	requeue_handle->ctx  = deferred_call->ctx;
+	talloc_steal(requeue_handle, requeue_handle->hdr);
+
+	/* when revoking, any READONLY requests have 1 second grace to let read/write finish first */
+	event_add_timed(ctdb->ev, requeue_handle, timeval_current_ofs(c->flags & CTDB_WANT_READONLY ? 1 : 0, 0), deferred_call_requeue, requeue_handle);
+
+	return 0;
+}
+
+
+static int revokechild_destructor(struct revokechild_handle *rc)
+{
+	if (rc->fde != NULL) {
+		talloc_free(rc->fde);
+	}
+
+	if (rc->fd[0] != -1) {
+		close(rc->fd[0]);
+	}
+	if (rc->fd[1] != -1) {
+		close(rc->fd[1]);
+	}
+	kill(rc->child, SIGKILL);
+
+	DLIST_REMOVE(rc->ctdb_db->revokechild_active, rc);
+	return 0;
+}
+
+static void revokechild_handler(struct event_context *ev, struct fd_event *fde, 
+			     uint16_t flags, void *private_data)
+{
+	struct revokechild_handle *rc = talloc_get_type(private_data, 
+						     struct revokechild_handle);
+	int ret;
+	char c;
+
+	ret = read(rc->fd[0], &c, 1);
+	if (ret != 1) {
+		DEBUG(DEBUG_ERR,("Failed to read status from revokechild. errno:%d\n", errno));
+		rc->status = -1;
+		talloc_free(rc);
+		return;
+	}
+	if (c != 0) {
+		DEBUG(DEBUG_ERR,("revokechild returned failure. status:%d\n", c));
+		rc->status = -1;
+		talloc_free(rc);
+		return;
+	}
+
+	talloc_free(rc);
+}
+
+struct ctdb_revoke_state {
+	struct ctdb_db_context *ctdb_db;
+	TDB_DATA key;
+	struct ctdb_ltdb_header *header;
+	TDB_DATA data;
+	int count;
+	int status;
+	int finished;
+};
+
+static void update_record_cb(struct ctdb_client_control_state *state)
+{
+	struct ctdb_revoke_state *revoke_state;
+	int ret;
+	int32_t res;
+
+	if (state == NULL) {
+		return;
+	}
+	revoke_state = state->async.private_data;
+
+	state->async.fn = NULL;
+        ret = ctdb_control_recv(state->ctdb, state, state, NULL, &res, NULL);
+        if ((ret != 0) || (res != 0)) {
+		DEBUG(DEBUG_ERR,("Recv for revoke update record failed ret:%d res:%d\n", ret, res));
+		revoke_state->status = -1;
+	}
+
+	revoke_state->count--;
+	if (revoke_state->count <= 0) {
+		revoke_state->finished = 1;
+	}
+}
+
+static void revoke_send_cb(struct ctdb_context *ctdb, uint32_t pnn, void *private_data)
+{
+	struct ctdb_revoke_state *revoke_state = private_data;
+	struct ctdb_client_control_state *state;
+
+	state = ctdb_ctrl_updaterecord_send(ctdb, revoke_state, timeval_current_ofs(5,0), pnn, revoke_state->ctdb_db, revoke_state->key, revoke_state->header, revoke_state->data);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR,("Failure to send update record to revoke readonly delegation\n"));
+		revoke_state->status = -1;
+		return;
+	}
+	state->async.fn           = update_record_cb;
+	state->async.private_data = revoke_state;
+
+	revoke_state->count++;
+
+}
+
+static void ctdb_revoke_timeout_handler(struct event_context *ev, struct timed_event *te, 
+			      struct timeval yt, void *private_data)
+{
+	struct ctdb_revoke_state *state = private_data;
+
+	DEBUG(DEBUG_ERR,("Timed out waiting for revoke to finish\n"));
+	state->finished = 1;
+	state->status   = -1;
+}
+
+static int ctdb_revoke_all_delegations(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA tdata, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data)
+{
+	struct ctdb_revoke_state *state = talloc_zero(ctdb, struct ctdb_revoke_state);
+	int status;
+
+	state->ctdb_db = ctdb_db;
+	state->key     = key;
+	state->header  = header;
+	state->data    = data;
+ 
+	ctdb_trackingdb_traverse(ctdb, tdata, revoke_send_cb, state);
+
+	event_add_timed(ctdb->ev, state, timeval_current_ofs(5, 0), ctdb_revoke_timeout_handler, state);
+
+	while (state->finished == 0) {
+		event_loop_once(ctdb->ev);
+	}
+
+	status = state->status;
+
+	if (status == 0) {
+		struct ctdb_ltdb_header new_header;
+		TDB_DATA new_data;
+
+		if (ctdb_ltdb_lock(ctdb_db, key) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to chainlock the database in revokechild\n"));
+			talloc_free(state);
+			return -1;
+		}
+		if (ctdb_ltdb_fetch(ctdb_db, key, &new_header, state, &new_data) != 0) {
+			ctdb_ltdb_unlock(ctdb_db, key);
+			DEBUG(DEBUG_ERR,("Failed for fetch tdb record in revokechild\n"));
+			talloc_free(state);
+			return -1;
+		}
+		header->rsn++;
+		if (new_header.rsn > header->rsn) {
+			ctdb_ltdb_unlock(ctdb_db, key);
+			DEBUG(DEBUG_ERR,("RSN too high in tdb record in revokechild\n"));
+			talloc_free(state);
+			return -1;
+		}
+		if ( (new_header.flags & (CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_HAVE_DELEGATIONS)) != (CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_HAVE_DELEGATIONS) ) {
+			ctdb_ltdb_unlock(ctdb_db, key);
+			DEBUG(DEBUG_ERR,("Flags are wrong in tdb record in revokechild\n"));
+			talloc_free(state);
+			return -1;
+		}
+		new_header.rsn++;
+		new_header.flags |= CTDB_REC_RO_REVOKE_COMPLETE;
+		if (ctdb_ltdb_store(ctdb_db, key, &new_header, new_data) != 0) {
+			ctdb_ltdb_unlock(ctdb_db, key);
+			DEBUG(DEBUG_ERR,("Failed to write new record in revokechild\n"));
+			talloc_free(state);
+			return -1;
+		}
+		ctdb_ltdb_unlock(ctdb_db, key);
+	}
+
+	talloc_free(state);
+	return status;
+}
+
+
+int ctdb_start_revoke_ro_record(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data)
+{
+	TDB_DATA tdata;
+	struct revokechild_handle *rc;
+	pid_t parent = getpid();
+	int ret;
+
+	header->flags &= ~(CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY);
+	header->rsn   -= 1;
+
+	if ((rc = talloc_zero(ctdb_db, struct revokechild_handle)) == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to allocate revokechild_handle\n"));
+		return -1;
+	}
+
+	tdata = tdb_fetch(ctdb_db->rottdb, key);
+	if (tdata.dsize > 0) {
+		uint8_t *tmp;
+
+		tmp = tdata.dptr;
+		tdata.dptr = talloc_memdup(rc, tdata.dptr, tdata.dsize);
+		free(tmp);
+	}
+
+	rc->status    = 0;
+	rc->ctdb      = ctdb;
+	rc->ctdb_db   = ctdb_db;
+	rc->fd[0]     = -1;
+	rc->fd[1]     = -1;
+
+	talloc_set_destructor(rc, revokechild_destructor);
+
+	rc->key.dsize = key.dsize;
+	rc->key.dptr  = talloc_memdup(rc, key.dptr, key.dsize);
+	if (rc->key.dptr == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to allocate key for revokechild_handle\n"));
+		talloc_free(rc);
+		return -1;
+	}
+
+	ret = pipe(rc->fd);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to allocate key for revokechild_handle\n"));
+		talloc_free(rc);
+		return -1;
+	}
+
+
+	rc->child = ctdb_fork(ctdb);
+	if (rc->child == (pid_t)-1) {
+		DEBUG(DEBUG_ERR,("Failed to fork child for revokechild\n"));
+		talloc_free(rc);
+		return -1;
+	}
+
+	if (rc->child == 0) {
+		char c = 0;
+		close(rc->fd[0]);
+		debug_extra = talloc_asprintf(NULL, "revokechild-%s:", ctdb_db->db_name);
+
+		if (switch_from_server_to_client(ctdb, "revokechild-%s", ctdb_db->db_name) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to switch from server to client for revokechild process\n"));
+			c = 1;
+			goto child_finished;
+		}
+
+		c = ctdb_revoke_all_delegations(ctdb, ctdb_db, tdata, key, header, data);
+
+child_finished:
+		write(rc->fd[1], &c, 1);
+		/* make sure we die when our parent dies */
+		while (kill(parent, 0) == 0 || errno != ESRCH) {
+			sleep(5);
+		}
+		_exit(0);
+	}
+
+	close(rc->fd[1]);
+	rc->fd[1] = -1;
+	set_close_on_exec(rc->fd[0]);
+
+	/* This is an active revokechild child process */
+	DLIST_ADD_END(ctdb_db->revokechild_active, rc, NULL);
+
+	rc->fde = event_add_fd(ctdb->ev, rc, rc->fd[0],
+				   EVENT_FD_READ, revokechild_handler,
+				   (void *)rc);
+	if (rc->fde == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to set up fd event for revokechild process\n"));
+		talloc_free(rc);
+	}
+	tevent_fd_set_auto_close(rc->fde);
+
+	return 0;
+}
+
+int ctdb_add_revoke_deferred_call(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_req_header *hdr, deferred_requeue_fn fn, void *call_context)
+{
+	struct revokechild_handle *rc;
+	struct revokechild_deferred_call *deferred_call;
+
+	for (rc = ctdb_db->revokechild_active; rc; rc = rc->next) {
+		if (rc->key.dsize == 0) {
+			continue;
+		}
+		if (rc->key.dsize != key.dsize) {
+			continue;
+		}
+		if (!memcmp(rc->key.dptr, key.dptr, key.dsize)) {
+			break;
+		}
+	}
+
+	if (rc == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to add deferred call to revoke list. revoke structure not found\n"));
+		return -1;
+	}
+
+	deferred_call = talloc(rc, struct revokechild_deferred_call);
+	if (deferred_call == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to allocate deferred call structure for revoking record\n"));
+		return -1;
+	}
+
+	deferred_call->ctdb = ctdb;
+	deferred_call->hdr  = hdr;
+	deferred_call->fn   = fn;
+	deferred_call->ctx  = call_context;
+
+	talloc_set_destructor(deferred_call, deferred_call_destructor);
+	talloc_steal(deferred_call, hdr);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_control.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_control.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_control.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,840 @@
+/* 
+   ctdb_control protocol code
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+#include "lib/util/dlinklist.h"
+#include "db_wrap.h"
+
+
+struct ctdb_control_state {
+	struct ctdb_context *ctdb;
+	uint32_t reqid;
+	ctdb_control_callback_fn_t callback;
+	void *private_data;
+	unsigned flags;
+};
+
+
+/*
+  dump talloc memory hierarchy, returning it as a blob to the client
+ */
+int32_t ctdb_dump_memory(struct ctdb_context *ctdb, TDB_DATA *outdata)
+{
+	/* dump to a file, then send the file as a blob */
+	FILE *f;
+	long fsize;
+	f = tmpfile();
+	if (f == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Unable to open tmpfile - %s\n", strerror(errno)));
+		return -1;
+	}
+	talloc_report_full(NULL, f);
+	fsize = ftell(f);
+	rewind(f);
+	outdata->dptr = talloc_size(outdata, fsize);
+	CTDB_NO_MEMORY(ctdb, outdata->dptr);
+	outdata->dsize = fread(outdata->dptr, 1, fsize, f);
+	fclose(f);
+	if (outdata->dsize != fsize) {
+		DEBUG(DEBUG_ERR,(__location__ " Unable to read tmpfile\n"));
+		return -1;
+	}
+	return 0;
+}
+
+
+/*
+  process a control request
+ */
+static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, 
+				     struct ctdb_req_control *c,
+				     TDB_DATA indata,
+				     TDB_DATA *outdata, uint32_t srcnode,
+				     const char **errormsg,
+				     bool *async_reply)
+{
+	uint32_t opcode = c->opcode;
+	uint64_t srvid = c->srvid;
+	uint32_t client_id = c->client_id;
+
+	switch (opcode) {
+	case CTDB_CONTROL_PROCESS_EXISTS: {
+		CHECK_CONTROL_DATA_SIZE(sizeof(pid_t));
+		return ctdb_control_process_exists(ctdb, *(pid_t *)indata.dptr);
+	}
+
+	case CTDB_CONTROL_SET_DEBUG: {
+		CHECK_CONTROL_DATA_SIZE(sizeof(int32_t));
+		LogLevel = *(int32_t *)indata.dptr;
+		return 0;
+	}
+
+	case CTDB_CONTROL_GET_DEBUG: {
+		CHECK_CONTROL_DATA_SIZE(0);
+		outdata->dptr = (uint8_t *)&LogLevel;
+		outdata->dsize = sizeof(LogLevel);
+		return 0;
+	}
+
+	case CTDB_CONTROL_STATISTICS: {
+		int i;
+		CHECK_CONTROL_DATA_SIZE(0);
+		ctdb->statistics.memory_used = talloc_total_size(NULL);
+		ctdb->statistics.frozen = 0;
+		for (i=1; i<= NUM_DB_PRIORITIES; i++) {
+			if (ctdb->freeze_mode[i] == CTDB_FREEZE_FROZEN) {
+				ctdb->statistics.frozen = 1;
+			}
+		}
+		ctdb->statistics.recovering = (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE);
+		ctdb->statistics.statistics_current_time = timeval_current();
+
+		outdata->dptr = (uint8_t *)&ctdb->statistics;
+		outdata->dsize = sizeof(ctdb->statistics);
+		return 0;
+	}
+
+	case CTDB_CONTROL_GET_ALL_TUNABLES: {
+		CHECK_CONTROL_DATA_SIZE(0);
+		outdata->dptr = (uint8_t *)&ctdb->tunable;
+		outdata->dsize = sizeof(ctdb->tunable);
+		return 0;
+	}
+
+	case CTDB_CONTROL_DUMP_MEMORY: {
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_dump_memory(ctdb, outdata);
+	}
+
+	case CTDB_CONTROL_STATISTICS_RESET: {
+		CHECK_CONTROL_DATA_SIZE(0);
+		ZERO_STRUCT(ctdb->statistics);
+		ctdb->statistics.statistics_start_time = timeval_current();
+		return 0;
+	}
+
+	case CTDB_CONTROL_GETVNNMAP:
+		return ctdb_control_getvnnmap(ctdb, opcode, indata, outdata);
+
+	case CTDB_CONTROL_GET_DBMAP:
+		return ctdb_control_getdbmap(ctdb, opcode, indata, outdata);
+
+	case CTDB_CONTROL_GET_NODEMAPv4:
+		return ctdb_control_getnodemapv4(ctdb, opcode, indata, outdata);
+
+	case CTDB_CONTROL_GET_NODEMAP:
+		return ctdb_control_getnodemap(ctdb, opcode, indata, outdata);
+
+	case CTDB_CONTROL_RELOAD_NODES_FILE:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_reload_nodes_file(ctdb, opcode);
+
+	case CTDB_CONTROL_SETVNNMAP:
+		return ctdb_control_setvnnmap(ctdb, opcode, indata, outdata);
+
+	case CTDB_CONTROL_PULL_DB: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_pulldb));
+		return ctdb_control_pull_db(ctdb, indata, outdata);
+
+	case CTDB_CONTROL_SET_DMASTER: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_set_dmaster));
+		return ctdb_control_set_dmaster(ctdb, indata);
+
+	case CTDB_CONTROL_PUSH_DB:
+		return ctdb_control_push_db(ctdb, indata);
+
+	case CTDB_CONTROL_GET_RECMODE: {
+		int i;
+		if (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE) {
+			return CTDB_RECOVERY_ACTIVE;
+		}		  
+		for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+			if (ctdb->freeze_mode[i] == CTDB_FREEZE_FROZEN) {
+				return CTDB_RECOVERY_ACTIVE;
+			}
+		}
+		return CTDB_RECOVERY_NORMAL;
+	}
+
+	case CTDB_CONTROL_SET_RECMASTER: {
+		return ctdb_control_set_recmaster(ctdb, opcode, indata);
+	}
+
+	case CTDB_CONTROL_GET_RECMASTER:
+		return ctdb->recovery_master;
+
+	case CTDB_CONTROL_GET_PID:
+		return getpid();
+
+	case CTDB_CONTROL_GET_PNN:
+		return ctdb->pnn;
+
+	case CTDB_CONTROL_PING:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb->statistics.num_clients;
+
+	case CTDB_CONTROL_SET_DB_READONLY: {
+		uint32_t db_id;
+		struct ctdb_db_context *ctdb_db;
+
+		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
+		db_id = *(uint32_t *)indata.dptr;
+		ctdb_db = find_ctdb_db(ctdb, db_id);
+		if (ctdb_db == NULL) return -1;
+		return ctdb_set_db_readonly(ctdb, ctdb_db);
+	}
+	case CTDB_CONTROL_GET_DBNAME: {
+		uint32_t db_id;
+		struct ctdb_db_context *ctdb_db;
+
+		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
+		db_id = *(uint32_t *)indata.dptr;
+		ctdb_db = find_ctdb_db(ctdb, db_id);
+		if (ctdb_db == NULL) return -1;
+		outdata->dptr = discard_const(ctdb_db->db_name);
+		outdata->dsize = strlen(ctdb_db->db_name)+1;
+		return 0;
+	}
+
+	case CTDB_CONTROL_GETDBPATH: {
+		uint32_t db_id;
+		struct ctdb_db_context *ctdb_db;
+
+		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
+		db_id = *(uint32_t *)indata.dptr;
+		ctdb_db = find_ctdb_db(ctdb, db_id);
+		if (ctdb_db == NULL) return -1;
+		outdata->dptr = discard_const(ctdb_db->db_path);
+		outdata->dsize = strlen(ctdb_db->db_path)+1;
+		return 0;
+	}
+
+	case CTDB_CONTROL_DB_ATTACH:
+	  return ctdb_control_db_attach(ctdb, indata, outdata, srvid, false, client_id, c, async_reply);
+
+	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+	  return ctdb_control_db_attach(ctdb, indata, outdata, srvid, true, client_id, c, async_reply);
+
+	case CTDB_CONTROL_SET_CALL: {
+		struct ctdb_control_set_call *sc = 
+			(struct ctdb_control_set_call *)indata.dptr;
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_set_call));
+		return ctdb_daemon_set_call(ctdb, sc->db_id, sc->fn, sc->id);
+	}
+
+	case CTDB_CONTROL_TRAVERSE_START:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start));
+		return ctdb_control_traverse_start(ctdb, indata, outdata, srcnode, client_id);
+
+	case CTDB_CONTROL_TRAVERSE_ALL:
+		return ctdb_control_traverse_all(ctdb, indata, outdata);
+
+	case CTDB_CONTROL_TRAVERSE_DATA:
+		return ctdb_control_traverse_data(ctdb, indata, outdata);
+
+	case CTDB_CONTROL_TRAVERSE_KILL:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start));
+		return ctdb_control_traverse_kill(ctdb, indata, outdata, srcnode);
+
+	case CTDB_CONTROL_REGISTER_SRVID:
+		return daemon_register_message_handler(ctdb, client_id, srvid);
+
+	case CTDB_CONTROL_DEREGISTER_SRVID:
+		return daemon_deregister_message_handler(ctdb, client_id, srvid);
+
+	case CTDB_CONTROL_ENABLE_SEQNUM:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_ltdb_enable_seqnum(ctdb, *(uint32_t *)indata.dptr);
+
+	case CTDB_CONTROL_UPDATE_SEQNUM:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
+		return ctdb_ltdb_update_seqnum(ctdb, *(uint32_t *)indata.dptr, srcnode);
+
+	case CTDB_CONTROL_FREEZE:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_freeze(ctdb, c, async_reply);
+
+	case CTDB_CONTROL_THAW:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_thaw(ctdb, (uint32_t)c->srvid);
+
+	case CTDB_CONTROL_SET_RECMODE:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
+		return ctdb_control_set_recmode(ctdb, c, indata, async_reply, errormsg);
+
+	case CTDB_CONTROL_GET_MONMODE: 
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_monitoring_mode(ctdb);
+		
+	case CTDB_CONTROL_ENABLE_MONITOR: 
+		CHECK_CONTROL_DATA_SIZE(0);
+		ctdb_enable_monitoring(ctdb);
+		return 0;
+	
+	case CTDB_CONTROL_RUN_EVENTSCRIPTS: 
+		return ctdb_run_eventscripts(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_DISABLE_MONITOR: 
+		CHECK_CONTROL_DATA_SIZE(0);
+		ctdb_disable_monitoring(ctdb);
+		return 0;
+
+	case CTDB_CONTROL_SHUTDOWN:
+		ctdb_stop_recoverd(ctdb);
+		ctdb_stop_keepalive(ctdb);
+		ctdb_stop_monitoring(ctdb);
+		ctdb_release_all_ips(ctdb);
+		if (ctdb->methods != NULL) {
+			ctdb->methods->shutdown(ctdb);
+		}
+		ctdb_event_script(ctdb, CTDB_EVENT_SHUTDOWN);
+		DEBUG(DEBUG_NOTICE,("Received SHUTDOWN command. Stopping CTDB daemon.\n"));
+		exit(0);
+
+	case CTDB_CONTROL_TAKEOVER_IPv4:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ipv4));
+		return ctdb_control_takeover_ipv4(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_TAKEOVER_IP:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip));
+		return ctdb_control_takeover_ip(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_RELEASE_IPv4:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ipv4));
+		return ctdb_control_release_ipv4(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_RELEASE_IP:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip));
+		return ctdb_control_release_ip(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_GET_PUBLIC_IPSv4:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_get_public_ipsv4(ctdb, c, outdata);
+
+	case CTDB_CONTROL_GET_PUBLIC_IPS:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_get_public_ips(ctdb, c, outdata);
+
+	case CTDB_CONTROL_TCP_CLIENT: 
+		return ctdb_control_tcp_client(ctdb, client_id, indata);
+
+	case CTDB_CONTROL_STARTUP: 
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_startup(ctdb, srcnode);
+
+	case CTDB_CONTROL_TCP_ADD: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_tcp_connection));
+		return ctdb_control_tcp_add(ctdb, indata, false);
+
+	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_tcp_connection));
+		return ctdb_control_tcp_add(ctdb, indata, true);
+
+	case CTDB_CONTROL_TCP_REMOVE: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_tcp_connection));
+		return ctdb_control_tcp_remove(ctdb, indata);
+
+	case CTDB_CONTROL_SET_TUNABLE:
+		return ctdb_control_set_tunable(ctdb, indata);
+
+	case CTDB_CONTROL_GET_TUNABLE:
+		return ctdb_control_get_tunable(ctdb, indata, outdata);
+
+	case CTDB_CONTROL_LIST_TUNABLES:
+		return ctdb_control_list_tunables(ctdb, outdata);
+
+	case CTDB_CONTROL_MODIFY_FLAGS:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_node_flag_change));
+		return ctdb_control_modflags(ctdb, indata);
+
+	case CTDB_CONTROL_KILL_TCP: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_killtcp));
+		return ctdb_control_kill_tcp(ctdb, indata);
+
+	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+		CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
+		return ctdb_control_get_tcp_tickle_list(ctdb, indata, outdata);
+
+	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+		/* data size is verified in the called function */
+		return ctdb_control_set_tcp_tickle_list(ctdb, indata);
+
+	case CTDB_CONTROL_REGISTER_SERVER_ID: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
+		return ctdb_control_register_server_id(ctdb, client_id, indata);
+
+	case CTDB_CONTROL_UNREGISTER_SERVER_ID: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
+		return ctdb_control_unregister_server_id(ctdb, indata);
+
+	case CTDB_CONTROL_CHECK_SERVER_ID: 
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
+		return ctdb_control_check_server_id(ctdb, indata);
+
+	case CTDB_CONTROL_GET_SERVER_ID_LIST:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_get_server_id_list(ctdb, outdata);
+
+	case CTDB_CONTROL_PERSISTENT_STORE:
+		return ctdb_control_persistent_store(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_UPDATE_RECORD:
+		return ctdb_control_update_record(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_SEND_GRATIOUS_ARP:
+		return ctdb_control_send_gratious_arp(ctdb, indata);
+
+	case CTDB_CONTROL_TRANSACTION_START:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_transaction_start(ctdb, *(uint32_t *)indata.dptr);
+
+	case CTDB_CONTROL_TRANSACTION_COMMIT:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_transaction_commit(ctdb, *(uint32_t *)indata.dptr);
+
+	case CTDB_CONTROL_WIPE_DATABASE:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_wipe_database));
+		return ctdb_control_wipe_database(ctdb, indata);
+
+	case CTDB_CONTROL_UPTIME:
+		return ctdb_control_uptime(ctdb, outdata);
+
+	case CTDB_CONTROL_START_RECOVERY:
+		return ctdb_control_start_recovery(ctdb, c, async_reply);
+
+	case CTDB_CONTROL_END_RECOVERY:
+		return ctdb_control_end_recovery(ctdb, c, async_reply);
+
+	case CTDB_CONTROL_TRY_DELETE_RECORDS:
+		return ctdb_control_try_delete_records(ctdb, indata, outdata);
+
+	case CTDB_CONTROL_ADD_PUBLIC_IP:
+		return ctdb_control_add_public_address(ctdb, indata);
+
+	case CTDB_CONTROL_DEL_PUBLIC_IP:
+		return ctdb_control_del_public_address(ctdb, indata);
+
+	case CTDB_CONTROL_GET_CAPABILITIES:
+		return ctdb_control_get_capabilities(ctdb, outdata);
+
+	case CTDB_CONTROL_START_PERSISTENT_UPDATE:
+		return ctdb_control_start_persistent_update(ctdb, c, indata);
+
+	case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
+		return ctdb_control_cancel_persistent_update(ctdb, c, indata);
+
+	case CTDB_CONTROL_TRANS2_COMMIT:
+	case CTDB_CONTROL_TRANS2_COMMIT_RETRY:
+		return ctdb_control_trans2_commit(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_TRANS2_ERROR:
+		return ctdb_control_trans2_error(ctdb, c);
+
+	case CTDB_CONTROL_TRANS2_FINISHED:
+		return ctdb_control_trans2_finished(ctdb, c);
+
+	case CTDB_CONTROL_TRANS2_ACTIVE:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_trans2_active(ctdb, c, *(uint32_t *)indata.dptr);
+
+	case CTDB_CONTROL_TRANS3_COMMIT:
+		return ctdb_control_trans3_commit(ctdb, c, indata, async_reply);
+
+	case CTDB_CONTROL_RECD_PING:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_recd_ping(ctdb);
+
+	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_get_event_script_status(ctdb, *(uint32_t *)indata.dptr, outdata);
+
+	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+		CHECK_CONTROL_DATA_SIZE(sizeof(double));
+		CTDB_UPDATE_RECLOCK_LATENCY(ctdb, "recd reclock", reclock.recd, *((double *)indata.dptr));
+		return 0;
+	case CTDB_CONTROL_GET_RECLOCK_FILE:
+		CHECK_CONTROL_DATA_SIZE(0);
+		if (ctdb->recovery_lock_file != NULL) {
+			outdata->dptr  = discard_const(ctdb->recovery_lock_file);
+			outdata->dsize = strlen(ctdb->recovery_lock_file) + 1;
+		}
+		return 0;
+	case CTDB_CONTROL_SET_RECLOCK_FILE:
+		ctdb->tunable.verify_recovery_lock = 0;
+		if (ctdb->recovery_lock_file != NULL) {
+			talloc_free(ctdb->recovery_lock_file);
+			ctdb->recovery_lock_file = NULL;
+		}
+		if (indata.dsize > 0) {
+			ctdb->recovery_lock_file = talloc_strdup(ctdb, discard_const(indata.dptr));
+			ctdb->tunable.verify_recovery_lock = 1;
+		}
+		return 0;
+
+	case CTDB_CONTROL_STOP_NODE:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_stop_node(ctdb, c, async_reply);
+
+	case CTDB_CONTROL_CONTINUE_NODE:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_continue_node(ctdb);
+
+	case CTDB_CONTROL_SET_NATGWSTATE: {
+		uint32_t natgwstate;
+
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
+		natgwstate = *(uint32_t *)indata.dptr;
+		if (natgwstate == 0) {
+			ctdb->capabilities &= ~CTDB_CAP_NATGW;
+		} else {
+			ctdb->capabilities |= CTDB_CAP_NATGW;
+		}
+		return 0;
+	}
+
+	case CTDB_CONTROL_SET_LMASTERROLE: {
+		uint32_t lmasterrole;
+
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
+		lmasterrole = *(uint32_t *)indata.dptr;
+		if (lmasterrole == 0) {
+			ctdb->capabilities &= ~CTDB_CAP_LMASTER;
+		} else {
+			ctdb->capabilities |= CTDB_CAP_LMASTER;
+		}
+		return 0;
+	}
+
+	case CTDB_CONTROL_SET_RECMASTERROLE: {
+		uint32_t recmasterrole;
+
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
+		recmasterrole = *(uint32_t *)indata.dptr;
+		if (recmasterrole == 0) {
+			ctdb->capabilities &= ~CTDB_CAP_RECMASTER;
+		} else {
+			ctdb->capabilities |= CTDB_CAP_RECMASTER;
+		}
+		return 0;
+	}
+
+	case CTDB_CONTROL_ENABLE_SCRIPT:
+		return ctdb_control_enable_script(ctdb, indata);
+
+	case CTDB_CONTROL_DISABLE_SCRIPT:
+		return ctdb_control_disable_script(ctdb, indata);
+
+	case CTDB_CONTROL_SET_BAN_STATE:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_ban_time));
+		return ctdb_control_set_ban_state(ctdb, indata);
+
+	case CTDB_CONTROL_GET_BAN_STATE:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_get_ban_state(ctdb, outdata);
+
+	case CTDB_CONTROL_SET_DB_PRIORITY:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_db_priority));
+		return ctdb_control_set_db_priority(ctdb, indata);
+
+	case CTDB_CONTROL_GET_DB_PRIORITY: {
+		uint32_t db_id;
+		struct ctdb_db_context *ctdb_db;
+
+		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
+		db_id = *(uint32_t *)indata.dptr;
+		ctdb_db = find_ctdb_db(ctdb, db_id);
+		if (ctdb_db == NULL) return -1;
+		return ctdb_db->priority;
+	}
+
+	case CTDB_CONTROL_TRANSACTION_CANCEL:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_transaction_cancel(ctdb);
+
+	case CTDB_CONTROL_REGISTER_NOTIFY:
+		return ctdb_control_register_notify(ctdb, client_id, indata);
+
+	case CTDB_CONTROL_DEREGISTER_NOTIFY:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_notify_deregister));
+		return ctdb_control_deregister_notify(ctdb, client_id, indata);
+
+	case CTDB_CONTROL_GET_LOG:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_get_log_addr));
+		return ctdb_control_get_log(ctdb, indata);
+
+	case CTDB_CONTROL_CLEAR_LOG:
+		return ctdb_control_clear_log(ctdb);
+
+	case CTDB_CONTROL_GET_DB_SEQNUM:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t));
+		return ctdb_control_get_db_seqnum(ctdb, indata, outdata);
+
+	case CTDB_CONTROL_DB_SET_HEALTHY:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_db_set_healthy(ctdb, indata);
+
+	case CTDB_CONTROL_DB_GET_HEALTH:
+		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+		return ctdb_control_db_get_health(ctdb, indata, outdata);
+
+	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+		CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
+		return ctdb_control_get_public_ip_info(ctdb, c, indata, outdata);
+
+	case CTDB_CONTROL_GET_IFACES:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_get_ifaces(ctdb, c, outdata);
+
+	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_iface_info));
+		return ctdb_control_set_iface_link(ctdb, c, indata);
+
+	case CTDB_CONTROL_GET_STAT_HISTORY:
+		CHECK_CONTROL_DATA_SIZE(0);
+		return ctdb_control_get_stat_history(ctdb, c, outdata);
+
+	case CTDB_CONTROL_SCHEDULE_FOR_DELETION: {
+		struct ctdb_control_schedule_for_deletion *d;
+		size_t size = offsetof(struct ctdb_control_schedule_for_deletion, key);
+		CHECK_CONTROL_MIN_DATA_SIZE(size);
+		d = (struct ctdb_control_schedule_for_deletion *)indata.dptr;
+		size += d->keylen;
+		CHECK_CONTROL_DATA_SIZE(size);
+		return ctdb_control_schedule_for_deletion(ctdb, indata);
+	}
+	default:
+		DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
+		return -1;
+	}
+}
+
+/*
+  send a reply for a ctdb control
+ */
+void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c,
+				TDB_DATA *outdata, int32_t status, const char *errormsg)
+{
+	struct ctdb_reply_control *r;
+	size_t len;
+	
+	/* some controls send no reply */
+	if (c->flags & CTDB_CTRL_FLAG_NOREPLY) {
+		return;
+	}
+
+	len = offsetof(struct ctdb_reply_control, data) + (outdata?outdata->dsize:0);
+	if (errormsg) {
+		len += strlen(errormsg);
+	}
+	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CONTROL, len, struct ctdb_reply_control);
+	CTDB_NO_MEMORY_VOID(ctdb, r);
+
+	r->hdr.destnode     = c->hdr.srcnode;
+	r->hdr.reqid        = c->hdr.reqid;
+	r->status           = status;
+	r->datalen          = outdata?outdata->dsize:0;
+	if (outdata && outdata->dsize) {
+		memcpy(&r->data[0], outdata->dptr, outdata->dsize);
+	}
+	if (errormsg) {
+		r->errorlen = strlen(errormsg);
+		memcpy(&r->data[r->datalen], errormsg, r->errorlen);
+	}
+
+	ctdb_queue_packet_opcode(ctdb, &r->hdr, c->opcode);	
+
+	talloc_free(r);
+}
+
+/*
+  called when a CTDB_REQ_CONTROL packet comes in
+*/
+void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_req_control *c = (struct ctdb_req_control *)hdr;
+	TDB_DATA data, *outdata;
+	int32_t status;
+	bool async_reply = False;
+	const char *errormsg = NULL;
+
+	data.dptr = &c->data[0];
+	data.dsize = c->datalen;
+
+	outdata = talloc_zero(c, TDB_DATA);
+
+	status = ctdb_control_dispatch(ctdb, c, data, outdata, hdr->srcnode, 
+				       &errormsg, &async_reply);
+
+	if (!async_reply) {
+		ctdb_request_control_reply(ctdb, c, outdata, status, errormsg);
+	}
+}
+
+/*
+  called when a CTDB_REPLY_CONTROL packet comes in
+*/
+void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
+	TDB_DATA data;
+	struct ctdb_control_state *state;
+	const char *errormsg = NULL;
+
+	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_control_state);
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_reply_control\n",
+			 ctdb->pnn, hdr->reqid));
+		return;
+	}
+
+	if (hdr->reqid != state->reqid) {
+		/* we found a record  but it was the wrong one */
+		DEBUG(DEBUG_ERR, ("Dropped orphaned control reply with reqid:%u\n", hdr->reqid));
+		return;
+	}
+
+	data.dptr = &c->data[0];
+	data.dsize = c->datalen;
+	if (c->errorlen) {
+		errormsg = talloc_strndup(state, 
+					  (char *)&c->data[c->datalen], c->errorlen);
+	}
+
+	/* make state a child of the packet, so it goes away when the packet
+	   is freed. */
+	talloc_steal(hdr, state);
+
+	state->callback(ctdb, c->status, data, errormsg, state->private_data);
+}
+
+static int ctdb_control_destructor(struct ctdb_control_state *state)
+{
+	ctdb_reqid_remove(state->ctdb, state->reqid);
+	return 0;
+}
+
+/*
+  handle a timeout of a control
+ */
+static void ctdb_control_timeout(struct event_context *ev, struct timed_event *te, 
+		       struct timeval t, void *private_data)
+{
+	struct ctdb_control_state *state = talloc_get_type(private_data, struct ctdb_control_state);
+	TALLOC_CTX *tmp_ctx = talloc_new(ev);
+
+	CTDB_INCREMENT_STAT(state->ctdb, timeouts.control);
+
+	talloc_steal(tmp_ctx, state);
+
+	state->callback(state->ctdb, -1, tdb_null,
+			"ctdb_control timed out", 
+			state->private_data);
+	talloc_free(tmp_ctx);
+}
+
+
+/*
+  send a control message to a node
+ */
+int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
+			     uint64_t srvid, uint32_t opcode, uint32_t client_id,
+			     uint32_t flags,
+			     TDB_DATA data,
+			     ctdb_control_callback_fn_t callback,
+			     void *private_data)
+{
+	struct ctdb_req_control *c;
+	struct ctdb_control_state *state;
+	size_t len;
+
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " Failed to send control. Transport is DOWN\n"));
+		return -1;
+	}
+
+	if (((destnode == CTDB_BROADCAST_VNNMAP) || 
+	     (destnode == CTDB_BROADCAST_ALL) ||
+	     (destnode == CTDB_BROADCAST_CONNECTED)) && 
+	    !(flags & CTDB_CTRL_FLAG_NOREPLY)) {
+		DEBUG(DEBUG_CRIT,("Attempt to broadcast control without NOREPLY\n"));
+		return -1;
+	}
+
+	if (destnode != CTDB_BROADCAST_VNNMAP && 
+	    destnode != CTDB_BROADCAST_ALL && 
+	    destnode != CTDB_BROADCAST_CONNECTED && 
+	    (!ctdb_validate_pnn(ctdb, destnode) || 
+	     (ctdb->nodes[destnode]->flags & NODE_FLAGS_DISCONNECTED))) {
+		if (!(flags & CTDB_CTRL_FLAG_NOREPLY)) {
+			callback(ctdb, -1, tdb_null, "ctdb_control to disconnected node", private_data);
+		}
+		return 0;
+	}
+
+	/* the state is made a child of private_data if possible. This means any reply
+	   will be discarded if the private_data goes away */
+	state = talloc(private_data?private_data:ctdb, struct ctdb_control_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->reqid = ctdb_reqid_new(ctdb, state);
+	state->callback = callback;
+	state->private_data = private_data;
+	state->ctdb = ctdb;
+	state->flags = flags;
+
+	talloc_set_destructor(state, ctdb_control_destructor);
+
+	len = offsetof(struct ctdb_req_control, data) + data.dsize;
+	c = ctdb_transport_allocate(ctdb, state, CTDB_REQ_CONTROL, len, 
+				    struct ctdb_req_control);
+	CTDB_NO_MEMORY(ctdb, c);
+	talloc_set_name_const(c, "ctdb_req_control packet");
+
+	c->hdr.destnode     = destnode;
+	c->hdr.reqid        = state->reqid;
+	c->opcode           = opcode;
+	c->client_id        = client_id;
+	c->flags            = flags;
+	c->srvid            = srvid;
+	c->datalen          = data.dsize;
+	if (data.dsize) {
+		memcpy(&c->data[0], data.dptr, data.dsize);
+	}
+
+	ctdb_queue_packet(ctdb, &c->hdr);	
+
+	if (flags & CTDB_CTRL_FLAG_NOREPLY) {
+		talloc_free(state);
+		return 0;
+	}
+
+	if (ctdb->tunable.control_timeout) {
+		event_add_timed(ctdb->ev, state, 
+				timeval_current_ofs(ctdb->tunable.control_timeout, 0), 
+				ctdb_control_timeout, state);
+	}
+
+	talloc_free(c);
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_daemon.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_daemon.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_daemon.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1371 @@
+/* 
+   ctdb daemon code
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "db_wrap.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/tevent/tevent.h"
+#include "lib/util/dlinklist.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_client.h"
+#include "../include/ctdb_private.h"
+#include <sys/socket.h>
+
+struct ctdb_client_pid_list {
+	struct ctdb_client_pid_list *next, *prev;
+	struct ctdb_context *ctdb;
+	pid_t pid;
+	struct ctdb_client *client;
+};
+
+static void daemon_incoming_packet(void *, struct ctdb_req_header *);
+
+static void print_exit_message(void)
+{
+	DEBUG(DEBUG_NOTICE,("CTDB daemon shutting down\n"));
+}
+
+
+
+static void ctdb_time_tick(struct event_context *ev, struct timed_event *te, 
+				  struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+
+	if (getpid() != ctdbd_pid) {
+		return;
+	}
+
+	event_add_timed(ctdb->ev, ctdb, 
+			timeval_current_ofs(1, 0), 
+			ctdb_time_tick, ctdb);
+}
+
+/* Used to trigger a dummy event once per second, to make
+ * detection of hangs more reliable.
+ */
+static void ctdb_start_time_tickd(struct ctdb_context *ctdb)
+{
+	event_add_timed(ctdb->ev, ctdb, 
+			timeval_current_ofs(1, 0), 
+			ctdb_time_tick, ctdb);
+}
+
+
+/* called when the "startup" event script has finished */
+static void ctdb_start_transport(struct ctdb_context *ctdb)
+{
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_ALERT,(__location__ " startup event finished but transport is DOWN.\n"));
+		ctdb_fatal(ctdb, "transport is not initialized but startup completed");
+	}
+
+	/* start the transport running */
+	if (ctdb->methods->start(ctdb) != 0) {
+		DEBUG(DEBUG_ALERT,("transport failed to start!\n"));
+		ctdb_fatal(ctdb, "transport failed to start");
+	}
+
+	/* start the recovery daemon process */
+	if (ctdb_start_recoverd(ctdb) != 0) {
+		DEBUG(DEBUG_ALERT,("Failed to start recovery daemon\n"));
+		exit(11);
+	}
+
+	/* Make sure we log something when the daemon terminates */
+	atexit(print_exit_message);
+
+	/* start monitoring for connected/disconnected nodes */
+	ctdb_start_keepalive(ctdb);
+
+	/* start monitoring for node health */
+	ctdb_start_monitoring(ctdb);
+
+	/* start periodic update of tcp tickle lists */
+       	ctdb_start_tcp_tickle_update(ctdb);
+
+	/* start listening for recovery daemon pings */
+	ctdb_control_recd_ping(ctdb);
+
+	/* start listening to timer ticks */
+	ctdb_start_time_tickd(ctdb);
+}
+
+static void block_signal(int signum)
+{
+	struct sigaction act;
+
+	memset(&act, 0, sizeof(act));
+
+	act.sa_handler = SIG_IGN;
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask, signum);
+	sigaction(signum, &act, NULL);
+}
+
+
+/*
+  send a packet to a client
+ */
+static int daemon_queue_send(struct ctdb_client *client, struct ctdb_req_header *hdr)
+{
+	CTDB_INCREMENT_STAT(client->ctdb, client_packets_sent);
+	if (hdr->operation == CTDB_REQ_MESSAGE) {
+		if (ctdb_queue_length(client->queue) > client->ctdb->tunable.max_queue_depth_drop_msg) {
+			DEBUG(DEBUG_ERR,("CTDB_REQ_MESSAGE queue full - killing client connection.\n"));
+			talloc_free(client);
+			return -1;
+		}
+	}
+	return ctdb_queue_send(client->queue, (uint8_t *)hdr, hdr->length);
+}
+
+/*
+  message handler for when we are in daemon mode. This redirects the message
+  to the right client
+ */
+static void daemon_message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+				    TDB_DATA data, void *private_data)
+{
+	struct ctdb_client *client = talloc_get_type(private_data, struct ctdb_client);
+	struct ctdb_req_message *r;
+	int len;
+
+	/* construct a message to send to the client containing the data */
+	len = offsetof(struct ctdb_req_message, data) + data.dsize;
+	r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE, 
+			       len, struct ctdb_req_message);
+	CTDB_NO_MEMORY_VOID(ctdb, r);
+
+	talloc_set_name_const(r, "req_message packet");
+
+	r->srvid         = srvid;
+	r->datalen       = data.dsize;
+	memcpy(&r->data[0], data.dptr, data.dsize);
+
+	daemon_queue_send(client, &r->hdr);
+
+	talloc_free(r);
+}
+
+/*
+  this is called when the ctdb daemon received a ctdb request to 
+  set the srvid from the client
+ */
+int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid)
+{
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+	int res;
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,("Bad client_id in daemon_request_register_message_handler\n"));
+		return -1;
+	}
+	res = ctdb_register_message_handler(ctdb, client, srvid, daemon_message_handler, client);
+	if (res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to register handler %llu in daemon\n", 
+			 (unsigned long long)srvid));
+	} else {
+		DEBUG(DEBUG_INFO,(__location__ " Registered message handler for srvid=%llu\n", 
+			 (unsigned long long)srvid));
+	}
+
+	return res;
+}
+
+/*
+  this is called when the ctdb daemon received a ctdb request to 
+  remove a srvid from the client
+ */
+int daemon_deregister_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid)
+{
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,("Bad client_id in daemon_request_deregister_message_handler\n"));
+		return -1;
+	}
+	return ctdb_deregister_message_handler(ctdb, srvid, client);
+}
+
+
+/*
+  destroy a ctdb_client
+*/
+static int ctdb_client_destructor(struct ctdb_client *client)
+{
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_takeover_client_destructor_hook(client);
+	ctdb_reqid_remove(client->ctdb, client->client_id);
+	CTDB_DECREMENT_STAT(client->ctdb, num_clients);
+
+	if (client->num_persistent_updates != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Client disconnecting with %u persistent updates in flight. Starting recovery\n", client->num_persistent_updates));
+		client->ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+	}
+	ctdb_db = find_ctdb_db(client->ctdb, client->db_id);
+	if (ctdb_db) {
+		DEBUG(DEBUG_ERR, (__location__ " client exit while transaction "
+				  "commit active. Forcing recovery.\n"));
+		client->ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+
+		/* legacy trans2 transaction state: */
+		ctdb_db->transaction_active = false;
+
+		/*
+		 * trans3 transaction state:
+		 *
+		 * The destructor sets the pointer to NULL.
+		 */
+		talloc_free(ctdb_db->persistent_state);
+	}
+
+	return 0;
+}
+
+
+/*
+  this is called when the ctdb daemon received a ctdb request message
+  from a local client over the unix domain socket
+ */
+static void daemon_request_message_from_client(struct ctdb_client *client, 
+					       struct ctdb_req_message *c)
+{
+	TDB_DATA data;
+	int res;
+
+	/* maybe the message is for another client on this node */
+	if (ctdb_get_pnn(client->ctdb)==c->hdr.destnode) {
+		ctdb_request_message(client->ctdb, (struct ctdb_req_header *)c);
+		return;
+	}
+
+	/* its for a remote node */
+	data.dptr = &c->data[0];
+	data.dsize = c->datalen;
+	res = ctdb_daemon_send_message(client->ctdb, c->hdr.destnode,
+				       c->srvid, data);
+	if (res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to send message to remote node %u\n",
+			 c->hdr.destnode));
+	}
+}
+
+
+struct daemon_call_state {
+	struct ctdb_client *client;
+	uint32_t reqid;
+	struct ctdb_call *call;
+	struct timeval start_time;
+};
+
+/* 
+   complete a call from a client 
+*/
+static void daemon_call_from_client_callback(struct ctdb_call_state *state)
+{
+	struct daemon_call_state *dstate = talloc_get_type(state->async.private_data, 
+							   struct daemon_call_state);
+	struct ctdb_reply_call *r;
+	int res;
+	uint32_t length;
+	struct ctdb_client *client = dstate->client;
+	struct ctdb_db_context *ctdb_db = state->ctdb_db;
+
+	talloc_steal(client, dstate);
+	talloc_steal(dstate, dstate->call);
+
+	res = ctdb_daemon_call_recv(state, dstate->call);
+	if (res != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " ctdbd_call_recv() returned error\n"));
+		CTDB_DECREMENT_STAT(client->ctdb, pending_calls);
+
+		CTDB_UPDATE_LATENCY(client->ctdb, ctdb_db, "call_from_client_cb 1", call_latency, dstate->start_time);
+		return;
+	}
+
+	length = offsetof(struct ctdb_reply_call, data) + dstate->call->reply_data.dsize;
+	r = ctdbd_allocate_pkt(client->ctdb, dstate, CTDB_REPLY_CALL, 
+			       length, struct ctdb_reply_call);
+	if (r == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to allocate reply_call in ctdb daemon\n"));
+		CTDB_DECREMENT_STAT(client->ctdb, pending_calls);
+		CTDB_UPDATE_LATENCY(client->ctdb, ctdb_db, "call_from_client_cb 2", call_latency, dstate->start_time);
+		return;
+	}
+	r->hdr.reqid        = dstate->reqid;
+	r->datalen          = dstate->call->reply_data.dsize;
+	r->status           = dstate->call->status;
+	memcpy(&r->data[0], dstate->call->reply_data.dptr, r->datalen);
+
+	res = daemon_queue_send(client, &r->hdr);
+	if (res == -1) {
+		/* client is dead - return immediately */
+		return;
+	}
+	if (res != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to queue packet from daemon to client\n"));
+	}
+	CTDB_UPDATE_LATENCY(client->ctdb, ctdb_db, "call_from_client_cb 3", call_latency, dstate->start_time);
+	CTDB_DECREMENT_STAT(client->ctdb, pending_calls);
+	talloc_free(dstate);
+}
+
+struct ctdb_daemon_packet_wrap {
+	struct ctdb_context *ctdb;
+	uint32_t client_id;
+};
+
+/*
+  a wrapper to catch disconnected clients
+ */
+static void daemon_incoming_packet_wrap(void *p, struct ctdb_req_header *hdr)
+{
+	struct ctdb_client *client;
+	struct ctdb_daemon_packet_wrap *w = talloc_get_type(p, 
+							    struct ctdb_daemon_packet_wrap);
+	if (w == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Bad packet type '%s'\n", talloc_get_name(p)));
+		return;
+	}
+
+	client = ctdb_reqid_find(w->ctdb, w->client_id, struct ctdb_client);
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Packet for disconnected client %u\n",
+			 w->client_id));
+		talloc_free(w);
+		return;
+	}
+	talloc_free(w);
+
+	/* process it */
+	daemon_incoming_packet(client, hdr);	
+}
+
+
+/*
+  this is called when the ctdb daemon received a ctdb request call
+  from a local client over the unix domain socket
+ */
+static void daemon_request_call_from_client(struct ctdb_client *client, 
+					    struct ctdb_req_call *c)
+{
+	struct ctdb_call_state *state;
+	struct ctdb_db_context *ctdb_db;
+	struct daemon_call_state *dstate;
+	struct ctdb_call *call;
+	struct ctdb_ltdb_header header;
+	TDB_DATA key, data;
+	int ret;
+	struct ctdb_context *ctdb = client->ctdb;
+	struct ctdb_daemon_packet_wrap *w;
+
+	CTDB_INCREMENT_STAT(ctdb, total_calls);
+	CTDB_DECREMENT_STAT(ctdb, pending_calls);
+
+	ctdb_db = find_ctdb_db(client->ctdb, c->db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR, (__location__ " Unknown database in request. db_id==0x%08x",
+			  c->db_id));
+		CTDB_DECREMENT_STAT(ctdb, pending_calls);
+		return;
+	}
+
+	if (ctdb_db->unhealthy_reason) {
+		/*
+		 * this is just a warning, as the tdb should be empty anyway,
+		 * and only persistent databases can be unhealthy, which doesn't
+		 * use this code patch
+		 */
+		DEBUG(DEBUG_WARNING,("warn: db(%s) unhealty in daemon_request_call_from_client(): %s\n",
+				     ctdb_db->db_name, ctdb_db->unhealthy_reason));
+	}
+
+	key.dptr = c->data;
+	key.dsize = c->keylen;
+
+	w = talloc(ctdb, struct ctdb_daemon_packet_wrap);
+	CTDB_NO_MEMORY_VOID(ctdb, w);	
+
+	w->ctdb = ctdb;
+	w->client_id = client->client_id;
+
+	ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, key, &header, 
+					   (struct ctdb_req_header *)c, &data,
+					   daemon_incoming_packet_wrap, w, True);
+	if (ret == -2) {
+		/* will retry later */
+		CTDB_DECREMENT_STAT(ctdb, pending_calls);
+		return;
+	}
+
+	talloc_free(w);
+
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Unable to fetch record\n"));
+		CTDB_DECREMENT_STAT(ctdb, pending_calls);
+		return;
+	}
+
+	/* Dont do READONLY if we dont have a tracking database */
+	if ((c->flags & CTDB_WANT_READONLY) && !ctdb_db->readonly) {
+		c->flags &= ~CTDB_WANT_READONLY;
+	}
+
+	if (header.flags & CTDB_REC_RO_REVOKE_COMPLETE) {
+		header.flags &= ~(CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY|CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_REVOKE_COMPLETE);
+		if (ctdb_ltdb_store(ctdb_db, key, &header, data) != 0) {
+			ctdb_fatal(ctdb, "Failed to write header with cleared REVOKE flag");
+		}
+		/* and clear out the tracking data */
+		if (tdb_delete(ctdb_db->rottdb, key) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to clear out trackingdb record\n"));
+		}
+	}
+
+	/* if we are revoking, we must defer all other calls until the revoke
+	 * had completed.
+	 */
+	if (header.flags & CTDB_REC_RO_REVOKING_READONLY) {
+		talloc_free(data.dptr);
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+
+		if (ctdb_add_revoke_deferred_call(ctdb, ctdb_db, key, (struct ctdb_req_header *)c, daemon_incoming_packet, client) != 0) {
+			ctdb_fatal(ctdb, "Failed to add deferred call for revoke child");
+		}
+		return;
+	}
+
+	if ((header.dmaster == ctdb->pnn)
+	&& (!(c->flags & CTDB_WANT_READONLY))
+	&& (header.flags & (CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY)) ) {
+		header.flags   |= CTDB_REC_RO_REVOKING_READONLY;
+		if (ctdb_ltdb_store(ctdb_db, key, &header, data) != 0) {
+			ctdb_fatal(ctdb, "Failed to store record with HAVE_DELEGATIONS set");
+		}
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+
+		if (ctdb_start_revoke_ro_record(ctdb, ctdb_db, key, &header, data) != 0) {
+			ctdb_fatal(ctdb, "Failed to start record revoke");
+		}
+		talloc_free(data.dptr);
+
+		if (ctdb_add_revoke_deferred_call(ctdb, ctdb_db, key, (struct ctdb_req_header *)c, daemon_incoming_packet, client) != 0) {
+			ctdb_fatal(ctdb, "Failed to add deferred call for revoke child");
+		}
+
+		return;
+	}		
+
+	dstate = talloc(client, struct daemon_call_state);
+	if (dstate == NULL) {
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+
+		DEBUG(DEBUG_ERR,(__location__ " Unable to allocate dstate\n"));
+		CTDB_DECREMENT_STAT(ctdb, pending_calls);
+		return;
+	}
+	dstate->start_time = timeval_current();
+	dstate->client = client;
+	dstate->reqid  = c->hdr.reqid;
+	talloc_steal(dstate, data.dptr);
+
+	call = dstate->call = talloc_zero(dstate, struct ctdb_call);
+	if (call == NULL) {
+		ret = ctdb_ltdb_unlock(ctdb_db, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+		}
+
+		DEBUG(DEBUG_ERR,(__location__ " Unable to allocate call\n"));
+		CTDB_DECREMENT_STAT(ctdb, pending_calls);
+		CTDB_UPDATE_LATENCY(ctdb, ctdb_db, "call_from_client 1", call_latency, dstate->start_time);
+		return;
+	}
+
+	call->call_id = c->callid;
+	call->key = key;
+	call->call_data.dptr = c->data + c->keylen;
+	call->call_data.dsize = c->calldatalen;
+	call->flags = c->flags;
+
+	if (header.dmaster == ctdb->pnn) {
+		state = ctdb_call_local_send(ctdb_db, call, &header, &data);
+	} else {
+		state = ctdb_daemon_call_send_remote(ctdb_db, call, &header);
+	}
+
+	ret = ctdb_ltdb_unlock(ctdb_db, key);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", ret));
+	}
+
+	if (state == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Unable to setup call send\n"));
+		CTDB_DECREMENT_STAT(ctdb, pending_calls);
+		CTDB_UPDATE_LATENCY(ctdb, ctdb_db, "call_from_client 2", call_latency, dstate->start_time);
+		return;
+	}
+	talloc_steal(state, dstate);
+	talloc_steal(client, state);
+
+	state->async.fn = daemon_call_from_client_callback;
+	state->async.private_data = dstate;
+}
+
+
+static void daemon_request_control_from_client(struct ctdb_client *client, 
+					       struct ctdb_req_control *c);
+
+/* data contains a packet from the client */
+static void daemon_incoming_packet(void *p, struct ctdb_req_header *hdr)
+{
+	struct ctdb_client *client = talloc_get_type(p, struct ctdb_client);
+	TALLOC_CTX *tmp_ctx;
+	struct ctdb_context *ctdb = client->ctdb;
+
+	/* place the packet as a child of a tmp_ctx. We then use
+	   talloc_free() below to free it. If any of the calls want
+	   to keep it, then they will steal it somewhere else, and the
+	   talloc_free() will be a no-op */
+	tmp_ctx = talloc_new(client);
+	talloc_steal(tmp_ctx, hdr);
+
+	if (hdr->ctdb_magic != CTDB_MAGIC) {
+		ctdb_set_error(client->ctdb, "Non CTDB packet rejected in daemon\n");
+		goto done;
+	}
+
+	if (hdr->ctdb_version != CTDB_VERSION) {
+		ctdb_set_error(client->ctdb, "Bad CTDB version 0x%x rejected in daemon\n", hdr->ctdb_version);
+		goto done;
+	}
+
+	switch (hdr->operation) {
+	case CTDB_REQ_CALL:
+		CTDB_INCREMENT_STAT(ctdb, client.req_call);
+		daemon_request_call_from_client(client, (struct ctdb_req_call *)hdr);
+		break;
+
+	case CTDB_REQ_MESSAGE:
+		CTDB_INCREMENT_STAT(ctdb, client.req_message);
+		daemon_request_message_from_client(client, (struct ctdb_req_message *)hdr);
+		break;
+
+	case CTDB_REQ_CONTROL:
+		CTDB_INCREMENT_STAT(ctdb, client.req_control);
+		daemon_request_control_from_client(client, (struct ctdb_req_control *)hdr);
+		break;
+
+	default:
+		DEBUG(DEBUG_CRIT,(__location__ " daemon: unrecognized operation %u\n",
+			 hdr->operation));
+	}
+
+done:
+	talloc_free(tmp_ctx);
+}
+
+/*
+  called when the daemon gets a incoming packet
+ */
+static void ctdb_daemon_read_cb(uint8_t *data, size_t cnt, void *args)
+{
+	struct ctdb_client *client = talloc_get_type(args, struct ctdb_client);
+	struct ctdb_req_header *hdr;
+
+	if (cnt == 0) {
+		talloc_free(client);
+		return;
+	}
+
+	CTDB_INCREMENT_STAT(client->ctdb, client_packets_recv);
+
+	if (cnt < sizeof(*hdr)) {
+		ctdb_set_error(client->ctdb, "Bad packet length %u in daemon\n", 
+			       (unsigned)cnt);
+		return;
+	}
+	hdr = (struct ctdb_req_header *)data;
+	if (cnt != hdr->length) {
+		ctdb_set_error(client->ctdb, "Bad header length %u expected %u\n in daemon", 
+			       (unsigned)hdr->length, (unsigned)cnt);
+		return;
+	}
+
+	if (hdr->ctdb_magic != CTDB_MAGIC) {
+		ctdb_set_error(client->ctdb, "Non CTDB packet rejected\n");
+		return;
+	}
+
+	if (hdr->ctdb_version != CTDB_VERSION) {
+		ctdb_set_error(client->ctdb, "Bad CTDB version 0x%x rejected in daemon\n", hdr->ctdb_version);
+		return;
+	}
+
+	DEBUG(DEBUG_DEBUG,(__location__ " client request %u of type %u length %u from "
+		 "node %u to %u\n", hdr->reqid, hdr->operation, hdr->length,
+		 hdr->srcnode, hdr->destnode));
+
+	/* it is the responsibility of the incoming packet function to free 'data' */
+	daemon_incoming_packet(client, hdr);
+}
+
+
+static int ctdb_clientpid_destructor(struct ctdb_client_pid_list *client_pid)
+{
+	if (client_pid->ctdb->client_pids != NULL) {
+		DLIST_REMOVE(client_pid->ctdb->client_pids, client_pid);
+	}
+
+	return 0;
+}
+
+
+static void ctdb_accept_client(struct event_context *ev, struct fd_event *fde, 
+			 uint16_t flags, void *private_data)
+{
+	struct sockaddr_un addr;
+	socklen_t len;
+	int fd;
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	struct ctdb_client *client;
+	struct ctdb_client_pid_list *client_pid;
+#ifdef _AIX
+	struct peercred_struct cr;
+	socklen_t crl = sizeof(struct peercred_struct);
+#else
+	struct ucred cr;
+	socklen_t crl = sizeof(struct ucred);
+#endif
+
+	memset(&addr, 0, sizeof(addr));
+	len = sizeof(addr);
+	fd = accept(ctdb->daemon.sd, (struct sockaddr *)&addr, &len);
+	if (fd == -1) {
+		return;
+	}
+
+	set_nonblocking(fd);
+	set_close_on_exec(fd);
+
+	DEBUG(DEBUG_DEBUG,(__location__ " Created SOCKET FD:%d to connected child\n", fd));
+
+	client = talloc_zero(ctdb, struct ctdb_client);
+#ifdef _AIX
+	if (getsockopt(fd, SOL_SOCKET, SO_PEERID, &cr, &crl) == 0) {
+#else
+	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &crl) == 0) {
+#endif
+		DEBUG(DEBUG_INFO,("Connected client with pid:%u\n", (unsigned)cr.pid));
+	}
+
+	client->ctdb = ctdb;
+	client->fd = fd;
+	client->client_id = ctdb_reqid_new(ctdb, client);
+	client->pid = cr.pid;
+
+	client_pid = talloc(client, struct ctdb_client_pid_list);
+	if (client_pid == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to allocate client pid structure\n"));
+		close(fd);
+		talloc_free(client);
+		return;
+	}		
+	client_pid->ctdb   = ctdb;
+	client_pid->pid    = cr.pid;
+	client_pid->client = client;
+
+	DLIST_ADD(ctdb->client_pids, client_pid);
+
+	client->queue = ctdb_queue_setup(ctdb, client, fd, CTDB_DS_ALIGNMENT, 
+					 ctdb_daemon_read_cb, client,
+					 "client-%u", client->pid);
+
+	talloc_set_destructor(client, ctdb_client_destructor);
+	talloc_set_destructor(client_pid, ctdb_clientpid_destructor);
+	CTDB_INCREMENT_STAT(ctdb, num_clients);
+}
+
+
+
+/*
+  create a unix domain socket and bind it
+  return a file descriptor open on the socket 
+*/
+static int ux_socket_bind(struct ctdb_context *ctdb)
+{
+	struct sockaddr_un addr;
+
+	ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (ctdb->daemon.sd == -1) {
+		return -1;
+	}
+
+	set_close_on_exec(ctdb->daemon.sd);
+	set_nonblocking(ctdb->daemon.sd);
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path));
+
+	if (bind(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+		DEBUG(DEBUG_CRIT,("Unable to bind on ctdb socket '%s'\n", ctdb->daemon.name));
+		goto failed;
+	}	
+
+	if (chown(ctdb->daemon.name, geteuid(), getegid()) != 0 ||
+	    chmod(ctdb->daemon.name, 0700) != 0) {
+		DEBUG(DEBUG_CRIT,("Unable to secure ctdb socket '%s', ctdb->daemon.name\n", ctdb->daemon.name));
+		goto failed;
+	} 
+
+
+	if (listen(ctdb->daemon.sd, 100) != 0) {
+		DEBUG(DEBUG_CRIT,("Unable to listen on ctdb socket '%s'\n", ctdb->daemon.name));
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	close(ctdb->daemon.sd);
+	ctdb->daemon.sd = -1;
+	return -1;	
+}
+
+static void sig_child_handler(struct event_context *ev,
+	struct signal_event *se, int signum, int count,
+	void *dont_care, 
+	void *private_data)
+{
+//	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	int status;
+	pid_t pid = -1;
+
+	while (pid != 0) {
+		pid = waitpid(-1, &status, WNOHANG);
+		if (pid == -1) {
+			DEBUG(DEBUG_ERR, (__location__ " waitpid() returned error. errno:%d\n", errno));
+			return;
+		}
+		if (pid > 0) {
+			DEBUG(DEBUG_DEBUG, ("SIGCHLD from %d\n", (int)pid));
+		}
+	}
+}
+
+static void ctdb_setup_event_callback(struct ctdb_context *ctdb, int status,
+				      void *private_data)
+{
+	if (status != 0) {
+		ctdb_fatal(ctdb, "Failed to run setup event\n");
+		return;
+	}
+	ctdb_run_notification_script(ctdb, "setup");
+
+	/* tell all other nodes we've just started up */
+	ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL,
+				 0, CTDB_CONTROL_STARTUP, 0,
+				 CTDB_CTRL_FLAG_NOREPLY,
+				 tdb_null, NULL, NULL);
+}
+
+/*
+  start the protocol going as a daemon
+*/
+int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork, bool use_syslog, const char *public_address_list)
+{
+	int res, ret = -1;
+	struct fd_event *fde;
+	const char *domain_socket_name;
+	struct signal_event *se;
+
+	/* get rid of any old sockets */
+	unlink(ctdb->daemon.name);
+
+	/* create a unix domain stream socket to listen to */
+	res = ux_socket_bind(ctdb);
+	if (res!=0) {
+		DEBUG(DEBUG_ALERT,(__location__ " Failed to open CTDB unix domain socket\n"));
+		exit(10);
+	}
+
+	if (do_fork && fork()) {
+		return 0;
+	}
+
+	tdb_reopen_all(False);
+
+	if (do_fork) {
+		setsid();
+		close(0);
+		if (open("/dev/null", O_RDONLY) != 0) {
+			DEBUG(DEBUG_ALERT,(__location__ " Failed to setup stdin on /dev/null\n"));
+			exit(11);
+		}
+	}
+	block_signal(SIGPIPE);
+
+	ctdbd_pid = getpid();
+	ctdb->ctdbd_pid = ctdbd_pid;
+
+
+	DEBUG(DEBUG_ERR, ("Starting CTDBD as pid : %u\n", ctdbd_pid));
+
+	if (ctdb->do_setsched) {
+		/* try to set us up as realtime */
+		ctdb_set_scheduler(ctdb);
+	}
+
+	/* ensure the socket is deleted on exit of the daemon */
+	domain_socket_name = talloc_strdup(talloc_autofree_context(), ctdb->daemon.name);
+	if (domain_socket_name == NULL) {
+		DEBUG(DEBUG_ALERT,(__location__ " talloc_strdup failed.\n"));
+		exit(12);
+	}
+
+	ctdb->ev = event_context_init(NULL);
+	tevent_loop_allow_nesting(ctdb->ev);
+	ret = ctdb_init_tevent_logging(ctdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ALERT,("Failed to initialize TEVENT logging\n"));
+		exit(1);
+	}
+
+	ctdb_set_child_logging(ctdb);
+
+	/* initialize statistics collection */
+	ctdb_statistics_init(ctdb);
+
+	/* force initial recovery for election */
+	ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+
+	if (strcmp(ctdb->transport, "tcp") == 0) {
+		int ctdb_tcp_init(struct ctdb_context *);
+		ret = ctdb_tcp_init(ctdb);
+	}
+#ifdef USE_INFINIBAND
+	if (strcmp(ctdb->transport, "ib") == 0) {
+		int ctdb_ibw_init(struct ctdb_context *);
+		ret = ctdb_ibw_init(ctdb);
+	}
+#endif
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to initialise transport '%s'\n", ctdb->transport));
+		return -1;
+	}
+
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_ALERT,(__location__ " Can not initialize transport. ctdb->methods is NULL\n"));
+		ctdb_fatal(ctdb, "transport is unavailable. can not initialize.");
+	}
+
+	/* initialise the transport  */
+	if (ctdb->methods->initialise(ctdb) != 0) {
+		ctdb_fatal(ctdb, "transport failed to initialise");
+	}
+	if (public_address_list) {
+		ret = ctdb_set_public_addresses(ctdb, public_address_list);
+		if (ret == -1) {
+			DEBUG(DEBUG_ALERT,("Unable to setup public address list\n"));
+			exit(1);
+		}
+	}
+
+
+	/* attach to existing databases */
+	if (ctdb_attach_databases(ctdb) != 0) {
+		ctdb_fatal(ctdb, "Failed to attach to databases\n");
+	}
+
+	ret = ctdb_event_script(ctdb, CTDB_EVENT_INIT);
+	if (ret != 0) {
+		ctdb_fatal(ctdb, "Failed to run init event\n");
+	}
+	ctdb_run_notification_script(ctdb, "init");
+
+	/* start frozen, then let the first election sort things out */
+	if (ctdb_blocking_freeze(ctdb)) {
+		ctdb_fatal(ctdb, "Failed to get initial freeze\n");
+	}
+
+	/* now start accepting clients, only can do this once frozen */
+	fde = event_add_fd(ctdb->ev, ctdb, ctdb->daemon.sd, 
+			   EVENT_FD_READ,
+			   ctdb_accept_client, ctdb);
+	tevent_fd_set_auto_close(fde);
+
+	/* release any IPs we hold from previous runs of the daemon */
+	if (ctdb->tunable.disable_ip_failover == 0) {
+		ctdb_release_all_ips(ctdb);
+	}
+
+	/* start the transport going */
+	ctdb_start_transport(ctdb);
+
+	/* set up a handler to pick up sigchld */
+	se = event_add_signal(ctdb->ev, ctdb,
+				     SIGCHLD, 0,
+				     sig_child_handler,
+				     ctdb);
+	if (se == NULL) {
+		DEBUG(DEBUG_CRIT,("Failed to set up signal handler for SIGCHLD\n"));
+		exit(1);
+	}
+
+	ret = ctdb_event_script_callback(ctdb,
+					 ctdb,
+					 ctdb_setup_event_callback,
+					 ctdb,
+					 false,
+					 CTDB_EVENT_SETUP,
+					 "");
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT,("Failed to set up 'setup' event\n"));
+		exit(1);
+	}
+
+	if (use_syslog) {
+		if (start_syslog_daemon(ctdb)) {
+			DEBUG(DEBUG_CRIT, ("Failed to start syslog daemon\n"));
+			exit(10);
+		}
+	}
+
+	ctdb_lockdown_memory(ctdb);
+	  
+	/* go into a wait loop to allow other nodes to complete */
+	event_loop_wait(ctdb->ev);
+
+	DEBUG(DEBUG_CRIT,("event_loop_wait() returned. this should not happen\n"));
+	exit(1);
+}
+
+/*
+  allocate a packet for use in daemon<->daemon communication
+ */
+struct ctdb_req_header *_ctdb_transport_allocate(struct ctdb_context *ctdb,
+						 TALLOC_CTX *mem_ctx, 
+						 enum ctdb_operation operation, 
+						 size_t length, size_t slength,
+						 const char *type)
+{
+	int size;
+	struct ctdb_req_header *hdr;
+
+	length = MAX(length, slength);
+	size = (length+(CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1);
+
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " Unable to allocate transport packet for operation %u of length %u. Transport is DOWN.\n",
+			 operation, (unsigned)length));
+		return NULL;
+	}
+
+	hdr = (struct ctdb_req_header *)ctdb->methods->allocate_pkt(mem_ctx, size);
+	if (hdr == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to allocate transport packet for operation %u of length %u\n",
+			 operation, (unsigned)length));
+		return NULL;
+	}
+	talloc_set_name_const(hdr, type);
+	memset(hdr, 0, slength);
+	hdr->length       = length;
+	hdr->operation    = operation;
+	hdr->ctdb_magic   = CTDB_MAGIC;
+	hdr->ctdb_version = CTDB_VERSION;
+	hdr->generation   = ctdb->vnn_map->generation;
+	hdr->srcnode      = ctdb->pnn;
+
+	return hdr;	
+}
+
+struct daemon_control_state {
+	struct daemon_control_state *next, *prev;
+	struct ctdb_client *client;
+	struct ctdb_req_control *c;
+	uint32_t reqid;
+	struct ctdb_node *node;
+};
+
+/*
+  callback when a control reply comes in
+ */
+static void daemon_control_callback(struct ctdb_context *ctdb,
+				    int32_t status, TDB_DATA data, 
+				    const char *errormsg,
+				    void *private_data)
+{
+	struct daemon_control_state *state = talloc_get_type(private_data, 
+							     struct daemon_control_state);
+	struct ctdb_client *client = state->client;
+	struct ctdb_reply_control *r;
+	size_t len;
+	int ret;
+
+	/* construct a message to send to the client containing the data */
+	len = offsetof(struct ctdb_reply_control, data) + data.dsize;
+	if (errormsg) {
+		len += strlen(errormsg);
+	}
+	r = ctdbd_allocate_pkt(ctdb, state, CTDB_REPLY_CONTROL, len, 
+			       struct ctdb_reply_control);
+	CTDB_NO_MEMORY_VOID(ctdb, r);
+
+	r->hdr.reqid     = state->reqid;
+	r->status        = status;
+	r->datalen       = data.dsize;
+	r->errorlen = 0;
+	memcpy(&r->data[0], data.dptr, data.dsize);
+	if (errormsg) {
+		r->errorlen = strlen(errormsg);
+		memcpy(&r->data[r->datalen], errormsg, r->errorlen);
+	}
+
+	ret = daemon_queue_send(client, &r->hdr);
+	if (ret != -1) {
+		talloc_free(state);
+	}
+}
+
+/*
+  fail all pending controls to a disconnected node
+ */
+void ctdb_daemon_cancel_controls(struct ctdb_context *ctdb, struct ctdb_node *node)
+{
+	struct daemon_control_state *state;
+	while ((state = node->pending_controls)) {
+		DLIST_REMOVE(node->pending_controls, state);
+		daemon_control_callback(ctdb, (uint32_t)-1, tdb_null, 
+					"node is disconnected", state);
+	}
+}
+
+/*
+  destroy a daemon_control_state
+ */
+static int daemon_control_destructor(struct daemon_control_state *state)
+{
+	if (state->node) {
+		DLIST_REMOVE(state->node->pending_controls, state);
+	}
+	return 0;
+}
+
+/*
+  this is called when the ctdb daemon received a ctdb request control
+  from a local client over the unix domain socket
+ */
+static void daemon_request_control_from_client(struct ctdb_client *client, 
+					       struct ctdb_req_control *c)
+{
+	TDB_DATA data;
+	int res;
+	struct daemon_control_state *state;
+	TALLOC_CTX *tmp_ctx = talloc_new(client);
+
+	if (c->hdr.destnode == CTDB_CURRENT_NODE) {
+		c->hdr.destnode = client->ctdb->pnn;
+	}
+
+	state = talloc(client, struct daemon_control_state);
+	CTDB_NO_MEMORY_VOID(client->ctdb, state);
+
+	state->client = client;
+	state->c = talloc_steal(state, c);
+	state->reqid = c->hdr.reqid;
+	if (ctdb_validate_pnn(client->ctdb, c->hdr.destnode)) {
+		state->node = client->ctdb->nodes[c->hdr.destnode];
+		DLIST_ADD(state->node->pending_controls, state);
+	} else {
+		state->node = NULL;
+	}
+
+	talloc_set_destructor(state, daemon_control_destructor);
+
+	if (c->flags & CTDB_CTRL_FLAG_NOREPLY) {
+		talloc_steal(tmp_ctx, state);
+	}
+	
+	data.dptr = &c->data[0];
+	data.dsize = c->datalen;
+	res = ctdb_daemon_send_control(client->ctdb, c->hdr.destnode,
+				       c->srvid, c->opcode, client->client_id,
+				       c->flags,
+				       data, daemon_control_callback,
+				       state);
+	if (res != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to send control to remote node %u\n",
+			 c->hdr.destnode));
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  register a call function
+*/
+int ctdb_daemon_set_call(struct ctdb_context *ctdb, uint32_t db_id,
+			 ctdb_fn_t fn, int id)
+{
+	struct ctdb_registered_call *call;
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (ctdb_db == NULL) {
+		return -1;
+	}
+
+	call = talloc(ctdb_db, struct ctdb_registered_call);
+	call->fn = fn;
+	call->id = id;
+
+	DLIST_ADD(ctdb_db->calls, call);	
+	return 0;
+}
+
+
+
+/*
+  this local messaging handler is ugly, but is needed to prevent
+  recursion in ctdb_send_message() when the destination node is the
+  same as the source node
+ */
+struct ctdb_local_message {
+	struct ctdb_context *ctdb;
+	uint64_t srvid;
+	TDB_DATA data;
+};
+
+static void ctdb_local_message_trigger(struct event_context *ev, struct timed_event *te, 
+				       struct timeval t, void *private_data)
+{
+	struct ctdb_local_message *m = talloc_get_type(private_data, 
+						       struct ctdb_local_message);
+	int res;
+
+	res = ctdb_dispatch_message(m->ctdb, m->srvid, m->data);
+	if (res != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to dispatch message for srvid=%llu\n", 
+			  (unsigned long long)m->srvid));
+	}
+	talloc_free(m);
+}
+
+static int ctdb_local_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data)
+{
+	struct ctdb_local_message *m;
+	m = talloc(ctdb, struct ctdb_local_message);
+	CTDB_NO_MEMORY(ctdb, m);
+
+	m->ctdb = ctdb;
+	m->srvid = srvid;
+	m->data  = data;
+	m->data.dptr = talloc_memdup(m, m->data.dptr, m->data.dsize);
+	if (m->data.dptr == NULL) {
+		talloc_free(m);
+		return -1;
+	}
+
+	/* this needs to be done as an event to prevent recursion */
+	event_add_timed(ctdb->ev, m, timeval_zero(), ctdb_local_message_trigger, m);
+	return 0;
+}
+
+/*
+  send a ctdb message
+*/
+int ctdb_daemon_send_message(struct ctdb_context *ctdb, uint32_t pnn,
+			     uint64_t srvid, TDB_DATA data)
+{
+	struct ctdb_req_message *r;
+	int len;
+
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " Failed to send message. Transport is DOWN\n"));
+		return -1;
+	}
+
+	/* see if this is a message to ourselves */
+	if (pnn == ctdb->pnn) {
+		return ctdb_local_message(ctdb, srvid, data);
+	}
+
+	len = offsetof(struct ctdb_req_message, data) + data.dsize;
+	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_MESSAGE, len,
+				    struct ctdb_req_message);
+	CTDB_NO_MEMORY(ctdb, r);
+
+	r->hdr.destnode  = pnn;
+	r->srvid         = srvid;
+	r->datalen       = data.dsize;
+	memcpy(&r->data[0], data.dptr, data.dsize);
+
+	ctdb_queue_packet(ctdb, &r->hdr);
+
+	talloc_free(r);
+	return 0;
+}
+
+
+
+struct ctdb_client_notify_list {
+	struct ctdb_client_notify_list *next, *prev;
+	struct ctdb_context *ctdb;
+	uint64_t srvid;
+	TDB_DATA data;
+};
+
+
+static int ctdb_client_notify_destructor(struct ctdb_client_notify_list *nl)
+{
+	int ret;
+
+	DEBUG(DEBUG_ERR,("Sending client notify message for srvid:%llu\n", (unsigned long long)nl->srvid));
+
+	ret = ctdb_daemon_send_message(nl->ctdb, CTDB_BROADCAST_CONNECTED, (unsigned long long)nl->srvid, nl->data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send client notify message\n"));
+	}
+
+	return 0;
+}
+
+int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata)
+{
+	struct ctdb_client_notify_register *notify = (struct ctdb_client_notify_register *)indata.dptr;
+        struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); 
+	struct ctdb_client_notify_list *nl;
+
+	DEBUG(DEBUG_INFO,("Register srvid %llu for client %d\n", (unsigned long long)notify->srvid, client_id));
+
+	if (indata.dsize < offsetof(struct ctdb_client_notify_register, notify_data)) {
+		DEBUG(DEBUG_ERR,(__location__ " Too little data in control : %d\n", (int)indata.dsize));
+		return -1;
+	}
+
+	if (indata.dsize != (notify->len + offsetof(struct ctdb_client_notify_register, notify_data))) {
+		DEBUG(DEBUG_ERR,(__location__ " Wrong amount of data in control. Got %d, expected %d\n", (int)indata.dsize, (int)(notify->len + offsetof(struct ctdb_client_notify_register, notify_data))));
+		return -1;
+	}
+
+
+        if (client == NULL) {
+                DEBUG(DEBUG_ERR,(__location__ " Could not find client parent structure. You can not send this control to a remote node\n"));
+                return -1;
+        }
+
+	for(nl=client->notify; nl; nl=nl->next) {
+		if (nl->srvid == notify->srvid) {
+			break;
+		}
+	}
+	if (nl != NULL) {
+                DEBUG(DEBUG_ERR,(__location__ " Notification for srvid:%llu already exists for this client\n", (unsigned long long)notify->srvid));
+                return -1;
+        }
+
+	nl = talloc(client, struct ctdb_client_notify_list);
+	CTDB_NO_MEMORY(ctdb, nl);
+	nl->ctdb       = ctdb;
+	nl->srvid      = notify->srvid;
+	nl->data.dsize = notify->len;
+	nl->data.dptr  = talloc_size(nl, nl->data.dsize);
+	CTDB_NO_MEMORY(ctdb, nl->data.dptr);
+	memcpy(nl->data.dptr, notify->notify_data, nl->data.dsize);
+	
+	DLIST_ADD(client->notify, nl);
+	talloc_set_destructor(nl, ctdb_client_notify_destructor);
+
+	return 0;
+}
+
+int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata)
+{
+	struct ctdb_client_notify_deregister *notify = (struct ctdb_client_notify_deregister *)indata.dptr;
+        struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); 
+	struct ctdb_client_notify_list *nl;
+
+	DEBUG(DEBUG_INFO,("Deregister srvid %llu for client %d\n", (unsigned long long)notify->srvid, client_id));
+
+        if (client == NULL) {
+                DEBUG(DEBUG_ERR,(__location__ " Could not find client parent structure. You can not send this control to a remote node\n"));
+                return -1;
+        }
+
+	for(nl=client->notify; nl; nl=nl->next) {
+		if (nl->srvid == notify->srvid) {
+			break;
+		}
+	}
+	if (nl == NULL) {
+                DEBUG(DEBUG_ERR,(__location__ " No notification for srvid:%llu found for this client\n", (unsigned long long)notify->srvid));
+                return -1;
+        }
+
+	DLIST_REMOVE(client->notify, nl);
+	talloc_set_destructor(nl, NULL);
+	talloc_free(nl);
+
+	return 0;
+}
+
+struct ctdb_client *ctdb_find_client_by_pid(struct ctdb_context *ctdb, pid_t pid)
+{
+	struct ctdb_client_pid_list *client_pid;
+
+	for (client_pid = ctdb->client_pids; client_pid; client_pid=client_pid->next) {
+		if (client_pid->pid == pid) {
+			return client_pid->client;
+		}
+	}
+	return NULL;
+}
+
+
+/* This control is used by samba when probing if a process (of a samba daemon)
+   exists on the node.
+   Samba does this when it needs/wants to check if a subrecord in one of the
+   databases is still valied, or if it is stale and can be removed.
+   If the node is in unhealthy or stopped state we just kill of the samba
+   process holding htis sub-record and return to the calling samba that
+   the process does not exist.
+   This allows us to forcefully recall subrecords registered by samba processes
+   on banned and stopped nodes.
+*/
+int32_t ctdb_control_process_exists(struct ctdb_context *ctdb, pid_t pid)
+{
+        struct ctdb_client *client;
+
+	if (ctdb->nodes[ctdb->pnn]->flags & (NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
+		client = ctdb_find_client_by_pid(ctdb, pid);
+		if (client != NULL) {
+			DEBUG(DEBUG_NOTICE,(__location__ " Killing client with pid:%d on banned/stopped node\n", (int)pid));
+			talloc_free(client);
+		}
+		return -1;
+	}
+
+	return kill(pid, 0);
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_freeze.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_freeze.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_freeze.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,620 @@
+/* 
+   ctdb freeze handling
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+#include "lib/util/dlinklist.h"
+#include "db_wrap.h"
+#include "../common/rb_tree.h"
+
+static bool later_db(const char *name)
+{
+	return (strstr(name, "notify") || strstr(name, "serverid"));
+}
+
+/*
+  lock all databases
+ */
+static int ctdb_lock_all_databases(struct ctdb_context *ctdb, uint32_t priority)
+{
+	struct ctdb_db_context *ctdb_db;
+	/* REMOVE later */
+	/* This double loop is for backward compatibility and deadlock
+	   avoidance for old samba versions that not yet support
+	   the set prio call.
+	   This code shall be removed later
+	*/
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		if (ctdb_db->priority != priority) {
+			continue;
+		}
+		if (later_db(ctdb_db->db_name)) {
+			continue;
+		}
+		DEBUG(DEBUG_INFO,("locking database 0x%08x priority:%u %s\n", ctdb_db->db_id, ctdb_db->priority, ctdb_db->db_name));
+		if (tdb_lockall(ctdb_db->ltdb->tdb) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to lock database %s\n", ctdb_db->db_name));
+			return -1;
+		}
+	}
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		if (ctdb_db->priority != priority) {
+			continue;
+		}
+		if (!later_db(ctdb_db->db_name)) {
+			continue;
+		}
+		DEBUG(DEBUG_INFO,("locking database 0x%08x priority:%u %s\n", ctdb_db->db_id, ctdb_db->priority, ctdb_db->db_name));
+		if (tdb_lockall(ctdb_db->ltdb->tdb) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to lock database %s\n", ctdb_db->db_name));
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+  a list of control requests waiting for a freeze lock child to get
+  the database locks
+ */
+struct ctdb_freeze_waiter {
+	struct ctdb_freeze_waiter *next, *prev;
+	struct ctdb_context *ctdb;
+	struct ctdb_req_control *c;
+	uint32_t priority;
+	int32_t status;
+};
+
+/* a handle to a freeze lock child process */
+struct ctdb_freeze_handle {
+	struct ctdb_context *ctdb;
+	uint32_t priority;
+	pid_t child;
+	int fd;
+	struct ctdb_freeze_waiter *waiters;
+};
+
+/*
+  destroy a freeze handle
+ */	
+static int ctdb_freeze_handle_destructor(struct ctdb_freeze_handle *h)
+{
+	struct ctdb_context *ctdb = h->ctdb;
+	struct ctdb_db_context *ctdb_db;
+
+	DEBUG(DEBUG_ERR,("Release freeze handler for prio %u\n", h->priority));
+
+	/* cancel any pending transactions */
+	if (ctdb->freeze_transaction_started) {
+		for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+			if (ctdb_db->priority != h->priority) {
+				continue;
+			}
+			tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+			if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
+				DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",
+					 ctdb_db->db_name));
+			}
+			tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+		}
+		ctdb->freeze_transaction_started = false;
+	}
+
+	ctdb->freeze_mode[h->priority]    = CTDB_FREEZE_NONE;
+	ctdb->freeze_handles[h->priority] = NULL;
+
+	kill(h->child, SIGKILL);
+	return 0;
+}
+
+/*
+  called when the child writes its status to us
+ */
+static void ctdb_freeze_lock_handler(struct event_context *ev, struct fd_event *fde, 
+				       uint16_t flags, void *private_data)
+{
+	struct ctdb_freeze_handle *h = talloc_get_type(private_data, struct ctdb_freeze_handle);
+	int32_t status;
+	struct ctdb_freeze_waiter *w;
+
+	if (h->ctdb->freeze_mode[h->priority] == CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_INFO,("freeze child died - unfreezing\n"));
+		talloc_free(h);
+		return;
+	}
+
+	if (read(h->fd, &status, sizeof(status)) != sizeof(status)) {
+		DEBUG(DEBUG_ERR,("read error from freeze lock child\n"));
+		status = -1;
+	}
+
+	if (status == -1) {
+		DEBUG(DEBUG_ERR,("Failed to get locks in ctdb_freeze_child\n"));
+		/* we didn't get the locks - destroy the handle */
+		talloc_free(h);
+		return;
+	}
+
+	h->ctdb->freeze_mode[h->priority] = CTDB_FREEZE_FROZEN;
+
+	/* notify the waiters */
+	if (h != h->ctdb->freeze_handles[h->priority]) {
+		DEBUG(DEBUG_ERR,("lockwait finished but h is not linked\n"));
+	}
+	while ((w = h->waiters)) {
+		w->status = status;
+		DLIST_REMOVE(h->waiters, w);
+		talloc_free(w);
+	}
+}
+
+/*
+  create a child which gets locks on all the open databases, then calls the callback telling the parent
+  that it is done
+ */
+static struct ctdb_freeze_handle *ctdb_freeze_lock(struct ctdb_context *ctdb, uint32_t priority)
+{
+	struct ctdb_freeze_handle *h;
+	int fd[2];
+	struct fd_event *fde;
+
+	h = talloc_zero(ctdb, struct ctdb_freeze_handle);
+	CTDB_NO_MEMORY_NULL(ctdb, h);
+
+	h->ctdb     = ctdb;
+	h->priority = priority;
+
+	if (pipe(fd) == -1) {
+		DEBUG(DEBUG_ERR,("Failed to create pipe for ctdb_freeze_lock\n"));
+		talloc_free(h);
+		return NULL;
+	}
+	
+	h->child = fork();
+	if (h->child == -1) {
+		DEBUG(DEBUG_ERR,("Failed to fork child for ctdb_freeze_lock\n"));
+		talloc_free(h);
+		return NULL;
+	}
+
+	if (h->child == 0) {
+		int ret;
+
+		/* in the child */
+		close(fd[0]);
+
+		debug_extra = talloc_asprintf(NULL, "freeze_lock-%u:", priority);
+		ret = ctdb_lock_all_databases(ctdb, priority);
+		if (ret != 0) {
+			_exit(0);
+		}
+
+		ret = write(fd[1], &ret, sizeof(ret));
+		if (ret != sizeof(ret)) {
+			DEBUG(DEBUG_ERR, (__location__ " Failed to write to socket from freeze child. ret:%d errno:%u\n", ret, errno));
+			_exit(1);
+		}
+
+		while (1) {
+			sleep(1);
+			if (kill(ctdb->ctdbd_pid, 0) != 0) {
+				DEBUG(DEBUG_ERR,("Parent died. Exiting lock wait child\n"));
+
+				_exit(0);
+			}
+		}
+	}
+
+	talloc_set_destructor(h, ctdb_freeze_handle_destructor);
+
+	close(fd[1]);
+	set_close_on_exec(fd[0]);
+
+	h->fd = fd[0];
+
+
+	fde = event_add_fd(ctdb->ev, h, h->fd, EVENT_FD_READ,
+			   ctdb_freeze_lock_handler, h);
+	if (fde == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to setup fd event for ctdb_freeze_lock\n"));
+		close(fd[0]);
+		talloc_free(h);
+		return NULL;
+	}
+	tevent_fd_set_auto_close(fde);
+
+	return h;
+}
+
+/*
+  destroy a waiter for a freeze mode change
+ */
+static int ctdb_freeze_waiter_destructor(struct ctdb_freeze_waiter *w)
+{
+	ctdb_request_control_reply(w->ctdb, w->c, NULL, w->status, NULL);
+	return 0;
+}
+
+/*
+  start the freeze process for a certain priority
+ */
+int ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority)
+{
+	if (priority == 0) {
+		DEBUG(DEBUG_ERR,("Freeze priority 0 requested, remapping to priority 1\n"));
+		priority = 1;
+	}
+
+	if ((priority < 1) || (priority > NUM_DB_PRIORITIES)) {
+		DEBUG(DEBUG_ERR,(__location__ " Invalid db priority : %u\n", priority));
+		return -1;
+	}
+
+	if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) {
+		/* we're already frozen */
+		return 0;
+	}
+
+	/* Stop any vacuuming going on: we don't want to wait. */
+	ctdb_stop_vacuuming(ctdb);
+
+	/* if there isn't a freeze lock child then create one */
+	if (ctdb->freeze_handles[priority] == NULL) {
+		ctdb->freeze_handles[priority] = ctdb_freeze_lock(ctdb, priority);
+		CTDB_NO_MEMORY(ctdb, ctdb->freeze_handles[priority]);
+		ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING;
+	}
+
+	return 0;
+}
+
+/*
+  freeze the databases
+ */
+int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply)
+{
+	struct ctdb_freeze_waiter *w;
+	uint32_t priority;
+
+	priority = (uint32_t)c->srvid;
+
+	DEBUG(DEBUG_ERR, ("Freeze priority %u\n", priority));
+
+	if (priority == 0) {
+		DEBUG(DEBUG_ERR,("Freeze priority 0 requested, remapping to priority 1\n"));
+		priority = 1;
+	}
+
+	if ((priority < 1) || (priority > NUM_DB_PRIORITIES)) {
+		DEBUG(DEBUG_ERR,(__location__ " Invalid db priority : %u\n", priority));
+		return -1;
+	}
+
+	if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) {
+		/* we're already frozen */
+		return 0;
+	}
+
+	if (ctdb_start_freeze(ctdb, priority) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to start freezing databases with priority %u\n", priority));
+		return -1;
+	}
+
+	/* add ourselves to list of waiters */
+	if (ctdb->freeze_handles[priority] == NULL) {
+		DEBUG(DEBUG_ERR,("No freeze lock handle when adding a waiter\n"));
+		return -1;
+	}
+
+	w = talloc(ctdb->freeze_handles[priority], struct ctdb_freeze_waiter);
+	CTDB_NO_MEMORY(ctdb, w);
+	w->ctdb     = ctdb;
+	w->c        = talloc_steal(w, c);
+	w->priority = priority;
+	w->status   = -1;
+	talloc_set_destructor(w, ctdb_freeze_waiter_destructor);
+	DLIST_ADD(ctdb->freeze_handles[priority]->waiters, w);
+
+	/* we won't reply till later */
+	*async_reply = True;
+	return 0;
+}
+
+
+/*
+  block until we are frozen, used during daemon startup
+ */
+bool ctdb_blocking_freeze(struct ctdb_context *ctdb)
+{
+	int i;
+
+	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb_start_freeze(ctdb, i)) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to freeze databases of prio %u\n", i));
+			continue;
+		}
+
+		/* block until frozen */
+		while (ctdb->freeze_mode[i] == CTDB_FREEZE_PENDING) {
+			event_loop_once(ctdb->ev);
+		}
+	}
+
+	return 0;
+}
+
+
+static void thaw_priority(struct ctdb_context *ctdb, uint32_t priority)
+{
+	DEBUG(DEBUG_ERR,("Thawing priority %u\n", priority));
+
+	/* cancel any pending transactions */
+	if (ctdb->freeze_transaction_started) {
+		struct ctdb_db_context *ctdb_db;
+
+		for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+			tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+			if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
+				DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",
+					 ctdb_db->db_name));
+			}
+			tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+		}
+	}
+	ctdb->freeze_transaction_started = false;
+
+#if 0
+	/* this hack can be used to get a copy of the databases at the end of a recovery */
+	system("mkdir -p /var/ctdb.saved; /usr/bin/rsync --delete -a /var/ctdb/ /var/ctdb.saved/$$ 2>&1 > /dev/null");
+#endif
+
+#if 0
+	/* and this one for local testing */
+	system("mkdir -p test.db.saved; /usr/bin/rsync --delete -a test.db/ test.db.saved/$$ 2>&1 > /dev/null");
+#endif
+
+	if (ctdb->freeze_handles[priority] != NULL) {
+		talloc_free(ctdb->freeze_handles[priority]);
+		ctdb->freeze_handles[priority] = NULL;
+	}
+}
+
+/*
+  thaw the databases
+ */
+int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority)
+{
+
+	if (priority > NUM_DB_PRIORITIES) {
+		DEBUG(DEBUG_ERR,(__location__ " Invalid db priority : %u\n", priority));
+		return -1;
+	}
+
+	if (priority == 0) {
+		int i;
+		for (i=1;i<=NUM_DB_PRIORITIES; i++) {
+			thaw_priority(ctdb, i);
+		}
+	} else {
+		thaw_priority(ctdb, priority);
+	}
+
+	ctdb_call_resend_all(ctdb);
+	return 0;
+}
+
+
+/*
+  start a transaction on all databases - used for recovery
+ */
+int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id)
+{
+	struct ctdb_db_context *ctdb_db;
+	int i;
+
+	for (i=1;i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n"));
+			return -1;
+		}
+	}
+
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		int ret;
+
+		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+
+		if (ctdb->freeze_transaction_started) {
+			if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
+				DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",
+					 ctdb_db->db_name));
+				/* not a fatal error */
+			}
+		}
+
+		ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
+
+		tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction for db '%s'\n",
+				 ctdb_db->db_name));
+			return -1;
+		}
+	}
+
+	ctdb->freeze_transaction_started = true;
+	ctdb->freeze_transaction_id = id;
+
+	return 0;
+}
+
+/*
+  cancel a transaction for all databases - used for recovery
+ */
+int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb)
+{
+	struct ctdb_db_context *ctdb_db;
+
+	DEBUG(DEBUG_ERR,(__location__ " recovery transaction cancelled called\n"));
+
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+
+		if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",  ctdb_db->db_name));
+			/* not a fatal error */
+		}
+
+		tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	}
+
+	ctdb->freeze_transaction_started = false;
+
+	return 0;
+}
+
+/*
+  commit transactions on all databases
+ */
+int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id)
+{
+	struct ctdb_db_context *ctdb_db;
+	int i;
+	int healthy_nodes = 0;
+
+	for (i=1;i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n"));
+			return -1;
+		}
+	}
+
+	if (!ctdb->freeze_transaction_started) {
+		DEBUG(DEBUG_ERR,(__location__ " transaction not started\n"));
+		return -1;
+	}
+
+	if (id != ctdb->freeze_transaction_id) {
+		DEBUG(DEBUG_ERR,(__location__ " incorrect transaction id 0x%x in commit\n", id));
+		return -1;
+	}
+
+	DEBUG(DEBUG_DEBUG,(__location__ " num_nodes[%d]\n", ctdb->num_nodes));
+	for (i=0; i < ctdb->num_nodes; i++) {
+		DEBUG(DEBUG_DEBUG,(__location__ " node[%d].flags[0x%X]\n",
+				   i, ctdb->nodes[i]->flags));
+		if (ctdb->nodes[i]->flags == 0) {
+			healthy_nodes++;
+		}
+	}
+	DEBUG(DEBUG_INFO,(__location__ " healthy_nodes[%d]\n", healthy_nodes));
+
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		int ret;
+
+		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+		ret = tdb_transaction_commit(ctdb_db->ltdb->tdb);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to commit transaction for db '%s'. Cancel all transactions and resetting transaction_started to false.\n",
+				 ctdb_db->db_name));
+			goto fail;
+		}
+		tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+
+		ret = ctdb_update_persistent_health(ctdb, ctdb_db, NULL, healthy_nodes);
+		if (ret != 0) {
+			DEBUG(DEBUG_CRIT,(__location__ " Failed to update persistent health for db '%s'. "
+					 "Cancel all remaining transactions and resetting transaction_started to false.\n",
+					 ctdb_db->db_name));
+			goto fail;
+		}
+	}
+
+	ctdb->freeze_transaction_started = false;
+	ctdb->freeze_transaction_id = 0;
+
+	return 0;
+
+fail:
+	/* cancel any pending transactions */
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+		if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n",
+				 ctdb_db->db_name));
+		}
+		tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK);
+	}
+	ctdb->freeze_transaction_started = false;
+
+	return -1;
+}
+
+/*
+  wipe a database - only possible when in a frozen transaction
+ */
+int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_control_wipe_database w = *(struct ctdb_control_wipe_database *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = find_ctdb_db(ctdb, w.db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%x\n", w.db_id));
+		return -1;
+	}
+
+	if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n"));
+		return -1;
+	}
+
+	if (!ctdb->freeze_transaction_started) {
+		DEBUG(DEBUG_ERR,(__location__ " transaction not started\n"));
+		return -1;
+	}
+
+	if (w.transaction_id != ctdb->freeze_transaction_id) {
+		DEBUG(DEBUG_ERR,(__location__ " incorrect transaction id 0x%x in commit\n", w.transaction_id));
+		return -1;
+	}
+
+	if (tdb_wipe_all(ctdb_db->ltdb->tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database for db '%s'\n",
+			 ctdb_db->db_name));
+		return -1;
+	}
+
+	if (!ctdb_db->persistent) {
+		talloc_free(ctdb_db->delete_queue);
+		ctdb_db->delete_queue = trbt_create(ctdb_db, 0);
+		if (ctdb_db->delete_queue == NULL) {
+			DEBUG(DEBUG_ERR, (__location__ " Failed to re-create "
+					  "the vacuum tree.\n"));
+			return -1;
+		}
+	}
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_keepalive.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_keepalive.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_keepalive.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,108 @@
+/* 
+   monitoring links to all other nodes to detect dead nodes
+
+
+   Copyright (C) Ronnie Sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+
+
+/*
+  see if any nodes are dead
+ */
+static void ctdb_check_for_dead_nodes(struct event_context *ev, struct timed_event *te, 
+				      struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	int i;
+
+	/* send a keepalive to all other nodes, unless */
+	for (i=0;i<ctdb->num_nodes;i++) {
+		struct ctdb_node *node = ctdb->nodes[i];
+
+		if (node->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+
+		if (node->pnn == ctdb->pnn) {
+			continue;
+		}
+		
+		if (node->flags & NODE_FLAGS_DISCONNECTED) {
+			/* it might have come alive again */
+			if (node->rx_cnt != 0) {
+				ctdb_node_connected(node);
+			}
+			continue;
+		}
+
+
+		if (node->rx_cnt == 0) {
+			node->dead_count++;
+		} else {
+			node->dead_count = 0;
+		}
+
+		node->rx_cnt = 0;
+
+		if (node->dead_count >= ctdb->tunable.keepalive_limit) {
+			DEBUG(DEBUG_NOTICE,("dead count reached for node %u\n", node->pnn));
+			ctdb_node_dead(node);
+			ctdb_send_keepalive(ctdb, node->pnn);
+			/* maybe tell the transport layer to kill the
+			   sockets as well?
+			*/
+			continue;
+		}
+		
+		DEBUG(DEBUG_DEBUG,("sending keepalive to %u\n", node->pnn));
+		ctdb_send_keepalive(ctdb, node->pnn);
+
+		node->tx_cnt = 0;
+	}
+	
+	event_add_timed(ctdb->ev, ctdb->keepalive_ctx,
+			timeval_current_ofs(ctdb->tunable.keepalive_interval, 0), 
+			ctdb_check_for_dead_nodes, ctdb);
+}
+
+
+void ctdb_start_keepalive(struct ctdb_context *ctdb)
+{
+	struct timed_event *te;
+
+	ctdb->keepalive_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY_FATAL(ctdb, ctdb->keepalive_ctx);
+
+	te = event_add_timed(ctdb->ev, ctdb->keepalive_ctx,
+			     timeval_current_ofs(ctdb->tunable.keepalive_interval, 0), 
+			     ctdb_check_for_dead_nodes, ctdb);
+	CTDB_NO_MEMORY_FATAL(ctdb, te);
+
+	DEBUG(DEBUG_NOTICE,("Keepalive monitoring has been started\n"));
+}
+
+void ctdb_stop_keepalive(struct ctdb_context *ctdb)
+{
+	talloc_free(ctdb->keepalive_ctx);
+	ctdb->keepalive_ctx = NULL;
+}
+

Added: branches/ctdb/squeeze-backports/server/ctdb_lockwait.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_lockwait.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_lockwait.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,235 @@
+/* 
+   wait for a tdb chain lock
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "db_wrap.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/util/dlinklist.h"
+#include "../include/ctdb_private.h"
+
+
+struct lockwait_handle {
+	struct lockwait_handle *next, *prev;
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	struct fd_event *fde;
+	int fd[2];
+	pid_t child;
+	void *private_data;
+	void (*callback)(void *);
+	TDB_DATA key;
+	struct timeval start_time;
+};
+
+/* If we managed to obtain a lock, find any overflow records which wanted the
+ * same one and do all the callbacks at once. */
+static void do_overflow(struct ctdb_db_context *ctdb_db,
+			TDB_DATA key)
+{
+	struct lockwait_handle *i, *next;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb_db);
+
+	for (i = ctdb_db->lockwait_overflow; i; i = next) {
+		/* Careful: destructor removes it from list! */
+		next = i->next;
+		if (key.dsize == i->key.dsize
+		    && memcmp(key.dptr, i->key.dptr, key.dsize) == 0) {
+			/* Callback might free them, so reparent. */
+			talloc_steal(tmp_ctx, i);
+			i->callback(i->private_data);
+		}
+	}
+
+	/* This will free them if callback didn't. */
+	talloc_free(tmp_ctx);
+
+	/* Remove one from the overflow queue if there is one. */
+	if (ctdb_db->lockwait_overflow) {
+		i = ctdb_db->lockwait_overflow;
+		ctdb_lockwait(ctdb_db, i->key, i->callback, i->private_data);
+		talloc_free(i);
+	}
+}
+
+static int lockwait_destructor(struct lockwait_handle *h)
+{
+	CTDB_DECREMENT_STAT(h->ctdb, pending_lockwait_calls);
+	kill(h->child, SIGKILL);
+	h->ctdb_db->pending_requests--;
+	DLIST_REMOVE(h->ctdb_db->lockwait_active, h);
+	return 0;
+}
+
+static void lockwait_handler(struct event_context *ev, struct fd_event *fde, 
+			     uint16_t flags, void *private_data)
+{
+	struct lockwait_handle *h = talloc_get_type(private_data, 
+						     struct lockwait_handle);
+	void (*callback)(void *) = h->callback;
+	void *p = h->private_data;
+	TDB_DATA key = h->key;
+	struct tdb_context *tdb = h->ctdb_db->ltdb->tdb;
+	TALLOC_CTX *tmp_ctx = talloc_new(ev);
+
+	key.dptr = talloc_memdup(tmp_ctx, key.dptr, key.dsize);
+	h->ctdb_db->pending_requests--;
+
+	CTDB_UPDATE_LATENCY(h->ctdb, h->ctdb_db, "lockwait", lockwait_latency, h->start_time);
+
+	/* the handle needs to go away when the context is gone - when
+	   the handle goes away this implicitly closes the pipe, which
+	   kills the child holding the lock */
+	talloc_steal(tmp_ctx, h);
+
+	if (h->ctdb->flags & CTDB_FLAG_TORTURE) {
+		if (tdb_chainlock_nonblock(tdb, key) == 0) {
+			ctdb_fatal(h->ctdb, "got chain lock while lockwait child active");
+		}
+	}
+
+	tdb_chainlock_mark(tdb, key);
+	callback(p);
+	if (h->ctdb_db->lockwait_overflow) {
+		do_overflow(h->ctdb_db, key);
+	}
+	tdb_chainlock_unmark(tdb, key);
+
+	talloc_free(tmp_ctx);
+}
+
+
+static int overflow_lockwait_destructor(struct lockwait_handle *h)
+{
+	CTDB_DECREMENT_STAT(h->ctdb, pending_lockwait_calls);
+	DLIST_REMOVE(h->ctdb_db->lockwait_overflow, h);
+	return 0;
+}
+
+/*
+  setup a non-blocking chainlock on a tdb record. If this function
+  returns NULL then it could not get the chainlock. Otherwise it
+  returns a opaque handle, and will call callback() once it has
+  managed to get the chainlock. You can cancel it by using talloc_free
+  on the returned handle.
+
+  It is the callers responsibility to unlock the chainlock once
+  acquired
+ */
+struct lockwait_handle *ctdb_lockwait(struct ctdb_db_context *ctdb_db,
+				      TDB_DATA key,
+				      void (*callback)(void *private_data),
+				      void *private_data)
+{
+	struct lockwait_handle *result, *i;
+	int ret;
+	pid_t parent = getpid();
+
+	CTDB_INCREMENT_STAT(ctdb_db->ctdb, lockwait_calls);
+	CTDB_INCREMENT_STAT(ctdb_db->ctdb, pending_lockwait_calls);
+
+	if (!(result = talloc_zero(private_data, struct lockwait_handle))) {
+		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_lockwait_calls);
+		return NULL;
+	}
+
+	result->callback = callback;
+	result->private_data = private_data;
+	result->ctdb = ctdb_db->ctdb;
+	result->ctdb_db = ctdb_db;
+	result->key = key;
+
+	/* If we already have a lockwait child for this request, then put this
+	   request on the overflow queue straight away
+	 */
+	for (i = ctdb_db->lockwait_active; i; i = i->next) {
+		if (key.dsize == i->key.dsize
+		    && memcmp(key.dptr, i->key.dptr, key.dsize) == 0) {
+			DLIST_ADD_END(ctdb_db->lockwait_overflow, result, NULL);
+			talloc_set_destructor(result, overflow_lockwait_destructor);
+			return result;
+		}
+	}
+
+	/* Don't fire off too many children at once! */
+	if (ctdb_db->pending_requests > 200) {
+		DLIST_ADD_END(ctdb_db->lockwait_overflow, result, NULL);
+		talloc_set_destructor(result, overflow_lockwait_destructor);
+		DEBUG(DEBUG_DEBUG, (__location__ " Created overflow for %s\n",
+				    ctdb_db->db_name));
+		return result;
+	}
+
+	ret = pipe(result->fd);
+
+	if (ret != 0) {
+		talloc_free(result);
+		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_lockwait_calls);
+		return NULL;
+	}
+
+	result->child = ctdb_fork(ctdb_db->ctdb);
+
+	if (result->child == (pid_t)-1) {
+		close(result->fd[0]);
+		close(result->fd[1]);
+		talloc_free(result);
+		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_lockwait_calls);
+		return NULL;
+	}
+
+	if (result->child == 0) {
+		char c = 0;
+		close(result->fd[0]);
+		debug_extra = talloc_asprintf(NULL, "chainlock-%s:", ctdb_db->db_name);
+		tdb_chainlock(ctdb_db->ltdb->tdb, key);
+		write(result->fd[1], &c, 1);
+		/* make sure we die when our parent dies */
+		while (kill(parent, 0) == 0 || errno != ESRCH) {
+			sleep(5);
+		}
+		_exit(0);
+	}
+
+	close(result->fd[1]);
+	set_close_on_exec(result->fd[0]);
+
+	/* This is an active lockwait child process */
+	DLIST_ADD_END(ctdb_db->lockwait_active, result, NULL);
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to child lockwait process\n", result->fd[0]));
+
+	ctdb_db->pending_requests++;
+	talloc_set_destructor(result, lockwait_destructor);
+
+	result->fde = event_add_fd(ctdb_db->ctdb->ev, result, result->fd[0],
+				   EVENT_FD_READ, lockwait_handler,
+				   (void *)result);
+	if (result->fde == NULL) {
+		talloc_free(result);
+		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_lockwait_calls);
+		return NULL;
+	}
+	tevent_fd_set_auto_close(result->fde);
+
+	result->start_time = timeval_current();
+	return result;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_logging.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_logging.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_logging.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,599 @@
+/* 
+   ctdb logging code
+
+   Copyright (C) Andrew Tridgell  2008
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "../include/ctdb_client.h"
+#include "../include/ctdb_private.h"
+#include "system/syslog.h"
+#include "system/time.h"
+#include "system/filesys.h"
+
+struct syslog_message {
+	uint32_t level;
+	uint32_t len;
+	char message[1];
+};
+
+
+struct ctdb_syslog_state {
+	int syslog_fd;
+	int fd[2];
+};
+
+static int syslogd_is_started = 0;
+
+
+/* called when child is finished
+ * this is for the syslog daemon, we can not use DEBUG here
+ */
+static void ctdb_syslog_handler(struct event_context *ev, struct fd_event *fde, 
+				      uint16_t flags, void *p)
+{
+	struct ctdb_syslog_state *state = talloc_get_type(p, struct ctdb_syslog_state);
+
+	int count;
+	char str[65536];
+	struct syslog_message *msg;
+
+	if (state == NULL) {
+		return;
+	}
+
+	count = recv(state->syslog_fd, str, sizeof(str), 0);
+	if (count < sizeof(struct syslog_message)) {
+		return;
+	}
+	msg = (struct syslog_message *)str;
+
+	syslog(msg->level, "%s", msg->message);
+}
+
+
+/* called when the pipd from the main daemon has closed
+ * this is for the syslog daemon, we can not use DEBUG here
+ */
+static void ctdb_syslog_terminate_handler(struct event_context *ev, struct fd_event *fde, 
+				      uint16_t flags, void *p)
+{
+	syslog(LOG_ERR, "Shutting down SYSLOG daemon with pid:%d", (int)getpid());
+	_exit(0);
+}
+
+
+
+/*
+ * this is for the syslog daemon, we can not use DEBUG here
+ */
+int start_syslog_daemon(struct ctdb_context *ctdb)
+{
+	struct sockaddr_in syslog_sin;
+	struct ctdb_syslog_state *state;
+	struct tevent_fd *fde;
+
+	state = talloc(ctdb, struct ctdb_syslog_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	if (pipe(state->fd) != 0) {
+		printf("Failed to create syslog pipe\n");
+		talloc_free(state);
+		return -1;
+	}
+	
+	ctdb->syslogd_pid = ctdb_fork(ctdb);
+	if (ctdb->syslogd_pid == (pid_t)-1) {
+		printf("Failed to create syslog child process\n");
+		close(state->fd[0]);
+		close(state->fd[1]);
+		talloc_free(state);
+		return -1;
+	}
+
+	syslogd_is_started = 1;
+
+	if (ctdb->syslogd_pid != 0) {
+		DEBUG(DEBUG_ERR,("Starting SYSLOG child process with pid:%d\n", (int)ctdb->syslogd_pid));
+
+		close(state->fd[1]);
+		set_close_on_exec(state->fd[0]);
+
+		return 0;
+	}
+
+	debug_extra = talloc_asprintf(NULL, "syslogd:");
+	talloc_free(ctdb->ev);
+	ctdb->ev = event_context_init(NULL);
+	tevent_loop_allow_nesting(ctdb->ev);
+
+	syslog(LOG_ERR, "Starting SYSLOG daemon with pid:%d", (int)getpid());
+
+	close(state->fd[0]);
+	set_close_on_exec(state->fd[1]);
+	fde = event_add_fd(ctdb->ev, state, state->fd[1], EVENT_FD_READ,
+		     ctdb_syslog_terminate_handler, state);
+	tevent_fd_set_auto_close(fde);
+
+	state->syslog_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (state->syslog_fd == -1) {
+		printf("Failed to create syslog socket\n");
+		return -1;
+	}
+
+	set_close_on_exec(state->syslog_fd);
+
+	syslog_sin.sin_family = AF_INET;
+	syslog_sin.sin_port   = htons(CTDB_PORT);
+	syslog_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);	
+
+	if (bind(state->syslog_fd, &syslog_sin, sizeof(syslog_sin)) == -1) {
+		if (errno == EADDRINUSE) {
+			/* this is ok, we already have a syslog daemon */
+			_exit(0);
+		}
+		printf("syslog daemon failed to bind to socket. errno:%d(%s)\n", errno, strerror(errno));
+		_exit(10);
+	}
+
+
+	fde = event_add_fd(ctdb->ev, state, state->syslog_fd, EVENT_FD_READ,
+		     ctdb_syslog_handler, state);
+	tevent_fd_set_auto_close(fde);
+
+	event_loop_wait(ctdb->ev);
+
+	/* this should not happen */
+	_exit(10);
+}
+
+struct ctdb_log_state {
+	struct ctdb_context *ctdb;
+	const char *prefix;
+	int fd, pfd;
+	char buf[1024];
+	uint16_t buf_used;
+	bool use_syslog;
+	void (*logfn)(const char *, uint16_t, void *);
+	void *logfn_private;
+};
+
+/* we need this global to keep the DEBUG() syntax */
+static struct ctdb_log_state *log_state;
+
+/*
+  syslog logging function
+ */
+static void ctdb_syslog_log(const char *format, va_list ap)
+{
+	struct syslog_message *msg;
+	int level = LOG_DEBUG;
+	char *s = NULL;
+	int len, ret;
+	int syslog_fd;
+	struct sockaddr_in syslog_sin;
+
+	ret = vasprintf(&s, format, ap);
+	if (ret == -1) {
+		return;
+	}
+
+	switch (this_log_level) {
+	case DEBUG_EMERG: 
+		level = LOG_EMERG; 
+		break;
+	case DEBUG_ALERT: 
+		level = LOG_ALERT; 
+		break;
+	case DEBUG_CRIT: 
+		level = LOG_CRIT; 
+		break;
+	case DEBUG_ERR: 
+		level = LOG_ERR; 
+		break;
+	case DEBUG_WARNING: 
+		level = LOG_WARNING; 
+		break;
+	case DEBUG_NOTICE: 
+		level = LOG_NOTICE;
+		break;
+	case DEBUG_INFO: 
+		level = LOG_INFO;
+		break;
+	default:
+		level = LOG_DEBUG;
+		break;		
+	}
+
+	len = offsetof(struct syslog_message, message) + strlen(debug_extra) + strlen(s) + 1;
+	msg = malloc(len);
+	if (msg == NULL) {
+		free(s);
+		return;
+	}
+	msg->level = level;
+	msg->len   = strlen(debug_extra) + strlen(s);
+	strcpy(msg->message, debug_extra);
+	strcat(msg->message, s);
+
+	if (syslogd_is_started == 0) {
+		syslog(msg->level, "%s", msg->message);
+	} else {
+		syslog_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+		if (syslog_fd == -1) {
+			printf("Failed to create syslog socket\n");
+			free(s);
+			free(msg);
+			return;
+		}
+
+		syslog_sin.sin_family = AF_INET;
+		syslog_sin.sin_port   = htons(CTDB_PORT);
+		syslog_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);	
+
+       
+		ret = sendto(syslog_fd, msg, len, 0, &syslog_sin, sizeof(syslog_sin));
+		/* no point in checking here since we cant log an error */
+
+		close(syslog_fd);
+	}
+
+	free(s);
+	free(msg);
+}
+
+
+/*
+  log file logging function
+ */
+static void ctdb_logfile_log(const char *format, va_list ap)
+{
+	struct timeval t;
+	char *s = NULL;
+	struct tm *tm;
+	char tbuf[100];
+	char *s2 = NULL;
+	int ret;
+
+	ret = vasprintf(&s, format, ap);
+	if (ret == -1) {
+		const char *errstr = "vasprintf failed\n";
+
+		write(log_state->fd, errstr, strlen(errstr));
+		return;
+	}
+
+	t = timeval_current();
+	tm = localtime(&t.tv_sec);
+
+	strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
+
+	ret = asprintf(&s2, "%s.%06u [%s%5u]: %s",
+		       tbuf, (unsigned)t.tv_usec,
+		       debug_extra, (unsigned)getpid(), s);
+	free(s);
+	if (ret == -1) {
+		const char *errstr = "asprintf failed\n";
+		write(log_state->fd, errstr, strlen(errstr));
+		return;
+	}
+	if (s2) {
+		write(log_state->fd, s2, strlen(s2));
+		free(s2);
+	}
+}
+
+static void ctdb_logfile_log_add(const char *format, va_list ap)
+{
+	char *s = NULL;
+	int ret;
+
+	ret = vasprintf(&s, format, ap);
+	if (ret == -1) {
+		const char *errstr = "vasprintf failed\n";
+
+		write(log_state->fd, errstr, strlen(errstr));
+		return;
+	}
+
+	if (s) {
+		write(log_state->fd, s, strlen(s));
+		free(s);
+	}
+}
+
+
+
+/*
+  choose the logfile location
+*/
+int ctdb_set_logfile(struct ctdb_context *ctdb, const char *logfile, bool use_syslog)
+{
+	int ret;
+
+	ctdb->log = talloc_zero(ctdb, struct ctdb_log_state);
+	if (ctdb->log == NULL) {
+		printf("talloc_zero failed\n");
+		abort();
+	}
+
+	ctdb->log->ctdb = ctdb;
+	log_state = ctdb->log;
+
+	if (use_syslog) {
+		do_debug_v = ctdb_syslog_log;
+		do_debug_add_v = ctdb_syslog_log;
+		ctdb->log->use_syslog = true;
+	} else if (logfile == NULL || strcmp(logfile, "-") == 0) {
+		do_debug_v = ctdb_logfile_log;
+		do_debug_add_v = ctdb_logfile_log_add;
+		ctdb->log->fd = 1;
+		/* also catch stderr of subcommands to stdout */
+		ret = dup2(1, 2);
+		if (ret == -1) {
+			printf("dup2 failed: %s\n", strerror(errno));
+			abort();
+		}
+	} else {
+		do_debug_v = ctdb_logfile_log;
+		do_debug_add_v = ctdb_logfile_log_add;
+
+		ctdb->log->fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, 0666);
+		if (ctdb->log->fd == -1) {
+			printf("Failed to open logfile %s\n", logfile);
+			abort();
+		}
+	}
+
+	return 0;
+}
+
+/* Note that do_debug always uses the global log state. */
+static void write_to_log(struct ctdb_log_state *log,
+			 const char *buf, unsigned int len)
+{
+	if (script_log_level <= LogLevel) {
+		if (log != NULL && log->prefix != NULL) {
+			do_debug("%s: %*.*s\n", log->prefix, len, len, buf);
+		} else {
+			do_debug("%*.*s\n", len, len, buf);
+		}
+		/* log it in the eventsystem as well */
+		if (log->logfn)
+			log->logfn(log->buf, len, log->logfn_private);
+	}
+}
+
+/*
+  called when log data comes in from a child process
+ */
+static void ctdb_log_handler(struct event_context *ev, struct fd_event *fde, 
+			     uint16_t flags, void *private)
+{
+	struct ctdb_log_state *log = talloc_get_type(private, struct ctdb_log_state);
+	char *p;
+	int n;
+
+	if (!(flags & EVENT_FD_READ)) {
+		return;
+	}
+
+	n = read(log->pfd, &log->buf[log->buf_used],
+		 sizeof(log->buf) - log->buf_used);
+	if (n > 0) {
+		log->buf_used += n;
+	} else if (n == 0) {
+		if (log != log_state) {
+			talloc_free(log);
+		}
+		return;
+	}
+
+	this_log_level = script_log_level;
+
+	while (log->buf_used > 0 &&
+	       (p = memchr(log->buf, '\n', log->buf_used)) != NULL) {
+		int n1 = (p - log->buf)+1;
+		int n2 = n1 - 1;
+		/* swallow \r from child processes */
+		if (n2 > 0 && log->buf[n2-1] == '\r') {
+			n2--;
+		}
+		write_to_log(log, log->buf, n2);
+		memmove(log->buf, p+1, sizeof(log->buf) - n1);
+		log->buf_used -= n1;
+	}
+
+	/* the buffer could have completely filled - unfortunately we have
+	   no choice but to dump it out straight away */
+	if (log->buf_used == sizeof(log->buf)) {
+		write_to_log(log, log->buf, log->buf_used);
+		log->buf_used = 0;
+	}
+}
+
+static int log_context_destructor(struct ctdb_log_state *log)
+{
+	/* Flush buffer in case it wasn't \n-terminated. */
+	if (log->buf_used > 0) {
+		this_log_level = script_log_level;
+		write_to_log(log, log->buf, log->buf_used);
+	}
+	return 0;
+}
+
+/*
+   fork(), redirecting child output to logging and specified callback.
+*/
+struct ctdb_log_state *ctdb_fork_with_logging(TALLOC_CTX *mem_ctx,
+					      struct ctdb_context *ctdb,
+					      const char *log_prefix,
+					      void (*logfn)(const char *, uint16_t, void *),
+					      void *logfn_private, pid_t *pid)
+{
+	int p[2];
+	struct ctdb_log_state *log;
+	struct tevent_fd *fde;
+
+	log = talloc_zero(mem_ctx, struct ctdb_log_state);
+	CTDB_NO_MEMORY_NULL(ctdb, log);
+	log->ctdb = ctdb;
+	log->prefix = log_prefix;
+	log->logfn = logfn;
+	log->logfn_private = (void *)logfn_private;
+
+	if (pipe(p) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to setup for child logging pipe\n"));
+		goto free_log;
+	}
+
+	*pid = ctdb_fork(ctdb);
+
+	/* Child? */
+	if (*pid == 0) {
+		close(STDOUT_FILENO);
+		close(STDERR_FILENO);
+		dup2(p[1], STDOUT_FILENO);
+		dup2(p[1], STDERR_FILENO);
+		close(p[0]);
+		close(p[1]);
+		return log;
+	}
+	close(p[1]);
+
+	/* We failed? */
+	if (*pid < 0) {
+		DEBUG(DEBUG_ERR, (__location__ " fork failed for child process\n"));
+		close(p[0]);
+		goto free_log;
+	}
+
+	log->pfd = p[0];
+	set_close_on_exec(log->pfd);
+	talloc_set_destructor(log, log_context_destructor);
+	fde = event_add_fd(ctdb->ev, log, log->pfd,
+			   EVENT_FD_READ, ctdb_log_handler, log);
+	tevent_fd_set_auto_close(fde);
+
+	return log;
+
+free_log:
+	talloc_free(log);
+	return NULL;
+}
+
+/*
+  setup for logging of child process stdout
+*/
+int ctdb_set_child_logging(struct ctdb_context *ctdb)
+{
+	int p[2];
+	int old_stdout, old_stderr;
+	struct tevent_fd *fde;
+
+	if (ctdb->log->fd == STDOUT_FILENO) {
+		/* not needed for stdout logging */
+		return 0;
+	}
+
+	/* setup a pipe to catch IO from subprocesses */
+	if (pipe(p) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to setup for child logging pipe\n"));
+		return -1;
+	}
+
+	/* We'll fail if stderr/stdout not already open; it's simpler. */
+	old_stdout = dup(STDOUT_FILENO);
+	old_stderr = dup(STDERR_FILENO);
+	if (dup2(p[1], STDOUT_FILENO) < 0 || dup2(p[1], STDERR_FILENO) < 0) {
+		int saved_errno = errno;
+		dup2(old_stdout, STDOUT_FILENO);
+		dup2(old_stderr, STDERR_FILENO);
+		close(old_stdout);
+		close(old_stderr);
+		close(p[0]);
+		close(p[1]);
+		errno = saved_errno;
+
+		printf(__location__ " dup2 failed: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	close(p[1]);
+	close(old_stdout);
+	close(old_stderr);
+
+	/* Is this correct for STDOUT and STDERR ? */
+	set_close_on_exec(STDOUT_FILENO);
+	set_close_on_exec(STDERR_FILENO);
+	set_close_on_exec(p[0]);
+
+	fde = event_add_fd(ctdb->ev, ctdb->log, p[0],
+			   EVENT_FD_READ, ctdb_log_handler, ctdb->log);
+	tevent_fd_set_auto_close(fde);
+
+	ctdb->log->pfd = p[0];
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d for logging\n", p[0]));
+
+	return 0;
+}
+
+
+/*
+ * set up a log handler to catch logging from TEVENT
+ */
+static void ctdb_tevent_logging(void *private_data,
+				enum tevent_debug_level level,
+				const char *fmt,
+				va_list ap)
+{
+	enum debug_level lvl = DEBUG_EMERG;
+
+	switch (level) {
+	case TEVENT_DEBUG_FATAL:
+		lvl = DEBUG_EMERG;
+		break;
+	case TEVENT_DEBUG_ERROR:
+		lvl = DEBUG_ERR;
+		break;
+	case TEVENT_DEBUG_WARNING:
+		lvl = DEBUG_WARNING;
+		break;
+	case TEVENT_DEBUG_TRACE:
+		lvl = DEBUG_DEBUG;
+		break;
+	}
+
+	if (lvl <= LogLevel) {
+		this_log_level = lvl;
+		do_debug_v(fmt, ap);
+	}
+}
+
+int ctdb_init_tevent_logging(struct ctdb_context *ctdb)
+{
+	int ret;
+
+	ret = tevent_set_debug(ctdb->ev,
+			ctdb_tevent_logging,
+		     	ctdb);
+	return ret;
+}
+
+
+	

Added: branches/ctdb/squeeze-backports/server/ctdb_ltdb_server.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_ltdb_server.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_ltdb_server.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1486 @@
+/* 
+   ctdb ltdb code - server side
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include "system/time.h"
+#include "../include/ctdb_private.h"
+#include "../common/rb_tree.h"
+#include "db_wrap.h"
+#include "lib/util/dlinklist.h"
+#include <ctype.h>
+
+#define PERSISTENT_HEALTH_TDB "persistent_health.tdb"
+
+/*
+  this is the dummy null procedure that all databases support
+*/
+static int ctdb_null_func(struct ctdb_call_info *call)
+{
+	return 0;
+}
+
+/*
+  this is a plain fetch procedure that all databases support
+*/
+static int ctdb_fetch_func(struct ctdb_call_info *call)
+{
+	call->reply_data = &call->record_data;
+	return 0;
+}
+
+/*
+  this is a plain fetch procedure that all databases support
+  this returns the full record including the ltdb header
+*/
+static int ctdb_fetch_with_header_func(struct ctdb_call_info *call)
+{
+	call->reply_data = talloc(call, TDB_DATA);
+	if (call->reply_data == NULL) {
+		return -1;
+	}
+	call->reply_data->dsize = sizeof(struct ctdb_ltdb_header) + call->record_data.dsize;
+	call->reply_data->dptr  = talloc_size(call->reply_data, call->reply_data->dsize);
+	if (call->reply_data->dptr == NULL) {
+		return -1;
+	}
+	memcpy(call->reply_data->dptr, call->header, sizeof(struct ctdb_ltdb_header));
+	memcpy(&call->reply_data->dptr[sizeof(struct ctdb_ltdb_header)], call->record_data.dptr, call->record_data.dsize);
+
+	return 0;
+}
+
+
+/**
+ * write a record to a normal database
+ *
+ * This is the server-variant of the ctdb_ltdb_store function.
+ * It contains logic to determine whether a record should be
+ * stored or deleted. It also sends SCHEDULE_FOR_DELETION
+ * controls to the local ctdb daemon if apporpriate.
+ */
+static int ctdb_ltdb_store_server(struct ctdb_db_context *ctdb_db,
+				  TDB_DATA key,
+				  struct ctdb_ltdb_header *header,
+				  TDB_DATA data)
+{
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	TDB_DATA rec;
+	int ret;
+	bool seqnum_suppressed = false;
+	bool keep = false;
+	bool schedule_for_deletion = false;
+	uint32_t lmaster;
+
+	if (ctdb->flags & CTDB_FLAG_TORTURE) {
+		struct ctdb_ltdb_header *h2;
+		rec = tdb_fetch(ctdb_db->ltdb->tdb, key);
+		h2 = (struct ctdb_ltdb_header *)rec.dptr;
+		if (rec.dptr && rec.dsize >= sizeof(h2) && h2->rsn > header->rsn) {
+			DEBUG(DEBUG_CRIT,("RSN regression! %llu %llu\n",
+				 (unsigned long long)h2->rsn, (unsigned long long)header->rsn));
+		}
+		if (rec.dptr) free(rec.dptr);
+	}
+
+	if (ctdb->vnn_map == NULL) {
+		/*
+		 * Called from a client: always store the record
+		 * Also don't call ctdb_lmaster since it uses the vnn_map!
+		 */
+		keep = true;
+		goto store;
+	}
+
+	lmaster = ctdb_lmaster(ctdb_db->ctdb, &key);
+
+	/*
+	 * If we migrate an empty record off to another node
+	 * and the record has not been migrated with data,
+	 * delete the record instead of storing the empty record.
+	 */
+	if (data.dsize != 0) {
+		keep = true;
+	} else if (ctdb_db->persistent) {
+		keep = true;
+	} else if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
+		/*
+		 * The record is not created by the client but
+		 * automatically by the ctdb_ltdb_fetch logic that
+		 * creates a record with an initial header in the
+		 * ltdb before trying to migrate the record from
+		 * the current lmaster. Keep it instead of trying
+		 * to delete the non-existing record...
+		 */
+		keep = true;
+		schedule_for_deletion = true;
+	} else if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
+		keep = true;
+	} else if (ctdb_db->ctdb->pnn == lmaster) {
+		/*
+		 * If we are lmaster, then we usually keep the record.
+		 * But if we retrieve the dmaster role by a VACUUM_MIGRATE
+		 * and the record is empty and has never been migrated
+		 * with data, then we should delete it instead of storing it.
+		 * This is part of the vacuuming process.
+		 *
+		 * The reason that we usually need to store even empty records
+		 * on the lmaster is that a client operating directly on the
+		 * lmaster (== dmaster) expects the local copy of the record to
+		 * exist after successful ctdb migrate call. If the record does
+		 * not exist, the client goes into a migrate loop and eventually
+		 * fails. So storing the empty record makes sure that we do not
+		 * need to change the client code.
+		 */
+		if (!(header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED)) {
+			keep = true;
+		} else if (ctdb_db->ctdb->pnn != header->dmaster) {
+			keep = true;
+		}
+	} else if (ctdb_db->ctdb->pnn == header->dmaster) {
+		keep = true;
+	}
+
+	if (keep &&
+	    (data.dsize == 0) &&
+	    !ctdb_db->persistent &&
+	    (ctdb_db->ctdb->pnn == header->dmaster))
+	{
+		schedule_for_deletion = true;
+	}
+
+store:
+	/*
+	 * The VACUUM_MIGRATED flag is only set temporarily for
+	 * the above logic when the record was retrieved by a
+	 * VACUUM_MIGRATE call and should not be stored in the
+	 * database.
+	 *
+	 * The VACUUM_MIGRATE call is triggered by a vacuum fetch,
+	 * and there are two cases in which the corresponding record
+	 * is stored in the local database:
+	 * 1. The record has been migrated with data in the past
+	 *    (the MIGRATED_WITH_DATA record flag is set).
+	 * 2. The record has been filled with data again since it
+	 *    had been submitted in the VACUUM_FETCH message to the
+	 *    lmaster.
+	 * For such records it is important to not store the
+	 * VACUUM_MIGRATED flag in the database.
+	 */
+	header->flags &= ~CTDB_REC_FLAG_VACUUM_MIGRATED;
+
+	/*
+	 * Similarly, clear the AUTOMATIC flag which should not enter
+	 * the local database copy since this would require client
+	 * modifications to clear the flag when the client stores
+	 * the record.
+	 */
+	header->flags &= ~CTDB_REC_FLAG_AUTOMATIC;
+
+	rec.dsize = sizeof(*header) + data.dsize;
+	rec.dptr = talloc_size(ctdb, rec.dsize);
+	CTDB_NO_MEMORY(ctdb, rec.dptr);
+
+	memcpy(rec.dptr, header, sizeof(*header));
+	memcpy(rec.dptr + sizeof(*header), data.dptr, data.dsize);
+
+	/* Databases with seqnum updates enabled only get their seqnum
+	   changes when/if we modify the data */
+	if (ctdb_db->seqnum_update != NULL) {
+		TDB_DATA old;
+		old = tdb_fetch(ctdb_db->ltdb->tdb, key);
+
+		if ( (old.dsize == rec.dsize)
+		&& !memcmp(old.dptr+sizeof(struct ctdb_ltdb_header),
+			  rec.dptr+sizeof(struct ctdb_ltdb_header),
+			  rec.dsize-sizeof(struct ctdb_ltdb_header)) ) {
+			tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_SEQNUM);
+			seqnum_suppressed = true;
+		}
+		if (old.dptr) free(old.dptr);
+	}
+
+	DEBUG(DEBUG_DEBUG, (__location__ " db[%s]: %s record: hash[0x%08x]\n",
+			    ctdb_db->db_name,
+			    keep?"storing":"deleting",
+			    ctdb_hash(&key)));
+
+	if (keep) {
+		ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE);
+	} else {
+		ret = tdb_delete(ctdb_db->ltdb->tdb, key);
+	}
+
+	if (ret != 0) {
+		int lvl = DEBUG_ERR;
+
+		if (keep == false &&
+		    tdb_error(ctdb_db->ltdb->tdb) == TDB_ERR_NOEXIST)
+		{
+			lvl = DEBUG_DEBUG;
+		}
+
+		DEBUG(lvl, (__location__ " db[%s]: Failed to %s record: "
+			    "%d - %s\n",
+			    ctdb_db->db_name,
+			    keep?"store":"delete", ret,
+			    tdb_errorstr(ctdb_db->ltdb->tdb)));
+
+		schedule_for_deletion = false;
+	}
+	if (seqnum_suppressed) {
+		tdb_add_flags(ctdb_db->ltdb->tdb, TDB_SEQNUM);
+	}
+
+	talloc_free(rec.dptr);
+
+	if (schedule_for_deletion) {
+		int ret2;
+		ret2 = ctdb_local_schedule_for_deletion(ctdb_db, header, key);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " ctdb_local_schedule_for_deletion failed.\n"));
+		}
+	}
+
+	return ret;
+}
+
+struct lock_fetch_state {
+	struct ctdb_context *ctdb;
+	void (*recv_pkt)(void *, struct ctdb_req_header *);
+	void *recv_context;
+	struct ctdb_req_header *hdr;
+	uint32_t generation;
+	bool ignore_generation;
+};
+
+/*
+  called when we should retry the operation
+ */
+static void lock_fetch_callback(void *p)
+{
+	struct lock_fetch_state *state = talloc_get_type(p, struct lock_fetch_state);
+	if (!state->ignore_generation &&
+	    state->generation != state->ctdb->vnn_map->generation) {
+		DEBUG(DEBUG_NOTICE,("Discarding previous generation lockwait packet\n"));
+		talloc_free(state->hdr);
+		return;
+	}
+	state->recv_pkt(state->recv_context, state->hdr);
+	DEBUG(DEBUG_INFO,(__location__ " PACKET REQUEUED\n"));
+}
+
+
+/*
+  do a non-blocking ltdb_lock, deferring this ctdb request until we
+  have the chainlock
+
+  It does the following:
+
+   1) tries to get the chainlock. If it succeeds, then it returns 0
+
+   2) if it fails to get a chainlock immediately then it sets up a
+   non-blocking chainlock via ctdb_lockwait, and when it gets the
+   chainlock it re-submits this ctdb request to the main packet
+   receive function
+
+   This effectively queues all ctdb requests that cannot be
+   immediately satisfied until it can get the lock. This means that
+   the main ctdb daemon will not block waiting for a chainlock held by
+   a client
+
+   There are 3 possible return values:
+
+       0:    means that it got the lock immediately.
+      -1:    means that it failed to get the lock, and won't retry
+      -2:    means that it failed to get the lock immediately, but will retry
+ */
+int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db, 
+			   TDB_DATA key, struct ctdb_req_header *hdr,
+			   void (*recv_pkt)(void *, struct ctdb_req_header *),
+			   void *recv_context, bool ignore_generation)
+{
+	int ret;
+	struct tdb_context *tdb = ctdb_db->ltdb->tdb;
+	struct lockwait_handle *h;
+	struct lock_fetch_state *state;
+	
+	ret = tdb_chainlock_nonblock(tdb, key);
+
+	if (ret != 0 &&
+	    !(errno == EACCES || errno == EAGAIN || errno == EDEADLK)) {
+		/* a hard failure - don't try again */
+		return -1;
+	}
+
+	/* when torturing, ensure we test the contended path */
+	if ((ctdb_db->ctdb->flags & CTDB_FLAG_TORTURE) &&
+	    random() % 5 == 0) {
+		ret = -1;
+		tdb_chainunlock(tdb, key);
+	}
+
+	/* first the non-contended path */
+	if (ret == 0) {
+		return 0;
+	}
+
+	state = talloc(hdr, struct lock_fetch_state);
+	state->ctdb = ctdb_db->ctdb;
+	state->hdr = hdr;
+	state->recv_pkt = recv_pkt;
+	state->recv_context = recv_context;
+	state->generation = ctdb_db->ctdb->vnn_map->generation;
+	state->ignore_generation = ignore_generation;
+
+	/* now the contended path */
+	h = ctdb_lockwait(ctdb_db, key, lock_fetch_callback, state);
+	if (h == NULL) {
+		return -1;
+	}
+
+	/* we need to move the packet off the temporary context in ctdb_input_pkt(),
+	   so it won't be freed yet */
+	talloc_steal(state, hdr);
+	talloc_steal(state, h);
+
+	/* now tell the caller than we will retry asynchronously */
+	return -2;
+}
+
+/*
+  a varient of ctdb_ltdb_lock_requeue that also fetches the record
+ */
+int ctdb_ltdb_lock_fetch_requeue(struct ctdb_db_context *ctdb_db, 
+				 TDB_DATA key, struct ctdb_ltdb_header *header, 
+				 struct ctdb_req_header *hdr, TDB_DATA *data,
+				 void (*recv_pkt)(void *, struct ctdb_req_header *),
+				 void *recv_context, bool ignore_generation)
+{
+	int ret;
+
+	ret = ctdb_ltdb_lock_requeue(ctdb_db, key, hdr, recv_pkt, 
+				     recv_context, ignore_generation);
+	if (ret == 0) {
+		ret = ctdb_ltdb_fetch(ctdb_db, key, header, hdr, data);
+		if (ret != 0) {
+			int uret;
+			uret = ctdb_ltdb_unlock(ctdb_db, key);
+			if (uret != 0) {
+				DEBUG(DEBUG_ERR,(__location__ " ctdb_ltdb_unlock() failed with error %d\n", uret));
+			}
+		}
+	}
+	return ret;
+}
+
+
+/*
+  paraoid check to see if the db is empty
+ */
+static void ctdb_check_db_empty(struct ctdb_db_context *ctdb_db)
+{
+	struct tdb_context *tdb = ctdb_db->ltdb->tdb;
+	int count = tdb_traverse_read(tdb, NULL, NULL);
+	if (count != 0) {
+		DEBUG(DEBUG_ALERT,(__location__ " tdb '%s' not empty on attach! aborting\n",
+			 ctdb_db->db_path));
+		ctdb_fatal(ctdb_db->ctdb, "database not empty on attach");
+	}
+}
+
+int ctdb_load_persistent_health(struct ctdb_context *ctdb,
+				struct ctdb_db_context *ctdb_db)
+{
+	struct tdb_context *tdb = ctdb->db_persistent_health->tdb;
+	char *old;
+	char *reason = NULL;
+	TDB_DATA key;
+	TDB_DATA val;
+
+	key.dptr = discard_const_p(uint8_t, ctdb_db->db_name);
+	key.dsize = strlen(ctdb_db->db_name);
+
+	old = ctdb_db->unhealthy_reason;
+	ctdb_db->unhealthy_reason = NULL;
+
+	val = tdb_fetch(tdb, key);
+	if (val.dsize > 0) {
+		reason = talloc_strndup(ctdb_db,
+					(const char *)val.dptr,
+					val.dsize);
+		if (reason == NULL) {
+			DEBUG(DEBUG_ALERT,(__location__ " talloc_strndup(%d) failed\n",
+					   (int)val.dsize));
+			ctdb_db->unhealthy_reason = old;
+			free(val.dptr);
+			return -1;
+		}
+	}
+
+	if (val.dptr) {
+		free(val.dptr);
+	}
+
+	talloc_free(old);
+	ctdb_db->unhealthy_reason = reason;
+	return 0;
+}
+
+int ctdb_update_persistent_health(struct ctdb_context *ctdb,
+				  struct ctdb_db_context *ctdb_db,
+				  const char *given_reason,/* NULL means healthy */
+				  int num_healthy_nodes)
+{
+	struct tdb_context *tdb = ctdb->db_persistent_health->tdb;
+	int ret;
+	TDB_DATA key;
+	TDB_DATA val;
+	char *new_reason = NULL;
+	char *old_reason = NULL;
+
+	ret = tdb_transaction_start(tdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ALERT,(__location__ " tdb_transaction_start('%s') failed: %d - %s\n",
+				   tdb_name(tdb), ret, tdb_errorstr(tdb)));
+		return -1;
+	}
+
+	ret = ctdb_load_persistent_health(ctdb, ctdb_db);
+	if (ret != 0) {
+		DEBUG(DEBUG_ALERT,(__location__ " ctdb_load_persistent_health('%s') failed: %d\n",
+				   ctdb_db->db_name, ret));
+		return -1;
+	}
+	old_reason = ctdb_db->unhealthy_reason;
+
+	key.dptr = discard_const_p(uint8_t, ctdb_db->db_name);
+	key.dsize = strlen(ctdb_db->db_name);
+
+	if (given_reason) {
+		new_reason = talloc_strdup(ctdb_db, given_reason);
+		if (new_reason == NULL) {
+			DEBUG(DEBUG_ALERT,(__location__ " talloc_strdup(%s) failed\n",
+					  given_reason));
+			return -1;
+		}
+	} else if (old_reason && num_healthy_nodes == 0) {
+		/*
+		 * If the reason indicates ok, but there where no healthy nodes
+		 * available, that it means, we have not recovered valid content
+		 * of the db. So if there's an old reason, prefix it with
+		 * "NO-HEALTHY-NODES - "
+		 */
+		const char *prefix;
+
+#define _TMP_PREFIX "NO-HEALTHY-NODES - "
+		ret = strncmp(_TMP_PREFIX, old_reason, strlen(_TMP_PREFIX));
+		if (ret != 0) {
+			prefix = _TMP_PREFIX;
+		} else {
+			prefix = "";
+		}
+		new_reason = talloc_asprintf(ctdb_db, "%s%s",
+					 prefix, old_reason);
+		if (new_reason == NULL) {
+			DEBUG(DEBUG_ALERT,(__location__ " talloc_asprintf(%s%s) failed\n",
+					  prefix, old_reason));
+			return -1;
+		}
+#undef _TMP_PREFIX
+	}
+
+	if (new_reason) {
+		val.dptr = discard_const_p(uint8_t, new_reason);
+		val.dsize = strlen(new_reason);
+
+		ret = tdb_store(tdb, key, val, TDB_REPLACE);
+		if (ret != 0) {
+			tdb_transaction_cancel(tdb);
+			DEBUG(DEBUG_ALERT,(__location__ " tdb_store('%s', %s, %s) failed: %d - %s\n",
+					   tdb_name(tdb), ctdb_db->db_name, new_reason,
+					   ret, tdb_errorstr(tdb)));
+			talloc_free(new_reason);
+			return -1;
+		}
+		DEBUG(DEBUG_ALERT,("Updated db health for db(%s) to: %s\n",
+				   ctdb_db->db_name, new_reason));
+	} else if (old_reason) {
+		ret = tdb_delete(tdb, key);
+		if (ret != 0) {
+			tdb_transaction_cancel(tdb);
+			DEBUG(DEBUG_ALERT,(__location__ " tdb_delete('%s', %s) failed: %d - %s\n",
+					   tdb_name(tdb), ctdb_db->db_name,
+					   ret, tdb_errorstr(tdb)));
+			talloc_free(new_reason);
+			return -1;
+		}
+		DEBUG(DEBUG_NOTICE,("Updated db health for db(%s): OK\n",
+				   ctdb_db->db_name));
+	}
+
+	ret = tdb_transaction_commit(tdb);
+	if (ret != TDB_SUCCESS) {
+		DEBUG(DEBUG_ALERT,(__location__ " tdb_transaction_commit('%s') failed: %d - %s\n",
+				   tdb_name(tdb), ret, tdb_errorstr(tdb)));
+		talloc_free(new_reason);
+		return -1;
+	}
+
+	talloc_free(old_reason);
+	ctdb_db->unhealthy_reason = new_reason;
+
+	return 0;
+}
+
+static int ctdb_backup_corrupted_tdb(struct ctdb_context *ctdb,
+				     struct ctdb_db_context *ctdb_db)
+{
+	time_t now = time(NULL);
+	char *new_path;
+	char *new_reason;
+	int ret;
+	struct tm *tm;
+
+	tm = gmtime(&now);
+
+	/* formatted like: foo.tdb.0.corrupted.20091204160825.0Z */
+	new_path = talloc_asprintf(ctdb_db, "%s.corrupted."
+				   "%04u%02u%02u%02u%02u%02u.0Z",
+				   ctdb_db->db_path,
+				   tm->tm_year+1900, tm->tm_mon+1,
+				   tm->tm_mday, tm->tm_hour, tm->tm_min,
+				   tm->tm_sec);
+	if (new_path == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " talloc_asprintf() failed\n"));
+		return -1;
+	}
+
+	new_reason = talloc_asprintf(ctdb_db,
+				     "ERROR - Backup of corrupted TDB in '%s'",
+				     new_path);
+	if (new_reason == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " talloc_asprintf() failed\n"));
+		return -1;
+	}
+	ret = ctdb_update_persistent_health(ctdb, ctdb_db, new_reason, 0);
+	talloc_free(new_reason);
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT,(__location__
+				 ": ctdb_backup_corrupted_tdb(%s) not implemented yet\n",
+				 ctdb_db->db_path));
+		return -1;
+	}
+
+	ret = rename(ctdb_db->db_path, new_path);
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT,(__location__
+				  ": ctdb_backup_corrupted_tdb(%s) rename to %s failed: %d - %s\n",
+				  ctdb_db->db_path, new_path,
+				  errno, strerror(errno)));
+		talloc_free(new_path);
+		return -1;
+	}
+
+	DEBUG(DEBUG_CRIT,(__location__
+			 ": ctdb_backup_corrupted_tdb(%s) renamed to %s\n",
+			 ctdb_db->db_path, new_path));
+	talloc_free(new_path);
+	return 0;
+}
+
+int ctdb_recheck_persistent_health(struct ctdb_context *ctdb)
+{
+	struct ctdb_db_context *ctdb_db;
+	int ret;
+	int ok = 0;
+	int fail = 0;
+
+	for (ctdb_db = ctdb->db_list; ctdb_db; ctdb_db = ctdb_db->next) {
+		if (!ctdb_db->persistent) {
+			continue;
+		}
+
+		ret = ctdb_load_persistent_health(ctdb, ctdb_db);
+		if (ret != 0) {
+			DEBUG(DEBUG_ALERT,(__location__
+					   " load persistent health for '%s' failed\n",
+					   ctdb_db->db_path));
+			return -1;
+		}
+
+		if (ctdb_db->unhealthy_reason == NULL) {
+			ok++;
+			DEBUG(DEBUG_INFO,(__location__
+				   " persistent db '%s' healthy\n",
+				   ctdb_db->db_path));
+			continue;
+		}
+
+		fail++;
+		DEBUG(DEBUG_ALERT,(__location__
+				   " persistent db '%s' unhealthy: %s\n",
+				   ctdb_db->db_path,
+				   ctdb_db->unhealthy_reason));
+	}
+	DEBUG((fail!=0)?DEBUG_ALERT:DEBUG_NOTICE,
+	      ("ctdb_recheck_presistent_health: OK[%d] FAIL[%d]\n",
+	       ok, fail));
+
+	if (fail != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+  mark a database - as healthy
+ */
+int32_t ctdb_control_db_set_healthy(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	uint32_t db_id = *(uint32_t *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
+	int ret;
+	bool may_recover = false;
+
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%x\n", db_id));
+		return -1;
+	}
+
+	if (ctdb_db->unhealthy_reason) {
+		may_recover = true;
+	}
+
+	ret = ctdb_update_persistent_health(ctdb, ctdb_db, NULL, 1);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__
+				 " ctdb_update_persistent_health(%s) failed\n",
+				 ctdb_db->db_name));
+		return -1;
+	}
+
+	if (may_recover && !ctdb->done_startup) {
+		DEBUG(DEBUG_ERR, (__location__ " db %s become healthy  - force recovery for startup\n",
+				  ctdb_db->db_name));
+		ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+	}
+
+	return 0;
+}
+
+int32_t ctdb_control_db_get_health(struct ctdb_context *ctdb,
+				   TDB_DATA indata,
+				   TDB_DATA *outdata)
+{
+	uint32_t db_id = *(uint32_t *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
+	int ret;
+
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%x\n", db_id));
+		return -1;
+	}
+
+	ret = ctdb_load_persistent_health(ctdb, ctdb_db);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__
+				 " ctdb_load_persistent_health(%s) failed\n",
+				 ctdb_db->db_name));
+		return -1;
+	}
+
+	*outdata = tdb_null;
+	if (ctdb_db->unhealthy_reason) {
+		outdata->dptr = (uint8_t *)ctdb_db->unhealthy_reason;
+		outdata->dsize = strlen(ctdb_db->unhealthy_reason)+1;
+	}
+
+	return 0;
+}
+
+
+int ctdb_set_db_readonly(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db)
+{
+	char *ropath;
+
+	if (ctdb_db->readonly) {
+		return 0;
+	}
+
+	if (ctdb_db->persistent) {
+		DEBUG(DEBUG_ERR,("Trying to set persistent database with readonly property\n"));
+		return -1;
+	}
+
+	ropath = talloc_asprintf(ctdb_db, "%s.RO", ctdb_db->db_path);
+	if (ropath == NULL) {
+		DEBUG(DEBUG_CRIT,("Failed to asprintf the tracking database\n"));
+		return -1;
+	}
+	ctdb_db->rottdb = tdb_open(ropath, 
+			      ctdb->tunable.database_hash_size, 
+			      TDB_NOLOCK|TDB_CLEAR_IF_FIRST|TDB_NOSYNC,
+			      O_CREAT|O_RDWR, 0);
+	if (ctdb_db->rottdb == NULL) {
+		DEBUG(DEBUG_CRIT,("Failed to open/create the tracking database '%s'\n", ropath));
+		talloc_free(ropath);
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE,("OPENED tracking database : '%s'\n", ropath));
+
+	ctdb_db->readonly = true;
+	talloc_free(ropath);
+	return 0;
+}
+
+/*
+  attach to a database, handling both persistent and non-persistent databases
+  return 0 on success, -1 on failure
+ */
+static int ctdb_local_attach(struct ctdb_context *ctdb, const char *db_name,
+			     bool persistent, const char *unhealthy_reason,
+			     bool jenkinshash)
+{
+	struct ctdb_db_context *ctdb_db, *tmp_db;
+	int ret;
+	struct TDB_DATA key;
+	unsigned tdb_flags;
+	int mode = 0600;
+	int remaining_tries = 0;
+
+	ctdb_db = talloc_zero(ctdb, struct ctdb_db_context);
+	CTDB_NO_MEMORY(ctdb, ctdb_db);
+
+	ctdb_db->priority = 1;
+	ctdb_db->ctdb = ctdb;
+	ctdb_db->db_name = talloc_strdup(ctdb_db, db_name);
+	CTDB_NO_MEMORY(ctdb, ctdb_db->db_name);
+
+	key.dsize = strlen(db_name)+1;
+	key.dptr  = discard_const(db_name);
+	ctdb_db->db_id = ctdb_hash(&key);
+	ctdb_db->persistent = persistent;
+
+	if (!ctdb_db->persistent) {
+		ctdb_db->delete_queue = trbt_create(ctdb_db, 0);
+		if (ctdb_db->delete_queue == NULL) {
+			CTDB_NO_MEMORY(ctdb, ctdb_db->delete_queue);
+		}
+
+		ctdb_db->ctdb_ltdb_store_fn = ctdb_ltdb_store_server;
+	}
+
+	/* check for hash collisions */
+	for (tmp_db=ctdb->db_list;tmp_db;tmp_db=tmp_db->next) {
+		if (tmp_db->db_id == ctdb_db->db_id) {
+			DEBUG(DEBUG_CRIT,("db_id 0x%x hash collision. name1='%s' name2='%s'\n",
+				 tmp_db->db_id, db_name, tmp_db->db_name));
+			talloc_free(ctdb_db);
+			return -1;
+		}
+	}
+
+	if (persistent) {
+		if (unhealthy_reason) {
+			ret = ctdb_update_persistent_health(ctdb, ctdb_db,
+							    unhealthy_reason, 0);
+			if (ret != 0) {
+				DEBUG(DEBUG_ALERT,(__location__ " ctdb_update_persistent_health('%s','%s') failed: %d\n",
+						   ctdb_db->db_name, unhealthy_reason, ret));
+				talloc_free(ctdb_db);
+				return -1;
+			}
+		}
+
+		if (ctdb->max_persistent_check_errors > 0) {
+			remaining_tries = 1;
+		}
+		if (ctdb->done_startup) {
+			remaining_tries = 0;
+		}
+
+		ret = ctdb_load_persistent_health(ctdb, ctdb_db);
+		if (ret != 0) {
+			DEBUG(DEBUG_ALERT,(__location__ " ctdb_load_persistent_health('%s') failed: %d\n",
+				   ctdb_db->db_name, ret));
+			talloc_free(ctdb_db);
+			return -1;
+		}
+	}
+
+	if (ctdb_db->unhealthy_reason && remaining_tries == 0) {
+		DEBUG(DEBUG_ALERT,(__location__ "ERROR: tdb %s is marked as unhealthy: %s\n",
+				   ctdb_db->db_name, ctdb_db->unhealthy_reason));
+		talloc_free(ctdb_db);
+		return -1;
+	}
+
+	if (ctdb_db->unhealthy_reason) {
+		/* this is just a warning, but we want that in the log file! */
+		DEBUG(DEBUG_ALERT,(__location__ "Warning: tdb %s is marked as unhealthy: %s\n",
+				   ctdb_db->db_name, ctdb_db->unhealthy_reason));
+	}
+
+	/* open the database */
+	ctdb_db->db_path = talloc_asprintf(ctdb_db, "%s/%s.%u", 
+					   persistent?ctdb->db_directory_persistent:ctdb->db_directory, 
+					   db_name, ctdb->pnn);
+
+	tdb_flags = persistent? TDB_DEFAULT : TDB_CLEAR_IF_FIRST | TDB_NOSYNC;
+	if (ctdb->valgrinding) {
+		tdb_flags |= TDB_NOMMAP;
+	}
+	tdb_flags |= TDB_DISALLOW_NESTING;
+	if (jenkinshash) {
+		tdb_flags |= TDB_INCOMPATIBLE_HASH;
+	}
+
+again:
+	ctdb_db->ltdb = tdb_wrap_open(ctdb, ctdb_db->db_path, 
+				      ctdb->tunable.database_hash_size, 
+				      tdb_flags, 
+				      O_CREAT|O_RDWR, mode);
+	if (ctdb_db->ltdb == NULL) {
+		struct stat st;
+		int saved_errno = errno;
+
+		if (!persistent) {
+			DEBUG(DEBUG_CRIT,("Failed to open tdb '%s': %d - %s\n",
+					  ctdb_db->db_path,
+					  saved_errno,
+					  strerror(saved_errno)));
+			talloc_free(ctdb_db);
+			return -1;
+		}
+
+		if (remaining_tries == 0) {
+			DEBUG(DEBUG_CRIT,(__location__
+					  "Failed to open persistent tdb '%s': %d - %s\n",
+					  ctdb_db->db_path,
+					  saved_errno,
+					  strerror(saved_errno)));
+			talloc_free(ctdb_db);
+			return -1;
+		}
+
+		ret = stat(ctdb_db->db_path, &st);
+		if (ret != 0) {
+			DEBUG(DEBUG_CRIT,(__location__
+					  "Failed to open persistent tdb '%s': %d - %s\n",
+					  ctdb_db->db_path,
+					  saved_errno,
+					  strerror(saved_errno)));
+			talloc_free(ctdb_db);
+			return -1;
+		}
+
+		ret = ctdb_backup_corrupted_tdb(ctdb, ctdb_db);
+		if (ret != 0) {
+			DEBUG(DEBUG_CRIT,(__location__
+					  "Failed to open persistent tdb '%s': %d - %s\n",
+					  ctdb_db->db_path,
+					  saved_errno,
+					  strerror(saved_errno)));
+			talloc_free(ctdb_db);
+			return -1;
+		}
+
+		remaining_tries--;
+		mode = st.st_mode;
+		goto again;
+	}
+
+	if (!persistent) {
+		ctdb_check_db_empty(ctdb_db);
+	} else {
+		ret = tdb_check(ctdb_db->ltdb->tdb, NULL, NULL);
+		if (ret != 0) {
+			int fd;
+			struct stat st;
+
+			DEBUG(DEBUG_CRIT,("tdb_check(%s) failed: %d - %s\n",
+					  ctdb_db->db_path, ret,
+					  tdb_errorstr(ctdb_db->ltdb->tdb)));
+			if (remaining_tries == 0) {
+				talloc_free(ctdb_db);
+				return -1;
+			}
+
+			fd = tdb_fd(ctdb_db->ltdb->tdb);
+			ret = fstat(fd, &st);
+			if (ret != 0) {
+				DEBUG(DEBUG_CRIT,(__location__
+						  "Failed to fstat() persistent tdb '%s': %d - %s\n",
+						  ctdb_db->db_path,
+						  errno,
+						  strerror(errno)));
+				talloc_free(ctdb_db);
+				return -1;
+			}
+
+			/* close the TDB */
+			talloc_free(ctdb_db->ltdb);
+			ctdb_db->ltdb = NULL;
+
+			ret = ctdb_backup_corrupted_tdb(ctdb, ctdb_db);
+			if (ret != 0) {
+				DEBUG(DEBUG_CRIT,("Failed to backup corrupted tdb '%s'\n",
+						  ctdb_db->db_path));
+				talloc_free(ctdb_db);
+				return -1;
+			}
+
+			remaining_tries--;
+			mode = st.st_mode;
+			goto again;
+		}
+	}
+
+	DLIST_ADD(ctdb->db_list, ctdb_db);
+
+	/* setting this can help some high churn databases */
+	tdb_set_max_dead(ctdb_db->ltdb->tdb, ctdb->tunable.database_max_dead);
+
+	/* 
+	   all databases support the "null" function. we need this in
+	   order to do forced migration of records
+	*/
+	ret = ctdb_daemon_set_call(ctdb, ctdb_db->db_id, ctdb_null_func, CTDB_NULL_FUNC);
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT,("Failed to setup null function for '%s'\n", ctdb_db->db_name));
+		talloc_free(ctdb_db);
+		return -1;
+	}
+
+	/* 
+	   all databases support the "fetch" function. we need this
+	   for efficient Samba3 ctdb fetch
+	*/
+	ret = ctdb_daemon_set_call(ctdb, ctdb_db->db_id, ctdb_fetch_func, CTDB_FETCH_FUNC);
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT,("Failed to setup fetch function for '%s'\n", ctdb_db->db_name));
+		talloc_free(ctdb_db);
+		return -1;
+	}
+
+	/* 
+	   all databases support the "fetch_with_header" function. we need this
+	   for efficient readonly record fetches
+	*/
+	ret = ctdb_daemon_set_call(ctdb, ctdb_db->db_id, ctdb_fetch_with_header_func, CTDB_FETCH_WITH_HEADER_FUNC);
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT,("Failed to setup fetch function for '%s'\n", ctdb_db->db_name));
+		talloc_free(ctdb_db);
+		return -1;
+	}
+
+	ret = ctdb_vacuum_init(ctdb_db);
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT,("Failed to setup vacuuming for "
+				  "database '%s'\n", ctdb_db->db_name));
+		talloc_free(ctdb_db);
+		return -1;
+	}
+
+
+	DEBUG(DEBUG_INFO,("Attached to database '%s'\n", ctdb_db->db_path));
+	
+	/* success */
+	return 0;
+}
+
+
+struct ctdb_deferred_attach_context {
+	struct ctdb_deferred_attach_context *next, *prev;
+	struct ctdb_context *ctdb;
+	struct ctdb_req_control *c;
+};
+
+
+static int ctdb_deferred_attach_destructor(struct ctdb_deferred_attach_context *da_ctx)
+{
+	DLIST_REMOVE(da_ctx->ctdb->deferred_attach, da_ctx);
+
+	return 0;
+}
+
+static void ctdb_deferred_attach_timeout(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data)
+{
+	struct ctdb_deferred_attach_context *da_ctx = talloc_get_type(private_data, struct ctdb_deferred_attach_context);
+	struct ctdb_context *ctdb = da_ctx->ctdb;
+
+	ctdb_request_control_reply(ctdb, da_ctx->c, NULL, -1, NULL);
+	talloc_free(da_ctx);
+}
+
+static void ctdb_deferred_attach_callback(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data)
+{
+	struct ctdb_deferred_attach_context *da_ctx = talloc_get_type(private_data, struct ctdb_deferred_attach_context);
+	struct ctdb_context *ctdb = da_ctx->ctdb;
+
+	/* This talloc-steals the packet ->c */
+	ctdb_input_pkt(ctdb, (struct ctdb_req_header *)da_ctx->c);
+	talloc_free(da_ctx);
+}
+
+int ctdb_process_deferred_attach(struct ctdb_context *ctdb)
+{
+	struct ctdb_deferred_attach_context *da_ctx;
+
+	/* call it from the main event loop as soon as the current event 
+	   finishes.
+	 */
+	while ((da_ctx = ctdb->deferred_attach) != NULL) {
+		DLIST_REMOVE(ctdb->deferred_attach, da_ctx);
+		event_add_timed(ctdb->ev, da_ctx, timeval_current_ofs(1,0), ctdb_deferred_attach_callback, da_ctx);
+	}
+
+	return 0;
+}
+
+/*
+  a client has asked to attach a new database
+ */
+int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata,
+			       TDB_DATA *outdata, uint64_t tdb_flags, 
+			       bool persistent, uint32_t client_id,
+			       struct ctdb_req_control *c,
+			       bool *async_reply)
+{
+	const char *db_name = (const char *)indata.dptr;
+	struct ctdb_db_context *db;
+	struct ctdb_node *node = ctdb->nodes[ctdb->pnn];
+	struct ctdb_client *client = NULL;
+
+	if (ctdb->tunable.allow_client_db_attach == 0) {
+		DEBUG(DEBUG_ERR, ("DB Attach to database %s denied by tunable "
+				  "AllowClientDBAccess == 0\n", db_name));
+		return -1;
+	}
+
+	/* dont allow any local clients to attach while we are in recovery mode
+	 * except for the recovery daemon.
+	 * allow all attach from the network since these are always from remote
+	 * recovery daemons.
+	 */
+	if (client_id != 0) {
+		client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+	}
+	if (client != NULL) {
+		/* If the node is inactive it is not part of the cluster
+		   and we should not allow clients to attach to any
+		   databases
+		*/
+		if (node->flags & NODE_FLAGS_INACTIVE) {
+			DEBUG(DEBUG_ERR,("DB Attach to database %s refused since node is inactive (disconnected or banned)\n", db_name));
+			return -1;
+		}
+
+		if (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE
+		 && client->pid != ctdb->recoverd_pid
+		 && !ctdb->done_startup) {
+			struct ctdb_deferred_attach_context *da_ctx = talloc(client, struct ctdb_deferred_attach_context);
+
+			if (da_ctx == NULL) {
+				DEBUG(DEBUG_ERR,("DB Attach to database %s deferral for client with pid:%d failed due to OOM.\n", db_name, client->pid));
+				return -1;
+			}
+
+			da_ctx->ctdb = ctdb;
+			da_ctx->c = talloc_steal(da_ctx, c);
+			talloc_set_destructor(da_ctx, ctdb_deferred_attach_destructor);
+			DLIST_ADD(ctdb->deferred_attach, da_ctx);
+
+			event_add_timed(ctdb->ev, da_ctx, timeval_current_ofs(ctdb->tunable.deferred_attach_timeout, 0), ctdb_deferred_attach_timeout, da_ctx);
+
+			DEBUG(DEBUG_ERR,("DB Attach to database %s deferred for client with pid:%d since node is in recovery mode.\n", db_name, client->pid));
+			*async_reply = true;
+			return 0;
+		}
+	}
+
+	/* the client can optionally pass additional tdb flags, but we
+	   only allow a subset of those on the database in ctdb. Note
+	   that tdb_flags is passed in via the (otherwise unused)
+	   srvid to the attach control */
+	tdb_flags &= (TDB_NOSYNC|TDB_INCOMPATIBLE_HASH);
+
+	/* see if we already have this name */
+	db = ctdb_db_handle(ctdb, db_name);
+	if (db) {
+		outdata->dptr  = (uint8_t *)&db->db_id;
+		outdata->dsize = sizeof(db->db_id);
+		tdb_add_flags(db->ltdb->tdb, tdb_flags);
+		return 0;
+	}
+
+	if (ctdb_local_attach(ctdb, db_name, persistent, NULL, (tdb_flags&TDB_INCOMPATIBLE_HASH)?true:false) != 0) {
+		return -1;
+	}
+
+	db = ctdb_db_handle(ctdb, db_name);
+	if (!db) {
+		DEBUG(DEBUG_ERR,("Failed to find db handle for name '%s'\n", db_name));
+		return -1;
+	}
+
+	/* remember the flags the client has specified */
+	tdb_add_flags(db->ltdb->tdb, tdb_flags);
+
+	outdata->dptr  = (uint8_t *)&db->db_id;
+	outdata->dsize = sizeof(db->db_id);
+
+	/* Try to ensure it's locked in mem */
+	ctdb_lockdown_memory(ctdb);
+
+	/* tell all the other nodes about this database */
+	ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL, tdb_flags,
+				 persistent?CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+						CTDB_CONTROL_DB_ATTACH,
+				 0, CTDB_CTRL_FLAG_NOREPLY,
+				 indata, NULL, NULL);
+
+	/* success */
+	return 0;
+}
+
+
+/*
+  attach to all existing persistent databases
+ */
+static int ctdb_attach_persistent(struct ctdb_context *ctdb,
+				  const char *unhealthy_reason)
+{
+	DIR *d;
+	struct dirent *de;
+
+	/* open the persistent db directory and scan it for files */
+	d = opendir(ctdb->db_directory_persistent);
+	if (d == NULL) {
+		return 0;
+	}
+
+	while ((de=readdir(d))) {
+		char *p, *s, *q;
+		size_t len = strlen(de->d_name);
+		uint32_t node;
+		int invalid_name = 0;
+		
+		s = talloc_strdup(ctdb, de->d_name);
+		CTDB_NO_MEMORY(ctdb, s);
+
+		/* only accept names ending in .tdb */
+		p = strstr(s, ".tdb.");
+		if (len < 7 || p == NULL) {
+			talloc_free(s);
+			continue;
+		}
+
+		/* only accept names ending with .tdb. and any number of digits */
+		q = p+5;
+		while (*q != 0 && invalid_name == 0) {
+			if (!isdigit(*q++)) {
+				invalid_name = 1;
+			}
+		}
+		if (invalid_name == 1 || sscanf(p+5, "%u", &node) != 1 || node != ctdb->pnn) {
+			DEBUG(DEBUG_ERR,("Ignoring persistent database '%s'\n", de->d_name));
+			talloc_free(s);
+			continue;
+		}
+		p[4] = 0;
+
+		if (ctdb_local_attach(ctdb, s, true, unhealthy_reason, 0) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to attach to persistent database '%s'\n", de->d_name));
+			closedir(d);
+			talloc_free(s);
+			return -1;
+		}
+
+		DEBUG(DEBUG_INFO,("Attached to persistent database %s\n", s));
+
+		talloc_free(s);
+	}
+	closedir(d);
+	return 0;
+}
+
+int ctdb_attach_databases(struct ctdb_context *ctdb)
+{
+	int ret;
+	char *persistent_health_path = NULL;
+	char *unhealthy_reason = NULL;
+	bool first_try = true;
+
+	if (ctdb->db_directory == NULL) {
+		ctdb->db_directory = VARDIR "/ctdb";
+	}
+	if (ctdb->db_directory_persistent == NULL) {
+		ctdb->db_directory_persistent = VARDIR "/ctdb/persistent";
+	}
+	if (ctdb->db_directory_state == NULL) {
+		ctdb->db_directory_state = VARDIR "/ctdb/state";
+	}
+
+	/* make sure the db directory exists */
+	ret = mkdir(ctdb->db_directory, 0700);
+	if (ret == -1 && errno != EEXIST) {
+		DEBUG(DEBUG_CRIT,(__location__ " Unable to create ctdb directory '%s'\n",
+			 ctdb->db_directory));
+		return -1;
+	}
+
+	/* make sure the persistent db directory exists */
+	ret = mkdir(ctdb->db_directory_persistent, 0700);
+	if (ret == -1 && errno != EEXIST) {
+		DEBUG(DEBUG_CRIT,(__location__ " Unable to create ctdb persistent directory '%s'\n",
+			 ctdb->db_directory_persistent));
+		return -1;
+	}
+
+	/* make sure the internal state db directory exists */
+	ret = mkdir(ctdb->db_directory_state, 0700);
+	if (ret == -1 && errno != EEXIST) {
+		DEBUG(DEBUG_CRIT,(__location__ " Unable to create ctdb state directory '%s'\n",
+			 ctdb->db_directory_state));
+		return -1;
+	}
+
+	persistent_health_path = talloc_asprintf(ctdb, "%s/%s.%u",
+						 ctdb->db_directory_state,
+						 PERSISTENT_HEALTH_TDB,
+						 ctdb->pnn);
+	if (persistent_health_path == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " talloc_asprintf() failed\n"));
+		return -1;
+	}
+
+again:
+
+	ctdb->db_persistent_health = tdb_wrap_open(ctdb, persistent_health_path,
+						   0, TDB_DISALLOW_NESTING,
+						   O_CREAT | O_RDWR, 0600);
+	if (ctdb->db_persistent_health == NULL) {
+		struct tdb_wrap *tdb;
+
+		if (!first_try) {
+			DEBUG(DEBUG_CRIT,("Failed to open tdb '%s': %d - %s\n",
+					  persistent_health_path,
+					  errno,
+					  strerror(errno)));
+			talloc_free(persistent_health_path);
+			talloc_free(unhealthy_reason);
+			return -1;
+		}
+		first_try = false;
+
+		unhealthy_reason = talloc_asprintf(ctdb, "WARNING - '%s' %s - %s",
+						   persistent_health_path,
+						   "was cleared after a failure",
+						   "manual verification needed");
+		if (unhealthy_reason == NULL) {
+			DEBUG(DEBUG_CRIT,(__location__ " talloc_asprintf() failed\n"));
+			talloc_free(persistent_health_path);
+			return -1;
+		}
+
+		DEBUG(DEBUG_CRIT,("Failed to open tdb '%s' - retrying after CLEAR_IF_FIRST\n",
+				  persistent_health_path));
+		tdb = tdb_wrap_open(ctdb, persistent_health_path,
+				    0, TDB_CLEAR_IF_FIRST | TDB_DISALLOW_NESTING,
+				    O_CREAT | O_RDWR, 0600);
+		if (tdb) {
+			DEBUG(DEBUG_CRIT,("Failed to open tdb '%s' - with CLEAR_IF_FIRST: %d - %s\n",
+					  persistent_health_path,
+					  errno,
+					  strerror(errno)));
+			talloc_free(persistent_health_path);
+			talloc_free(unhealthy_reason);
+			return -1;
+		}
+
+		talloc_free(tdb);
+		goto again;
+	}
+	ret = tdb_check(ctdb->db_persistent_health->tdb, NULL, NULL);
+	if (ret != 0) {
+		struct tdb_wrap *tdb;
+
+		talloc_free(ctdb->db_persistent_health);
+		ctdb->db_persistent_health = NULL;
+
+		if (!first_try) {
+			DEBUG(DEBUG_CRIT,("tdb_check('%s') failed\n",
+					  persistent_health_path));
+			talloc_free(persistent_health_path);
+			talloc_free(unhealthy_reason);
+			return -1;
+		}
+		first_try = false;
+
+		unhealthy_reason = talloc_asprintf(ctdb, "WARNING - '%s' %s - %s",
+						   persistent_health_path,
+						   "was cleared after a failure",
+						   "manual verification needed");
+		if (unhealthy_reason == NULL) {
+			DEBUG(DEBUG_CRIT,(__location__ " talloc_asprintf() failed\n"));
+			talloc_free(persistent_health_path);
+			return -1;
+		}
+
+		DEBUG(DEBUG_CRIT,("tdb_check('%s') failed - retrying after CLEAR_IF_FIRST\n",
+				  persistent_health_path));
+		tdb = tdb_wrap_open(ctdb, persistent_health_path,
+				    0, TDB_CLEAR_IF_FIRST | TDB_DISALLOW_NESTING,
+				    O_CREAT | O_RDWR, 0600);
+		if (tdb) {
+			DEBUG(DEBUG_CRIT,("Failed to open tdb '%s' - with CLEAR_IF_FIRST: %d - %s\n",
+					  persistent_health_path,
+					  errno,
+					  strerror(errno)));
+			talloc_free(persistent_health_path);
+			talloc_free(unhealthy_reason);
+			return -1;
+		}
+
+		talloc_free(tdb);
+		goto again;
+	}
+	talloc_free(persistent_health_path);
+
+	ret = ctdb_attach_persistent(ctdb, unhealthy_reason);
+	talloc_free(unhealthy_reason);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  called when a broadcast seqnum update comes in
+ */
+int32_t ctdb_ltdb_update_seqnum(struct ctdb_context *ctdb, uint32_t db_id, uint32_t srcnode)
+{
+	struct ctdb_db_context *ctdb_db;
+	if (srcnode == ctdb->pnn) {
+		/* don't update ourselves! */
+		return 0;
+	}
+
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_ltdb_update_seqnum\n", db_id));
+		return -1;
+	}
+
+	if (ctdb_db->unhealthy_reason) {
+		DEBUG(DEBUG_ERR,("db(%s) unhealty in ctdb_ltdb_update_seqnum: %s\n",
+				 ctdb_db->db_name, ctdb_db->unhealthy_reason));
+		return -1;
+	}
+
+	tdb_increment_seqnum_nonblock(ctdb_db->ltdb->tdb);
+	ctdb_db->seqnum = tdb_get_seqnum(ctdb_db->ltdb->tdb);
+	return 0;
+}
+
+/*
+  timer to check for seqnum changes in a ltdb and propogate them
+ */
+static void ctdb_ltdb_seqnum_check(struct event_context *ev, struct timed_event *te, 
+				   struct timeval t, void *p)
+{
+	struct ctdb_db_context *ctdb_db = talloc_get_type(p, struct ctdb_db_context);
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	uint32_t new_seqnum = tdb_get_seqnum(ctdb_db->ltdb->tdb);
+	if (new_seqnum != ctdb_db->seqnum) {
+		/* something has changed - propogate it */
+		TDB_DATA data;
+		data.dptr = (uint8_t *)&ctdb_db->db_id;
+		data.dsize = sizeof(uint32_t);
+		ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_VNNMAP, 0,
+					 CTDB_CONTROL_UPDATE_SEQNUM, 0, CTDB_CTRL_FLAG_NOREPLY,
+					 data, NULL, NULL);		
+	}
+	ctdb_db->seqnum = new_seqnum;
+
+	/* setup a new timer */
+	ctdb_db->seqnum_update =
+		event_add_timed(ctdb->ev, ctdb_db, 
+				timeval_current_ofs(ctdb->tunable.seqnum_interval/1000, (ctdb->tunable.seqnum_interval%1000)*1000),
+				ctdb_ltdb_seqnum_check, ctdb_db);
+}
+
+/*
+  enable seqnum handling on this db
+ */
+int32_t ctdb_ltdb_enable_seqnum(struct ctdb_context *ctdb, uint32_t db_id)
+{
+	struct ctdb_db_context *ctdb_db;
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_ltdb_enable_seqnum\n", db_id));
+		return -1;
+	}
+
+	if (ctdb_db->seqnum_update == NULL) {
+		ctdb_db->seqnum_update =
+			event_add_timed(ctdb->ev, ctdb_db, 
+					timeval_current_ofs(ctdb->tunable.seqnum_interval/1000, (ctdb->tunable.seqnum_interval%1000)*1000),
+					ctdb_ltdb_seqnum_check, ctdb_db);
+	}
+
+	tdb_enable_seqnum(ctdb_db->ltdb->tdb);
+	ctdb_db->seqnum = tdb_get_seqnum(ctdb_db->ltdb->tdb);
+	return 0;
+}
+
+int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_db_priority *db_prio = (struct ctdb_db_priority *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = find_ctdb_db(ctdb, db_prio->db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_set_db_priority\n", db_prio->db_id));
+		return 0;
+	}
+
+	if ((db_prio->priority<1) || (db_prio->priority>NUM_DB_PRIORITIES)) {
+		DEBUG(DEBUG_ERR,("Trying to set invalid priority : %u\n", db_prio->priority));
+		return 0;
+	}
+
+	ctdb_db->priority = db_prio->priority;
+	DEBUG(DEBUG_INFO,("Setting DB priority to %u for db 0x%08x\n", db_prio->priority, db_prio->db_id));
+
+	return 0;
+}
+

Added: branches/ctdb/squeeze-backports/server/ctdb_monitor.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_monitor.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_monitor.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,504 @@
+/* 
+   monitoring links to all other nodes to detect dead nodes
+
+
+   Copyright (C) Ronnie Sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+
+struct ctdb_monitor_state {
+	uint32_t monitoring_mode;
+	TALLOC_CTX *monitor_context;
+	uint32_t next_interval;
+};
+
+static void ctdb_check_health(struct event_context *ev, struct timed_event *te, 
+			      struct timeval t, void *private_data);
+
+/*
+  setup the notification script
+*/
+int ctdb_set_notification_script(struct ctdb_context *ctdb, const char *script)
+{
+	ctdb->notification_script = talloc_strdup(ctdb, script);
+	CTDB_NO_MEMORY(ctdb, ctdb->notification_script);
+	return 0;
+}
+
+static int ctdb_run_notification_script_child(struct ctdb_context *ctdb, const char *event)
+{
+	struct stat st;
+	int ret;
+	char *cmd;
+
+	if (stat(ctdb->notification_script, &st) != 0) {
+		DEBUG(DEBUG_ERR,("Could not stat notification script %s. Can not send notifications.\n", ctdb->notification_script));
+		return -1;
+	}
+	if (!(st.st_mode & S_IXUSR)) {
+		DEBUG(DEBUG_ERR,("Notification script %s is not executable.\n", ctdb->notification_script));
+		return -1;
+	}
+
+	cmd = talloc_asprintf(ctdb, "%s %s\n", ctdb->notification_script, event);
+	CTDB_NO_MEMORY(ctdb, cmd);
+
+	ret = system(cmd);
+	/* if the system() call was successful, translate ret into the
+	   return code from the command
+	*/
+	if (ret != -1) {
+		ret = WEXITSTATUS(ret);
+	}
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Notification script \"%s\" failed with error %d\n", cmd, ret));
+	}
+
+	return ret;
+}
+
+void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event)
+{
+	pid_t child;
+
+	if (ctdb->notification_script == NULL) {
+		return;
+	}
+
+	child = ctdb_fork(ctdb);
+	if (child == (pid_t)-1) {
+		DEBUG(DEBUG_ERR,("Failed to fork() a notification child process\n"));
+		return;
+	}
+	if (child == 0) {
+		int ret;
+
+		debug_extra = talloc_asprintf(NULL, "notification-%s:", event);
+		ret = ctdb_run_notification_script_child(ctdb, event);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Notification script failed\n"));
+		}
+		_exit(0);
+	}
+
+	return;
+}
+
+/*
+  called when a health monitoring event script finishes
+ */
+static void ctdb_health_callback(struct ctdb_context *ctdb, int status, void *p)
+{
+	struct ctdb_node *node = ctdb->nodes[ctdb->pnn];
+	TDB_DATA data;
+	struct ctdb_node_flag_change c;
+	uint32_t next_interval;
+	int ret;
+	TDB_DATA rddata;
+	struct takeover_run_reply rd;
+	const char *state_str = NULL;
+
+	c.pnn = ctdb->pnn;
+	c.old_flags = node->flags;
+
+	rd.pnn   = ctdb->pnn;
+	rd.srvid = CTDB_SRVID_TAKEOVER_RUN_RESPONSE;
+
+	rddata.dptr = (uint8_t *)&rd;
+	rddata.dsize = sizeof(rd);
+
+	if (status == -ETIME) {
+		ctdb->event_script_timeouts++;
+
+		if (ctdb->event_script_timeouts >= ctdb->tunable.script_timeout_count) {
+			DEBUG(DEBUG_ERR, ("Maximum timeout count %u reached for eventscript. Making node unhealthy\n", ctdb->tunable.script_timeout_count));
+		} else {
+			/* We pretend this is OK. */
+			goto after_change_status;
+		}
+	}
+
+	if (status != 0 && !(node->flags & NODE_FLAGS_UNHEALTHY)) {
+		DEBUG(DEBUG_NOTICE,("monitor event failed - disabling node\n"));
+		node->flags |= NODE_FLAGS_UNHEALTHY;
+		ctdb->monitor->next_interval = 5;
+
+		ctdb_run_notification_script(ctdb, "unhealthy");
+	} else if (status == 0 && (node->flags & NODE_FLAGS_UNHEALTHY)) {
+		DEBUG(DEBUG_NOTICE,("monitor event OK - node re-enabled\n"));
+		node->flags &= ~NODE_FLAGS_UNHEALTHY;
+		ctdb->monitor->next_interval = 5;
+
+		ctdb_run_notification_script(ctdb, "healthy");
+	}
+
+after_change_status:
+	next_interval = ctdb->monitor->next_interval;
+
+	ctdb->monitor->next_interval *= 2;
+	if (ctdb->monitor->next_interval > ctdb->tunable.monitor_interval) {
+		ctdb->monitor->next_interval = ctdb->tunable.monitor_interval;
+	}
+
+	event_add_timed(ctdb->ev, ctdb->monitor->monitor_context, 
+				timeval_current_ofs(next_interval, 0), 
+				ctdb_check_health, ctdb);
+
+	if (c.old_flags == node->flags) {
+		return;
+	}
+
+	c.new_flags = node->flags;
+
+	data.dptr = (uint8_t *)&c;
+	data.dsize = sizeof(c);
+
+	/* ask the recovery daemon to push these changes out to all nodes */
+	ctdb_daemon_send_message(ctdb, ctdb->pnn,
+				 CTDB_SRVID_PUSH_NODE_FLAGS, data);
+
+	if (c.new_flags & NODE_FLAGS_UNHEALTHY) {
+		state_str = "UNHEALTHY";
+	} else {
+		state_str = "HEALTHY";
+	}
+
+	/* ask the recmaster to reallocate all addresses */
+	DEBUG(DEBUG_ERR,("Node became %s. Ask recovery master %u to perform ip reallocation\n",
+			 state_str, ctdb->recovery_master));
+	ret = ctdb_daemon_send_message(ctdb, ctdb->recovery_master, CTDB_SRVID_TAKEOVER_RUN, rddata);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to send ip takeover run request message to %u\n", ctdb->recovery_master));
+	}
+}
+
+
+/*
+  called when the startup event script finishes
+ */
+static void ctdb_startup_callback(struct ctdb_context *ctdb, int status, void *p)
+{
+	if (status != 0) {
+		DEBUG(DEBUG_ERR,("startup event failed\n"));
+	} else if (status == 0) {
+		DEBUG(DEBUG_NOTICE,("startup event OK - enabling monitoring\n"));
+		ctdb->done_startup = true;
+		ctdb->monitor->next_interval = 2;
+		ctdb_run_notification_script(ctdb, "startup");
+	}
+
+	event_add_timed(ctdb->ev, ctdb->monitor->monitor_context, 
+			timeval_current_ofs(ctdb->monitor->next_interval, 0),
+			ctdb_check_health, ctdb);
+}
+
+
+/*
+  wait until we have finished initial recoveries before we start the
+  monitoring events
+ */
+static void ctdb_wait_until_recovered(struct event_context *ev, struct timed_event *te, 
+			      struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	int ret;
+	static int count = 0;
+
+	count++;
+
+	if (count < 60 || count%600 == 0) { 
+		DEBUG(DEBUG_NOTICE,("CTDB_WAIT_UNTIL_RECOVERED\n"));
+		if (ctdb->nodes[ctdb->pnn]->flags & NODE_FLAGS_STOPPED) {
+			DEBUG(DEBUG_NOTICE,("Node is STOPPED. Node will NOT recover.\n"));
+		}
+	}
+
+	if (ctdb->vnn_map->generation == INVALID_GENERATION) {
+		ctdb->db_persistent_startup_generation = INVALID_GENERATION;
+
+		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
+				     timeval_current_ofs(1, 0), 
+				     ctdb_wait_until_recovered, ctdb);
+		return;
+	}
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		ctdb->db_persistent_startup_generation = INVALID_GENERATION;
+
+		DEBUG(DEBUG_NOTICE,(__location__ " in recovery. Wait one more second\n"));
+		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
+				     timeval_current_ofs(1, 0), 
+				     ctdb_wait_until_recovered, ctdb);
+		return;
+	}
+
+
+	if (!fast_start && timeval_elapsed(&ctdb->last_recovery_finished) < (ctdb->tunable.rerecovery_timeout + 3)) {
+		ctdb->db_persistent_startup_generation = INVALID_GENERATION;
+
+		DEBUG(DEBUG_NOTICE,(__location__ " wait for pending recoveries to end. Wait one more second.\n"));
+
+		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
+				     timeval_current_ofs(1, 0), 
+				     ctdb_wait_until_recovered, ctdb);
+		return;
+	}
+
+	if (ctdb->vnn_map->generation == ctdb->db_persistent_startup_generation) {
+		DEBUG(DEBUG_INFO,(__location__ " skip ctdb_recheck_persistent_health() "
+				  "until the next recovery\n"));
+		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
+				     timeval_current_ofs(1, 0),
+				     ctdb_wait_until_recovered, ctdb);
+		return;
+	}
+
+	ctdb->db_persistent_startup_generation = ctdb->vnn_map->generation;
+	ret = ctdb_recheck_persistent_health(ctdb);
+	if (ret != 0) {
+		ctdb->db_persistent_check_errors++;
+		if (ctdb->db_persistent_check_errors < ctdb->max_persistent_check_errors) {
+			DEBUG(ctdb->db_persistent_check_errors==1?DEBUG_ERR:DEBUG_WARNING,
+			      (__location__ "ctdb_recheck_persistent_health() "
+			      "failed (%llu of %llu times) - retry later\n",
+			      (unsigned long long)ctdb->db_persistent_check_errors,
+			      (unsigned long long)ctdb->max_persistent_check_errors));
+			event_add_timed(ctdb->ev,
+					ctdb->monitor->monitor_context,
+					timeval_current_ofs(1, 0),
+					ctdb_wait_until_recovered, ctdb);
+			return;
+		}
+		DEBUG(DEBUG_ALERT,(__location__
+				  "ctdb_recheck_persistent_health() failed (%llu times) - prepare shutdown\n",
+				  (unsigned long long)ctdb->db_persistent_check_errors));
+		ctdb_stop_recoverd(ctdb);
+		ctdb_stop_keepalive(ctdb);
+		ctdb_stop_monitoring(ctdb);
+		ctdb_release_all_ips(ctdb);
+		if (ctdb->methods != NULL) {
+			ctdb->methods->shutdown(ctdb);
+		}
+		ctdb_event_script(ctdb, CTDB_EVENT_SHUTDOWN);
+		DEBUG(DEBUG_ALERT,("ctdb_recheck_persistent_health() failed - Stopping CTDB daemon\n"));
+		exit(11);
+	}
+	ctdb->db_persistent_check_errors = 0;
+
+	DEBUG(DEBUG_NOTICE,(__location__ " Recoveries finished. Running the \"startup\" event.\n"));
+	event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
+			     timeval_current(),
+			     ctdb_check_health, ctdb);
+}
+
+
+/*
+  see if the event scripts think we are healthy
+ */
+static void ctdb_check_health(struct event_context *ev, struct timed_event *te, 
+			      struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	int ret = 0;
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL ||
+	    (ctdb->monitor->monitoring_mode == CTDB_MONITORING_DISABLED && ctdb->done_startup)) {
+		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
+				timeval_current_ofs(ctdb->monitor->next_interval, 0), 
+				ctdb_check_health, ctdb);
+		return;
+	}
+	
+	if (!ctdb->done_startup) {
+		ret = ctdb_event_script_callback(ctdb, 
+						 ctdb->monitor->monitor_context, ctdb_startup_callback, 
+						 ctdb, false,
+						 CTDB_EVENT_STARTUP, "%s", "");
+	} else {
+		int i;
+		int skip_monitoring = 0;
+		
+		if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+			skip_monitoring = 1;
+			DEBUG(DEBUG_ERR,("Skip monitoring during recovery\n"));
+		}
+		for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+			if (ctdb->freeze_handles[i] != NULL) {
+				DEBUG(DEBUG_ERR,("Skip monitoring since databases are frozen\n"));
+				skip_monitoring = 1;
+				break;
+			}
+		}
+		if (skip_monitoring != 0) {
+			event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
+					timeval_current_ofs(ctdb->monitor->next_interval, 0), 
+					ctdb_check_health, ctdb);
+			return;
+		} else {
+			ret = ctdb_event_script_callback(ctdb, 
+					ctdb->monitor->monitor_context, ctdb_health_callback,
+					ctdb, false,
+					CTDB_EVENT_MONITOR, "%s", "");
+		}
+	}
+
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Unable to launch monitor event script\n"));
+		ctdb->monitor->next_interval = 5;
+		event_add_timed(ctdb->ev, ctdb->monitor->monitor_context, 
+			timeval_current_ofs(5, 0), 
+			ctdb_check_health, ctdb);
+	}
+}
+
+/* 
+  (Temporaily) Disabling monitoring will stop the monitor event scripts
+  from running   but node health checks will still occur
+*/
+void ctdb_disable_monitoring(struct ctdb_context *ctdb)
+{
+	ctdb->monitor->monitoring_mode = CTDB_MONITORING_DISABLED;
+	DEBUG(DEBUG_INFO,("Monitoring has been disabled\n"));
+}
+
+/* 
+   Re-enable running monitor events after they have been disabled
+ */
+void ctdb_enable_monitoring(struct ctdb_context *ctdb)
+{
+	ctdb->monitor->monitoring_mode  = CTDB_MONITORING_ACTIVE;
+	ctdb->monitor->next_interval = 5;
+	DEBUG(DEBUG_INFO,("Monitoring has been enabled\n"));
+}
+
+/* stop any monitoring 
+   this should only be done when shutting down the daemon
+*/
+void ctdb_stop_monitoring(struct ctdb_context *ctdb)
+{
+	talloc_free(ctdb->monitor->monitor_context);
+	ctdb->monitor->monitor_context = NULL;
+
+	ctdb->monitor->monitoring_mode  = CTDB_MONITORING_DISABLED;
+	ctdb->monitor->next_interval = 5;
+	DEBUG(DEBUG_NOTICE,("Monitoring has been stopped\n"));
+}
+
+/*
+  start watching for nodes that might be dead
+ */
+void ctdb_start_monitoring(struct ctdb_context *ctdb)
+{
+	if (ctdb->monitor != NULL) {
+		return;
+	}
+
+	ctdb->monitor = talloc(ctdb, struct ctdb_monitor_state);
+	CTDB_NO_MEMORY_FATAL(ctdb, ctdb->monitor);
+
+	ctdb->monitor->next_interval = 5;
+
+	ctdb->monitor->monitor_context = talloc_new(ctdb->monitor);
+	CTDB_NO_MEMORY_FATAL(ctdb, ctdb->monitor->monitor_context);
+
+	event_add_timed(ctdb->ev, ctdb->monitor->monitor_context,
+			     timeval_current_ofs(1, 0), 
+			     ctdb_wait_until_recovered, ctdb);
+
+	ctdb->monitor->monitoring_mode  = CTDB_MONITORING_ACTIVE;
+	DEBUG(DEBUG_NOTICE,("Monitoring has been started\n"));
+}
+
+
+/*
+  modify flags on a node
+ */
+int32_t ctdb_control_modflags(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_node_flag_change *c = (struct ctdb_node_flag_change *)indata.dptr;
+	struct ctdb_node *node;
+	uint32_t old_flags;
+
+	if (c->pnn >= ctdb->num_nodes) {
+		DEBUG(DEBUG_ERR,(__location__ " Node %d is invalid, num_nodes :%d\n", c->pnn, ctdb->num_nodes));
+		return -1;
+	}
+
+	node         = ctdb->nodes[c->pnn];
+	old_flags    = node->flags;
+	if (c->pnn != ctdb->pnn) {
+		c->old_flags  = node->flags;
+	}
+	node->flags   = c->new_flags & ~NODE_FLAGS_DISCONNECTED;
+	node->flags  |= (c->old_flags & NODE_FLAGS_DISCONNECTED);
+
+	/* we dont let other nodes modify our STOPPED status */
+	if (c->pnn == ctdb->pnn) {
+		node->flags &= ~NODE_FLAGS_STOPPED;
+		if (old_flags & NODE_FLAGS_STOPPED) {
+			node->flags |= NODE_FLAGS_STOPPED;
+		}
+	}
+
+	/* we dont let other nodes modify our BANNED status */
+	if (c->pnn == ctdb->pnn) {
+		node->flags &= ~NODE_FLAGS_BANNED;
+		if (old_flags & NODE_FLAGS_BANNED) {
+			node->flags |= NODE_FLAGS_BANNED;
+		}
+	}
+
+	if (node->flags == c->old_flags) {
+		DEBUG(DEBUG_INFO, ("Control modflags on node %u - Unchanged - flags 0x%x\n", c->pnn, node->flags));
+		return 0;
+	}
+
+	DEBUG(DEBUG_INFO, ("Control modflags on node %u - flags now 0x%x\n", c->pnn, node->flags));
+
+	if (node->flags == 0 && !ctdb->done_startup) {
+		DEBUG(DEBUG_ERR, (__location__ " Node %u became healthy - force recovery for startup\n",
+				  c->pnn));
+		ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+	}
+
+	/* tell the recovery daemon something has changed */
+	ctdb_daemon_send_message(ctdb, ctdb->pnn,
+				 CTDB_SRVID_SET_NODE_FLAGS, indata);
+
+	/* if we have become banned, we should go into recovery mode */
+	if ((node->flags & NODE_FLAGS_BANNED) && !(c->old_flags & NODE_FLAGS_BANNED) && (node->pnn == ctdb->pnn)) {
+		return ctdb_local_node_got_banned(ctdb);
+	}
+	
+	return 0;
+}
+
+/*
+  return the monitoring mode
+ */
+int32_t ctdb_monitoring_mode(struct ctdb_context *ctdb)
+{
+	if (ctdb->monitor == NULL) {
+		return CTDB_MONITORING_DISABLED;
+	}
+	return ctdb->monitor->monitoring_mode;
+}
+

Added: branches/ctdb/squeeze-backports/server/ctdb_persistent.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_persistent.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_persistent.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,997 @@
+/* 
+   persistent store logic
+
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Ronnie Sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "db_wrap.h"
+#include "lib/tdb/include/tdb.h"
+#include "../include/ctdb_private.h"
+
+struct ctdb_persistent_state {
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db; /* used by trans3_commit */
+	struct ctdb_client *client; /* used by trans3_commit */
+	struct ctdb_req_control *c;
+	const char *errormsg;
+	uint32_t num_pending;
+	int32_t status;
+	uint32_t num_failed, num_sent;
+};
+
+/*
+  1) all nodes fail, and all nodes reply
+  2) some nodes fail, all nodes reply
+  3) some nodes timeout
+  4) all nodes succeed
+ */
+
+/*
+  called when a node has acknowledged a ctdb_control_update_record call
+ */
+static void ctdb_persistent_callback(struct ctdb_context *ctdb,
+				     int32_t status, TDB_DATA data, 
+				     const char *errormsg,
+				     void *private_data)
+{
+	struct ctdb_persistent_state *state = talloc_get_type(private_data, 
+							      struct ctdb_persistent_state);
+	enum ctdb_trans2_commit_error etype;
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		DEBUG(DEBUG_INFO, ("ctdb_persistent_callback: ignoring reply "
+				   "during recovery\n"));
+		return;
+	}
+
+	if (status != 0) {
+		DEBUG(DEBUG_ERR,("ctdb_persistent_callback failed with status %d (%s)\n",
+			 status, errormsg?errormsg:"no error message given"));
+		state->status = status;
+		state->errormsg = errormsg;
+		state->num_failed++;
+
+		/*
+		 * If a node failed to complete the update_record control,
+		 * then either a recovery is already running or something
+		 * bad is going on. So trigger a recovery and let the
+		 * recovery finish the transaction, sending back the reply
+		 * for the trans3_commit control to the client.
+		 */
+		ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+		return;
+	}
+
+	state->num_pending--;
+
+	if (state->num_pending != 0) {
+		return;
+	}
+
+	if (state->num_failed == state->num_sent) {
+		etype = CTDB_TRANS2_COMMIT_ALLFAIL;
+	} else if (state->num_failed != 0) {
+		etype = CTDB_TRANS2_COMMIT_SOMEFAIL;
+	} else {
+		etype = CTDB_TRANS2_COMMIT_SUCCESS;
+	}
+
+	ctdb_request_control_reply(state->ctdb, state->c, NULL, etype, state->errormsg);
+	talloc_free(state);
+}
+
+/*
+  called if persistent store times out
+ */
+static void ctdb_persistent_store_timeout(struct event_context *ev, struct timed_event *te, 
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_persistent_state *state = talloc_get_type(private_data, struct ctdb_persistent_state);
+
+	if (state->ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		DEBUG(DEBUG_INFO, ("ctdb_persistent_store_timeout: ignoring "
+				   "timeout during recovery\n"));
+		return;
+	}
+
+	ctdb_request_control_reply(state->ctdb, state->c, NULL, CTDB_TRANS2_COMMIT_TIMEOUT, 
+				   "timeout in ctdb_persistent_state");
+
+	talloc_free(state);
+}
+
+/**
+ * Finish pending trans3 commit controls, i.e. send
+ * reply to the client. This is called by the end-recovery
+ * control to fix the situation when a recovery interrupts
+ * the usual porgress of a transaction.
+ */
+void ctdb_persistent_finish_trans3_commits(struct ctdb_context *ctdb)
+{
+	struct ctdb_db_context *ctdb_db;
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		DEBUG(DEBUG_INFO, ("ctdb_persistent_store_timeout: ignoring "
+				   "timeout during recovery\n"));
+		return;
+	}
+
+	for (ctdb_db = ctdb->db_list; ctdb_db; ctdb_db = ctdb_db->next) {
+		struct ctdb_persistent_state *state;
+
+		if (ctdb_db->persistent_state == NULL) {
+			continue;
+		}
+
+		state = ctdb_db->persistent_state;
+
+		ctdb_request_control_reply(ctdb, state->c, NULL,
+					   CTDB_TRANS2_COMMIT_SOMEFAIL,
+					   "trans3 commit ended by recovery");
+
+		/* The destructor sets ctdb_db->persistent_state to NULL. */
+		talloc_free(state);
+	}
+}
+
+/*
+  store a set of persistent records - called from a ctdb client when it has updated
+  some records in a persistent database. The client will have the record
+  locked for the duration of this call. The client is the dmaster when 
+  this call is made
+ */
+int32_t ctdb_control_trans2_commit(struct ctdb_context *ctdb, 
+				   struct ctdb_req_control *c, 
+				   TDB_DATA recdata, bool *async_reply)
+{
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+	struct ctdb_persistent_state *state;
+	int i;
+	struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = find_ctdb_db(ctdb, m->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_commit: "
+				 "Unknown database db_id[0x%08x]\n", m->db_id));
+		return -1;
+	}
+
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " can not match persistent_store to a client. Returning error\n"));
+		return -1;
+	}
+
+	if (ctdb_db->unhealthy_reason) {
+		DEBUG(DEBUG_ERR,("db(%s) unhealty in ctdb_control_trans2_commit: %s\n",
+				 ctdb_db->db_name, ctdb_db->unhealthy_reason));
+		return -1;
+	}
+
+	/* handling num_persistent_updates is a bit strange - 
+	   there are 3 cases
+	     1) very old clients, which never called CTDB_CONTROL_START_PERSISTENT_UPDATE
+	        They don't expect num_persistent_updates to be used at all
+
+	     2) less old clients, which uses CTDB_CONTROL_START_PERSISTENT_UPDATE, and expected
+	        this commit to then decrement it
+
+             3) new clients which use TRANS2 commit functions, and
+	        expect this function to increment the counter, and
+	        then have it decremented in ctdb_control_trans2_error
+	        or ctdb_control_trans2_finished
+	*/
+	switch (c->opcode) {
+	case CTDB_CONTROL_PERSISTENT_STORE:
+		if (ctdb_db->transaction_active) {
+			DEBUG(DEBUG_ERR, (__location__ " trans2_commit: a "
+					  "transaction is active on database "
+					  "db_id[0x%08x] - refusing persistent "
+					 " store for client id[0x%08x]\n",
+					  ctdb_db->db_id, client->client_id));
+			return -1;
+		}
+		if (client->num_persistent_updates > 0) {
+			client->num_persistent_updates--;
+		}
+		break;
+	case CTDB_CONTROL_TRANS2_COMMIT:
+		if (ctdb_db->transaction_active) {
+			DEBUG(DEBUG_ERR,(__location__ " trans2_commit: there is"
+					 " already a transaction commit "
+					 "active on db_id[0x%08x] - forbidding "
+					 "client_id[0x%08x] to commit\n",
+					 ctdb_db->db_id, client->client_id));
+			return -1;
+		}
+		if (client->db_id != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " ERROR: trans2_commit: "
+					 "client-db_id[0x%08x] != 0 "
+					 "(client_id[0x%08x])\n",
+					 client->db_id, client->client_id));
+			return -1;
+		}
+		client->num_persistent_updates++;
+		ctdb_db->transaction_active = true;
+		client->db_id = m->db_id;
+		DEBUG(DEBUG_DEBUG, (__location__ " client id[0x%08x] started to"
+				  " commit transaction on db id[0x%08x]\n",
+				  client->client_id, client->db_id));
+		break;
+	case CTDB_CONTROL_TRANS2_COMMIT_RETRY:
+		/* already updated from the first commit */
+		if (client->db_id != m->db_id) {
+			DEBUG(DEBUG_ERR,(__location__ " ERROR: trans2_commit "
+					 "retry: client-db_id[0x%08x] != "
+					 "db_id[0x%08x] (client_id[0x%08x])\n",
+					 client->db_id,
+					 m->db_id, client->client_id));
+			return -1;
+		}
+		DEBUG(DEBUG_DEBUG, (__location__ " client id[0x%08x] started "
+				    "transaction commit retry on "
+				    "db_id[0x%08x]\n",
+				    client->client_id, client->db_id));
+		break;
+	}
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		DEBUG(DEBUG_INFO,("rejecting ctdb_control_trans2_commit when recovery active\n"));
+		return -1;
+	}
+
+	state = talloc_zero(ctdb, struct ctdb_persistent_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->ctdb = ctdb;
+	state->c    = c;
+
+	for (i=0;i<ctdb->vnn_map->size;i++) {
+		struct ctdb_node *node = ctdb->nodes[ctdb->vnn_map->map[i]];
+		int ret;
+
+		/* only send to active nodes */
+		if (node->flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+
+		/* don't send to ourselves */
+		if (node->pnn == ctdb->pnn) {
+			continue;
+		}
+		
+		ret = ctdb_daemon_send_control(ctdb, node->pnn, 0, CTDB_CONTROL_UPDATE_RECORD,
+					       c->client_id, 0, recdata, 
+					       ctdb_persistent_callback, state);
+		if (ret == -1) {
+			DEBUG(DEBUG_ERR,("Unable to send CTDB_CONTROL_UPDATE_RECORD to pnn %u\n", node->pnn));
+			talloc_free(state);
+			return -1;
+		}
+
+		state->num_pending++;
+		state->num_sent++;
+	}
+
+	if (state->num_pending == 0) {
+		talloc_free(state);
+		return 0;
+	}
+	
+	/* we need to wait for the replies */
+	*async_reply = true;
+
+	/* need to keep the control structure around */
+	talloc_steal(state, c);
+
+	/* but we won't wait forever */
+	event_add_timed(ctdb->ev, state, 
+			timeval_current_ofs(ctdb->tunable.control_timeout, 0),
+			ctdb_persistent_store_timeout, state);
+
+	return 0;
+}
+
+static int ctdb_persistent_state_destructor(struct ctdb_persistent_state *state)
+{
+	if (state->client != NULL) {
+		state->client->db_id = 0;
+	}
+
+	if (state->ctdb_db != NULL) {
+		state->ctdb_db->persistent_state = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * Store a set of persistent records.
+ * This is used to roll out a transaction to all nodes.
+ */
+int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
+				   struct ctdb_req_control *c,
+				   TDB_DATA recdata, bool *async_reply)
+{
+	struct ctdb_client *client;
+	struct ctdb_persistent_state *state;
+	int i;
+	struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
+	struct ctdb_db_context *ctdb_db;
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		DEBUG(DEBUG_INFO,("rejecting ctdb_control_trans3_commit when recovery active\n"));
+		return -1;
+	}
+
+	client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " can not match persistent_store "
+				 "to a client. Returning error\n"));
+		return -1;
+	}
+
+	if (client->db_id != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ERROR: trans3_commit: "
+				 "client-db_id[0x%08x] != 0 "
+				 "(client_id[0x%08x]): trans3_commit active?\n",
+				 client->db_id, client->client_id));
+		return -1;
+	}
+
+	ctdb_db = find_ctdb_db(ctdb, m->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans3_commit: "
+				 "Unknown database db_id[0x%08x]\n", m->db_id));
+		return -1;
+	}
+
+	if (ctdb_db->persistent_state != NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Error: "
+				  "ctdb_control_trans3_commit "
+				  "called while a transaction commit is "
+				  "active. db_id[0x%08x]\n", m->db_id));
+		return -1;
+	}
+
+	ctdb_db->persistent_state = talloc_zero(ctdb_db,
+						struct ctdb_persistent_state);
+	CTDB_NO_MEMORY(ctdb, ctdb_db->persistent_state);
+
+	client->db_id = m->db_id;
+
+	state = ctdb_db->persistent_state;
+	state->ctdb = ctdb;
+	state->ctdb_db = ctdb_db;
+	state->c    = c;
+	state->client = client;
+
+	talloc_set_destructor(state, ctdb_persistent_state_destructor);
+
+	for (i = 0; i < ctdb->vnn_map->size; i++) {
+		struct ctdb_node *node = ctdb->nodes[ctdb->vnn_map->map[i]];
+		int ret;
+
+		/* only send to active nodes */
+		if (node->flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+
+		ret = ctdb_daemon_send_control(ctdb, node->pnn, 0,
+					       CTDB_CONTROL_UPDATE_RECORD,
+					       c->client_id, 0, recdata,
+					       ctdb_persistent_callback,
+					       state);
+		if (ret == -1) {
+			DEBUG(DEBUG_ERR,("Unable to send "
+					 "CTDB_CONTROL_UPDATE_RECORD "
+					 "to pnn %u\n", node->pnn));
+			talloc_free(state);
+			return -1;
+		}
+
+		state->num_pending++;
+		state->num_sent++;
+	}
+
+	if (state->num_pending == 0) {
+		talloc_free(state);
+		return 0;
+	}
+
+	/* we need to wait for the replies */
+	*async_reply = true;
+
+	/* need to keep the control structure around */
+	talloc_steal(state, c);
+
+	/* but we won't wait forever */
+	event_add_timed(ctdb->ev, state,
+			timeval_current_ofs(ctdb->tunable.control_timeout, 0),
+			ctdb_persistent_store_timeout, state);
+
+	return 0;
+}
+
+
+struct ctdb_persistent_write_state {
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_marshall_buffer *m;
+	struct ctdb_req_control *c;
+};
+
+
+/*
+  called from a child process to write the data
+ */
+static int ctdb_persistent_store(struct ctdb_persistent_write_state *state)
+{
+	int ret, i;
+	struct ctdb_rec_data *rec = NULL;
+	struct ctdb_marshall_buffer *m = state->m;
+
+	ret = tdb_transaction_start(state->ctdb_db->ltdb->tdb);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR,("Failed to start transaction for db_id 0x%08x in ctdb_persistent_store\n",
+				 state->ctdb_db->db_id));
+		return -1;
+	}
+
+	for (i=0;i<m->count;i++) {
+		struct ctdb_ltdb_header oldheader;
+		struct ctdb_ltdb_header header;
+		TDB_DATA key, data, olddata;
+		TALLOC_CTX *tmp_ctx = talloc_new(state);
+
+		rec = ctdb_marshall_loop_next(m, rec, NULL, &header, &key, &data);
+		
+		if (rec == NULL) {
+			DEBUG(DEBUG_ERR,("Failed to get next record %d for db_id 0x%08x in ctdb_persistent_store\n",
+					 i, state->ctdb_db->db_id));
+			talloc_free(tmp_ctx);
+			goto failed;			
+		}
+
+		/* fetch the old header and ensure the rsn is less than the new rsn */
+		ret = ctdb_ltdb_fetch(state->ctdb_db, key, &oldheader, tmp_ctx, &olddata);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to fetch old record for db_id 0x%08x in ctdb_persistent_store\n",
+					 state->ctdb_db->db_id));
+			talloc_free(tmp_ctx);
+			goto failed;
+		}
+
+		if (oldheader.rsn >= header.rsn &&
+		    (olddata.dsize != data.dsize || 
+		     memcmp(olddata.dptr, data.dptr, data.dsize) != 0)) {
+			DEBUG(DEBUG_CRIT,("existing header for db_id 0x%08x has larger RSN %llu than new RSN %llu in ctdb_persistent_store\n",
+					  state->ctdb_db->db_id, 
+					  (unsigned long long)oldheader.rsn, (unsigned long long)header.rsn));
+			talloc_free(tmp_ctx);
+			goto failed;
+		}
+
+		talloc_free(tmp_ctx);
+
+		ret = ctdb_ltdb_store(state->ctdb_db, key, &header, data);
+		if (ret != 0) {
+			DEBUG(DEBUG_CRIT,("Failed to store record for db_id 0x%08x in ctdb_persistent_store\n", 
+					  state->ctdb_db->db_id));
+			goto failed;
+		}
+	}
+
+	ret = tdb_transaction_commit(state->ctdb_db->ltdb->tdb);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR,("Failed to commit transaction for db_id 0x%08x in ctdb_persistent_store\n",
+				 state->ctdb_db->db_id));
+		return -1;
+	}
+
+	return 0;
+	
+failed:
+	tdb_transaction_cancel(state->ctdb_db->ltdb->tdb);
+	return -1;
+}
+
+
+/*
+  called when we the child has completed the persistent write
+  on our behalf
+ */
+static void ctdb_persistent_write_callback(int status, void *private_data)
+{
+	struct ctdb_persistent_write_state *state = talloc_get_type(private_data, 
+								   struct ctdb_persistent_write_state);
+
+
+	ctdb_request_control_reply(state->ctdb_db->ctdb, state->c, NULL, status, NULL);
+
+	talloc_free(state);
+}
+
+/*
+  called if our lockwait child times out
+ */
+static void ctdb_persistent_lock_timeout(struct event_context *ev, struct timed_event *te, 
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_persistent_write_state *state = talloc_get_type(private_data, 
+								   struct ctdb_persistent_write_state);
+	ctdb_request_control_reply(state->ctdb_db->ctdb, state->c, NULL, -1, "timeout in ctdb_persistent_lock");
+	talloc_free(state);
+}
+
+struct childwrite_handle {
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	struct fd_event *fde;
+	int fd[2];
+	pid_t child;
+	void *private_data;
+	void (*callback)(int, void *);
+	struct timeval start_time;
+};
+
+static int childwrite_destructor(struct childwrite_handle *h)
+{
+	CTDB_DECREMENT_STAT(h->ctdb, pending_childwrite_calls);
+	kill(h->child, SIGKILL);
+	return 0;
+}
+
+/* called when the child process has finished writing the record to the
+   database
+*/
+static void childwrite_handler(struct event_context *ev, struct fd_event *fde, 
+			     uint16_t flags, void *private_data)
+{
+	struct childwrite_handle *h = talloc_get_type(private_data, 
+						     struct childwrite_handle);
+	void *p = h->private_data;
+	void (*callback)(int, void *) = h->callback;
+	pid_t child = h->child;
+	TALLOC_CTX *tmp_ctx = talloc_new(ev);
+	int ret;
+	char c;
+
+	CTDB_UPDATE_LATENCY(h->ctdb, h->ctdb_db, "persistent", childwrite_latency, h->start_time);
+	CTDB_DECREMENT_STAT(h->ctdb, pending_childwrite_calls);
+
+	/* the handle needs to go away when the context is gone - when
+	   the handle goes away this implicitly closes the pipe, which
+	   kills the child */
+	talloc_steal(tmp_ctx, h);
+
+	talloc_set_destructor(h, NULL);
+
+	ret = read(h->fd[0], &c, 1);
+	if (ret < 1) {
+		DEBUG(DEBUG_ERR, (__location__ " Read returned %d. Childwrite failed\n", ret));
+		c = 1;
+	}
+
+	callback(c, p);
+
+	kill(child, SIGKILL);
+	talloc_free(tmp_ctx);
+}
+
+/* this creates a child process which will take out a tdb transaction
+   and write the record to the database.
+*/
+struct childwrite_handle *ctdb_childwrite(struct ctdb_db_context *ctdb_db,
+				void (*callback)(int, void *private_data),
+				struct ctdb_persistent_write_state *state)
+{
+	struct childwrite_handle *result;
+	int ret;
+	pid_t parent = getpid();
+
+	CTDB_INCREMENT_STAT(ctdb_db->ctdb, childwrite_calls);
+	CTDB_INCREMENT_STAT(ctdb_db->ctdb, pending_childwrite_calls);
+
+	if (!(result = talloc_zero(state, struct childwrite_handle))) {
+		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_childwrite_calls);
+		return NULL;
+	}
+
+	ret = pipe(result->fd);
+
+	if (ret != 0) {
+		talloc_free(result);
+		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_childwrite_calls);
+		return NULL;
+	}
+
+	result->child = ctdb_fork(ctdb_db->ctdb);
+
+	if (result->child == (pid_t)-1) {
+		close(result->fd[0]);
+		close(result->fd[1]);
+		talloc_free(result);
+		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_childwrite_calls);
+		return NULL;
+	}
+
+	result->callback = callback;
+	result->private_data = state;
+	result->ctdb = ctdb_db->ctdb;
+	result->ctdb_db = ctdb_db;
+
+	if (result->child == 0) {
+		char c = 0;
+
+		close(result->fd[0]);
+		debug_extra = talloc_asprintf(NULL, "childwrite-%s:", ctdb_db->db_name);
+		ret = ctdb_persistent_store(state);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Failed to write persistent data\n"));
+			c = 1;
+		}
+
+		write(result->fd[1], &c, 1);
+
+		/* make sure we die when our parent dies */
+		while (kill(parent, 0) == 0 || errno != ESRCH) {
+			sleep(5);
+		}
+		_exit(0);
+	}
+
+	close(result->fd[1]);
+	set_close_on_exec(result->fd[0]);
+
+	talloc_set_destructor(result, childwrite_destructor);
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d for ctdb_childwrite\n", result->fd[0]));
+
+	result->fde = event_add_fd(ctdb_db->ctdb->ev, result, result->fd[0],
+				   EVENT_FD_READ, childwrite_handler,
+				   (void *)result);
+	if (result->fde == NULL) {
+		talloc_free(result);
+		CTDB_DECREMENT_STAT(ctdb_db->ctdb, pending_childwrite_calls);
+		return NULL;
+	}
+	tevent_fd_set_auto_close(result->fde);
+
+	result->start_time = timeval_current();
+
+	return result;
+}
+
+/* 
+   update a record on this node if the new record has a higher rsn than the
+   current record
+ */
+int32_t ctdb_control_update_record(struct ctdb_context *ctdb, 
+				   struct ctdb_req_control *c, TDB_DATA recdata, 
+				   bool *async_reply)
+{
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_persistent_write_state *state;
+	struct childwrite_handle *handle;
+	struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		DEBUG(DEBUG_INFO,("rejecting ctdb_control_update_record when recovery active\n"));
+		return -1;
+	}
+
+	ctdb_db = find_ctdb_db(ctdb, m->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unknown database 0x%08x in ctdb_control_update_record\n", m->db_id));
+		return -1;
+	}
+
+	if (ctdb_db->unhealthy_reason) {
+		DEBUG(DEBUG_ERR,("db(%s) unhealty in ctdb_control_update_record: %s\n",
+				 ctdb_db->db_name, ctdb_db->unhealthy_reason));
+		return -1;
+	}
+
+	state = talloc(ctdb, struct ctdb_persistent_write_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->ctdb_db = ctdb_db;
+	state->c       = c;
+	state->m       = m;
+
+	/* create a child process to take out a transaction and 
+	   write the data.
+	*/
+	handle = ctdb_childwrite(ctdb_db, ctdb_persistent_write_callback, state);
+	if (handle == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to setup childwrite handler in ctdb_control_update_record\n"));
+		talloc_free(state);
+		return -1;
+	}
+
+	/* we need to wait for the replies */
+	*async_reply = true;
+
+	/* need to keep the control structure around */
+	talloc_steal(state, c);
+
+	/* but we won't wait forever */
+	event_add_timed(ctdb->ev, state, timeval_current_ofs(ctdb->tunable.control_timeout, 0),
+			ctdb_persistent_lock_timeout, state);
+
+	return 0;
+}
+
+
+/*
+  called when a client has finished a local commit in a transaction to 
+  a persistent database
+ */
+int32_t ctdb_control_trans2_finished(struct ctdb_context *ctdb, 
+				     struct ctdb_req_control *c)
+{
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = find_ctdb_db(ctdb, client->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_finish "
+				 "Unknown database 0x%08x\n", client->db_id));
+		return -1;
+	}
+	if (!ctdb_db->transaction_active) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_finish: "
+				 "Database 0x%08x has no transaction commit "
+				 "started\n", client->db_id));
+		return -1;
+	}
+
+	ctdb_db->transaction_active = false;
+	client->db_id = 0;
+
+	if (client->num_persistent_updates == 0) {
+		DEBUG(DEBUG_ERR, (__location__ " ERROR: num_persistent_updates == 0\n"));
+		DEBUG(DEBUG_ERR,(__location__ " Forcing recovery\n"));
+		client->ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+		return -1;
+	}
+	client->num_persistent_updates--;
+
+	DEBUG(DEBUG_DEBUG, (__location__ " client id[0x%08x] finished "
+			    "transaction commit db_id[0x%08x]\n",
+			    client->client_id, ctdb_db->db_id));
+
+	return 0;
+}
+
+/*
+  called when a client gets an error committing its database
+  during a transaction commit
+ */
+int32_t ctdb_control_trans2_error(struct ctdb_context *ctdb, 
+				  struct ctdb_req_control *c)
+{
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = find_ctdb_db(ctdb, client->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_error: "
+				 "Unknown database 0x%08x\n", client->db_id));
+		return -1;
+	}
+	if (!ctdb_db->transaction_active) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control_trans2_error: "
+				 "Database 0x%08x has no transaction commit "
+				 "started\n", client->db_id));
+		return -1;
+	}
+
+	ctdb_db->transaction_active = false;
+	client->db_id = 0;
+
+	if (client->num_persistent_updates == 0) {
+		DEBUG(DEBUG_ERR, (__location__ " ERROR: num_persistent_updates == 0\n"));
+	} else {
+		client->num_persistent_updates--;
+	}
+
+	DEBUG(DEBUG_ERR,(__location__ " An error occurred during transaction on"
+			 " db_id[0x%08x] - forcing recovery\n",
+			 ctdb_db->db_id));
+	client->ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
+
+	return 0;
+}
+
+/**
+ * Tell whether a transaction is active on this node on the give DB.
+ */
+int32_t ctdb_control_trans2_active(struct ctdb_context *ctdb,
+				   struct ctdb_req_control *c,
+				   uint32_t db_id)
+{
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", db_id));
+		return -1;
+	}
+
+	if (client->db_id == db_id) {
+		return 0;
+	}
+
+	if (ctdb_db->transaction_active) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+/*
+  backwards compatibility:
+
+  start a persistent store operation. passing both the key, header and
+  data to the daemon. If the client disconnects before it has issued
+  a persistent_update call to the daemon we trigger a full recovery
+  to ensure the databases are brought back in sync.
+  for now we ignore the recdata that the client has passed to us.
+ */
+int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb, 
+				      struct ctdb_req_control *c,
+				      TDB_DATA recdata)
+{
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " can not match start_persistent_update to a client. Returning error\n"));
+		return -1;
+	}
+
+	client->num_persistent_updates++;
+
+	return 0;
+}
+
+/* 
+  backwards compatibility:
+
+  called to tell ctdbd that it is no longer doing a persistent update 
+*/
+int32_t ctdb_control_cancel_persistent_update(struct ctdb_context *ctdb, 
+					      struct ctdb_req_control *c,
+					      TDB_DATA recdata)
+{
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client);
+
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " can not match cancel_persistent_update to a client. Returning error\n"));
+		return -1;
+	}
+
+	if (client->num_persistent_updates > 0) {
+		client->num_persistent_updates--;
+	}
+
+	return 0;
+}
+
+
+/*
+  backwards compatibility:
+
+  single record varient of ctdb_control_trans2_commit for older clients
+ */
+int32_t ctdb_control_persistent_store(struct ctdb_context *ctdb, 
+				      struct ctdb_req_control *c, 
+				      TDB_DATA recdata, bool *async_reply)
+{
+	struct ctdb_marshall_buffer *m;
+	struct ctdb_rec_data *rec = (struct ctdb_rec_data *)recdata.dptr;
+	TDB_DATA key, data;
+
+	if (recdata.dsize != offsetof(struct ctdb_rec_data, data) + 
+	    rec->keylen + rec->datalen) {
+		DEBUG(DEBUG_ERR, (__location__ " Bad data size in recdata\n"));
+		return -1;
+	}
+
+	key.dptr = &rec->data[0];
+	key.dsize = rec->keylen;
+	data.dptr = &rec->data[rec->keylen];
+	data.dsize = rec->datalen;
+
+	m = ctdb_marshall_add(c, NULL, rec->reqid, rec->reqid, key, NULL, data);
+	CTDB_NO_MEMORY(ctdb, m);
+
+	return ctdb_control_trans2_commit(ctdb, c, ctdb_marshall_finish(m), async_reply);
+}
+
+static int32_t ctdb_get_db_seqnum(struct ctdb_context *ctdb,
+				  uint32_t db_id,
+				  uint64_t *seqnum)
+{
+	int32_t ret;
+	struct ctdb_db_context *ctdb_db;
+	const char *keyname = CTDB_DB_SEQNUM_KEY;
+	TDB_DATA key;
+	TDB_DATA data;
+	TALLOC_CTX *mem_ctx = talloc_new(ctdb);
+
+	ctdb_db = find_ctdb_db(ctdb, db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", db_id));
+		ret = -1;
+		goto done;
+	}
+
+	key.dptr = (uint8_t *)discard_const(keyname);
+	key.dsize = strlen(keyname) + 1;
+
+	ret = (int32_t)ctdb_ltdb_fetch(ctdb_db, key, NULL, mem_ctx, &data);
+	if (ret != 0) {
+		goto done;
+	}
+
+	if (data.dsize != sizeof(uint64_t)) {
+		*seqnum = 0;
+		goto done;
+	}
+
+	*seqnum = *(uint64_t *)data.dptr;
+
+done:
+	talloc_free(mem_ctx);
+	return ret;
+}
+
+/**
+ * Get the sequence number of a persistent database.
+ */
+int32_t ctdb_control_get_db_seqnum(struct ctdb_context *ctdb,
+				   TDB_DATA indata,
+				   TDB_DATA *outdata)
+{
+	uint32_t db_id;
+	int32_t ret;
+	uint64_t seqnum;
+
+	db_id = *(uint32_t *)indata.dptr;
+	ret = ctdb_get_db_seqnum(ctdb, db_id, &seqnum);
+	if (ret != 0) {
+		goto done;
+	}
+
+	outdata->dsize = sizeof(uint64_t);
+	outdata->dptr = (uint8_t *)talloc_zero(outdata, uint64_t);
+	if (outdata->dptr == NULL) {
+		ret = -1;
+		goto done;
+	}
+
+	*(outdata->dptr) = seqnum;
+
+done:
+	return ret;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_recover.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_recover.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_recover.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1326 @@
+/* 
+   ctdb recovery code
+
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Ronnie Sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/time.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+#include "lib/util/dlinklist.h"
+#include "db_wrap.h"
+
+/*
+  lock all databases - mark only
+ */
+static int ctdb_lock_all_databases_mark(struct ctdb_context *ctdb, uint32_t priority)
+{
+	struct ctdb_db_context *ctdb_db;
+
+	if ((priority < 1) || (priority > NUM_DB_PRIORITIES)) {
+		DEBUG(DEBUG_ERR,(__location__ " Illegal priority when trying to mark all databases Prio:%u\n", priority));
+		return -1;
+	}
+
+	if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_ERR,("Attempt to mark all databases locked when not frozen\n"));
+		return -1;
+	}
+	/* The dual loop is a woraround for older versions of samba
+	   that does not yet support the set-db-priority/lock order
+	   call. So that we get basic deadlock avoiidance also for
+	   these old versions of samba.
+	   This code will be removed in the future.
+	*/
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		if (ctdb_db->priority != priority) {
+			continue;
+		}
+		if (strstr(ctdb_db->db_name, "notify") != NULL) {
+			continue;
+		}
+		if (tdb_transaction_write_lock_mark(ctdb_db->ltdb->tdb) != 0) {
+			return -1;
+		}
+		if (tdb_lockall_mark(ctdb_db->ltdb->tdb) != 0) {
+			tdb_transaction_write_lock_unmark(ctdb_db->ltdb->tdb);
+			return -1;
+		}
+	}
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		if (ctdb_db->priority != priority) {
+			continue;
+		}
+		if (strstr(ctdb_db->db_name, "notify") == NULL) {
+			continue;
+		}
+		if (tdb_transaction_write_lock_mark(ctdb_db->ltdb->tdb) != 0) {
+			return -1;
+		}
+		if (tdb_lockall_mark(ctdb_db->ltdb->tdb) != 0) {
+			tdb_transaction_write_lock_unmark(ctdb_db->ltdb->tdb);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+  lock all databases - unmark only
+ */
+static int ctdb_lock_all_databases_unmark(struct ctdb_context *ctdb, uint32_t priority)
+{
+	struct ctdb_db_context *ctdb_db;
+
+	if ((priority < 1) || (priority > NUM_DB_PRIORITIES)) {
+		DEBUG(DEBUG_ERR,(__location__ " Illegal priority when trying to mark all databases Prio:%u\n", priority));
+		return -1;
+	}
+
+	if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_ERR,("Attempt to unmark all databases locked when not frozen\n"));
+		return -1;
+	}
+	for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) {
+		if (ctdb_db->priority != priority) {
+			continue;
+		}
+		tdb_transaction_write_lock_unmark(ctdb_db->ltdb->tdb);
+		if (tdb_lockall_unmark(ctdb_db->ltdb->tdb) != 0) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+
+int 
+ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
+{
+	CHECK_CONTROL_DATA_SIZE(0);
+	struct ctdb_vnn_map_wire *map;
+	size_t len;
+
+	len = offsetof(struct ctdb_vnn_map_wire, map) + sizeof(uint32_t)*ctdb->vnn_map->size;
+	map = talloc_size(outdata, len);
+	CTDB_NO_MEMORY(ctdb, map);
+
+	map->generation = ctdb->vnn_map->generation;
+	map->size = ctdb->vnn_map->size;
+	memcpy(map->map, ctdb->vnn_map->map, sizeof(uint32_t)*map->size);
+
+	outdata->dsize = len;
+	outdata->dptr  = (uint8_t *)map;
+
+	return 0;
+}
+
+int 
+ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
+{
+	struct ctdb_vnn_map_wire *map = (struct ctdb_vnn_map_wire *)indata.dptr;
+	int i;
+
+	for(i=1; i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) {
+			DEBUG(DEBUG_ERR,("Attempt to set vnnmap when not frozen\n"));
+			return -1;
+		}
+	}
+
+	talloc_free(ctdb->vnn_map);
+
+	ctdb->vnn_map = talloc(ctdb, struct ctdb_vnn_map);
+	CTDB_NO_MEMORY(ctdb, ctdb->vnn_map);
+
+	ctdb->vnn_map->generation = map->generation;
+	ctdb->vnn_map->size       = map->size;
+	ctdb->vnn_map->map = talloc_array(ctdb->vnn_map, uint32_t, map->size);
+	CTDB_NO_MEMORY(ctdb, ctdb->vnn_map->map);
+
+	memcpy(ctdb->vnn_map->map, map->map, sizeof(uint32_t)*map->size);
+
+	return 0;
+}
+
+int 
+ctdb_control_getdbmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
+{
+	uint32_t i, len;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_dbid_map *dbid_map;
+
+	CHECK_CONTROL_DATA_SIZE(0);
+
+	len = 0;
+	for(ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next){
+		len++;
+	}
+
+
+	outdata->dsize = offsetof(struct ctdb_dbid_map, dbs) + sizeof(dbid_map->dbs[0])*len;
+	outdata->dptr  = (unsigned char *)talloc_zero_size(outdata, outdata->dsize);
+	if (!outdata->dptr) {
+		DEBUG(DEBUG_ALERT, (__location__ " Failed to allocate dbmap array\n"));
+		exit(1);
+	}
+
+	dbid_map = (struct ctdb_dbid_map *)outdata->dptr;
+	dbid_map->num = len;
+	for (i=0,ctdb_db=ctdb->db_list;ctdb_db;i++,ctdb_db=ctdb_db->next){
+		dbid_map->dbs[i].dbid       = ctdb_db->db_id;
+		if (ctdb_db->persistent != 0) {
+			dbid_map->dbs[i].flags |= CTDB_DB_FLAGS_PERSISTENT;
+		}
+		if (ctdb_db->readonly != 0) {
+			dbid_map->dbs[i].flags |= CTDB_DB_FLAGS_READONLY;
+		}
+	}
+
+	return 0;
+}
+
+int 
+ctdb_control_getnodemap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
+{
+	uint32_t i, num_nodes;
+	struct ctdb_node_map *node_map;
+
+	CHECK_CONTROL_DATA_SIZE(0);
+
+	num_nodes = ctdb->num_nodes;
+
+	outdata->dsize = offsetof(struct ctdb_node_map, nodes) + num_nodes*sizeof(struct ctdb_node_and_flags);
+	outdata->dptr  = (unsigned char *)talloc_zero_size(outdata, outdata->dsize);
+	if (!outdata->dptr) {
+		DEBUG(DEBUG_ALERT, (__location__ " Failed to allocate nodemap array\n"));
+		exit(1);
+	}
+
+	node_map = (struct ctdb_node_map *)outdata->dptr;
+	node_map->num = num_nodes;
+	for (i=0; i<num_nodes; i++) {
+		if (parse_ip(ctdb->nodes[i]->address.address,
+			     NULL, /* TODO: pass in the correct interface here*/
+			     0,
+			     &node_map->nodes[i].addr) == 0)
+		{
+			DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a sockaddr\n", ctdb->nodes[i]->address.address));
+		}
+
+		node_map->nodes[i].pnn   = ctdb->nodes[i]->pnn;
+		node_map->nodes[i].flags = ctdb->nodes[i]->flags;
+	}
+
+	return 0;
+}
+
+/*
+   get an old style ipv4-only nodemap
+*/
+int 
+ctdb_control_getnodemapv4(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
+{
+	uint32_t i, num_nodes;
+	struct ctdb_node_mapv4 *node_map;
+
+	CHECK_CONTROL_DATA_SIZE(0);
+
+	num_nodes = ctdb->num_nodes;
+
+	outdata->dsize = offsetof(struct ctdb_node_mapv4, nodes) + num_nodes*sizeof(struct ctdb_node_and_flagsv4);
+	outdata->dptr  = (unsigned char *)talloc_zero_size(outdata, outdata->dsize);
+	if (!outdata->dptr) {
+		DEBUG(DEBUG_ALERT, (__location__ " Failed to allocate nodemap array\n"));
+		exit(1);
+	}
+
+	node_map = (struct ctdb_node_mapv4 *)outdata->dptr;
+	node_map->num = num_nodes;
+	for (i=0; i<num_nodes; i++) {
+		if (parse_ipv4(ctdb->nodes[i]->address.address, 0, &node_map->nodes[i].sin) == 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a sockaddr\n", ctdb->nodes[i]->address.address));
+			return -1;
+		}
+
+		node_map->nodes[i].pnn   = ctdb->nodes[i]->pnn;
+		node_map->nodes[i].flags = ctdb->nodes[i]->flags;
+	}
+
+	return 0;
+}
+
+static void
+ctdb_reload_nodes_event(struct event_context *ev, struct timed_event *te, 
+			       struct timeval t, void *private_data)
+{
+	int i, num_nodes;
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	TALLOC_CTX *tmp_ctx;
+	struct ctdb_node **nodes;	
+
+	tmp_ctx = talloc_new(ctdb);
+
+	/* steal the old nodes file for a while */
+	talloc_steal(tmp_ctx, ctdb->nodes);
+	nodes = ctdb->nodes;
+	ctdb->nodes = NULL;
+	num_nodes = ctdb->num_nodes;
+	ctdb->num_nodes = 0;
+
+	/* load the new nodes file */
+	ctdb_load_nodes_file(ctdb);
+
+	for (i=0; i<ctdb->num_nodes; i++) {
+		/* keep any identical pre-existing nodes and connections */
+		if ((i < num_nodes) && ctdb_same_address(&ctdb->nodes[i]->address, &nodes[i]->address)) {
+			talloc_free(ctdb->nodes[i]);
+			ctdb->nodes[i] = talloc_steal(ctdb->nodes, nodes[i]);
+			continue;
+		}
+
+		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+
+		/* any new or different nodes must be added */
+		if (ctdb->methods->add_node(ctdb->nodes[i]) != 0) {
+			DEBUG(DEBUG_CRIT, (__location__ " methods->add_node failed at %d\n", i));
+			ctdb_fatal(ctdb, "failed to add node. shutting down\n");
+		}
+		if (ctdb->methods->connect_node(ctdb->nodes[i]) != 0) {
+			DEBUG(DEBUG_CRIT, (__location__ " methods->add_connect failed at %d\n", i));
+			ctdb_fatal(ctdb, "failed to connect to node. shutting down\n");
+		}
+	}
+
+	/* tell the recovery daemon to reaload the nodes file too */
+	ctdb_daemon_send_message(ctdb, ctdb->pnn, CTDB_SRVID_RELOAD_NODES, tdb_null);
+
+	talloc_free(tmp_ctx);
+	return;
+}
+
+/*
+  reload the nodes file after a short delay (so that we can send the response
+  back first
+*/
+int 
+ctdb_control_reload_nodes_file(struct ctdb_context *ctdb, uint32_t opcode)
+{
+	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1,0), ctdb_reload_nodes_event, ctdb);
+
+	return 0;
+}
+
+/* 
+   a traverse function for pulling all relevent records from pulldb
+ */
+struct pulldb_data {
+	struct ctdb_context *ctdb;
+	struct ctdb_marshall_buffer *pulldata;
+	uint32_t len;
+	bool failed;
+};
+
+static int traverse_pulldb(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *p)
+{
+	struct pulldb_data *params = (struct pulldb_data *)p;
+	struct ctdb_rec_data *rec;
+
+	/* add the record to the blob */
+	rec = ctdb_marshall_record(params->pulldata, 0, key, NULL, data);
+	if (rec == NULL) {
+		params->failed = true;
+		return -1;
+	}
+	params->pulldata = talloc_realloc_size(NULL, params->pulldata, rec->length + params->len);
+	if (params->pulldata == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to expand pulldb_data to %u\n", rec->length + params->len));
+		ctdb_fatal(params->ctdb, "failed to allocate memory for recovery. shutting down\n");
+	}
+	params->pulldata->count++;
+	memcpy(params->len+(uint8_t *)params->pulldata, rec, rec->length);
+	params->len += rec->length;
+	talloc_free(rec);
+
+	return 0;
+}
+
+/*
+  pul a bunch of records from a ltdb, filtering by lmaster
+ */
+int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata)
+{
+	struct ctdb_control_pulldb *pull;
+	struct ctdb_db_context *ctdb_db;
+	struct pulldb_data params;
+	struct ctdb_marshall_buffer *reply;
+
+	pull = (struct ctdb_control_pulldb *)indata.dptr;
+	
+	ctdb_db = find_ctdb_db(ctdb, pull->db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", pull->db_id));
+		return -1;
+	}
+
+	if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_pull_db when not frozen\n"));
+		return -1;
+	}
+
+	reply = talloc_zero(outdata, struct ctdb_marshall_buffer);
+	CTDB_NO_MEMORY(ctdb, reply);
+
+	reply->db_id = pull->db_id;
+
+	params.ctdb = ctdb;
+	params.pulldata = reply;
+	params.len = offsetof(struct ctdb_marshall_buffer, data);
+	params.failed = false;
+
+	if (ctdb_db->unhealthy_reason) {
+		/* this is just a warning, as the tdb should be empty anyway */
+		DEBUG(DEBUG_WARNING,("db(%s) unhealty in ctdb_control_pull_db: %s\n",
+				     ctdb_db->db_name, ctdb_db->unhealthy_reason));
+	}
+
+	if (ctdb_lock_all_databases_mark(ctdb, ctdb_db->priority) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entired db - failing\n"));
+		return -1;
+	}
+
+	if (tdb_traverse_read(ctdb_db->ltdb->tdb, traverse_pulldb, &params) == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get traverse db '%s'\n", ctdb_db->db_name));
+		ctdb_lock_all_databases_unmark(ctdb, ctdb_db->priority);
+		talloc_free(params.pulldata);
+		return -1;
+	}
+
+	ctdb_lock_all_databases_unmark(ctdb, ctdb_db->priority);
+
+	outdata->dptr = (uint8_t *)params.pulldata;
+	outdata->dsize = params.len;
+
+	return 0;
+}
+
+/*
+  push a bunch of records into a ltdb, filtering by rsn
+ */
+int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_marshall_buffer *reply = (struct ctdb_marshall_buffer *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
+	int i, ret;
+	struct ctdb_rec_data *rec;
+
+	if (indata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
+		DEBUG(DEBUG_ERR,(__location__ " invalid data in pulldb reply\n"));
+		return -1;
+	}
+
+	ctdb_db = find_ctdb_db(ctdb, reply->db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", reply->db_id));
+		return -1;
+	}
+
+	if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_push_db when not frozen\n"));
+		return -1;
+	}
+
+	if (ctdb_lock_all_databases_mark(ctdb, ctdb_db->priority) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entired db - failing\n"));
+		return -1;
+	}
+
+	rec = (struct ctdb_rec_data *)&reply->data[0];
+
+	DEBUG(DEBUG_INFO,("starting push of %u records for dbid 0x%x\n",
+		 reply->count, reply->db_id));
+
+	for (i=0;i<reply->count;i++) {
+		TDB_DATA key, data;
+		struct ctdb_ltdb_header *hdr;
+
+		key.dptr = &rec->data[0];
+		key.dsize = rec->keylen;
+		data.dptr = &rec->data[key.dsize];
+		data.dsize = rec->datalen;
+
+		if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
+			DEBUG(DEBUG_CRIT,(__location__ " bad ltdb record\n"));
+			goto failed;
+		}
+		hdr = (struct ctdb_ltdb_header *)data.dptr;
+		/* strip off any read only record flags. All readonly records
+		   are revoked implicitely by a recovery
+		*/
+		hdr->flags &= ~(CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY|CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_REVOKE_COMPLETE);
+
+		data.dptr += sizeof(*hdr);
+		data.dsize -= sizeof(*hdr);
+
+		ret = ctdb_ltdb_store(ctdb_db, key, hdr, data);
+		if (ret != 0) {
+			DEBUG(DEBUG_CRIT, (__location__ " Unable to store record\n"));
+			goto failed;
+		}
+
+		rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+	}	    
+
+	DEBUG(DEBUG_DEBUG,("finished push of %u records for dbid 0x%x\n",
+		 reply->count, reply->db_id));
+
+	if (ctdb_db->readonly) {
+		DEBUG(DEBUG_CRIT,("Clearing the tracking database for dbid 0x%x\n",
+				  ctdb_db->db_id));
+		if (tdb_wipe_all(ctdb_db->rottdb) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to wipe tracking database for 0x%x. Dropping read-only delegation support\n", ctdb_db->db_id));
+			ctdb_db->readonly = false;
+			tdb_close(ctdb_db->rottdb);
+			ctdb_db->rottdb = NULL;
+			ctdb_db->readonly = false;
+		}
+		while (ctdb_db->revokechild_active != NULL) {
+			talloc_free(ctdb_db->revokechild_active);
+		}
+	}
+
+	ctdb_lock_all_databases_unmark(ctdb, ctdb_db->priority);
+	return 0;
+
+failed:
+	ctdb_lock_all_databases_unmark(ctdb, ctdb_db->priority);
+	return -1;
+}
+
+
+static int traverse_setdmaster(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *p)
+{
+	uint32_t *dmaster = (uint32_t *)p;
+	struct ctdb_ltdb_header *header = (struct ctdb_ltdb_header *)data.dptr;
+	int ret;
+
+	/* skip if already correct */
+	if (header->dmaster == *dmaster) {
+		return 0;
+	}
+
+	header->dmaster = *dmaster;
+
+	ret = tdb_store(tdb, key, data, TDB_REPLACE);
+	if (ret) {
+		DEBUG(DEBUG_CRIT,(__location__ " failed to write tdb data back  ret:%d\n",ret));
+		return ret;
+	}
+
+	/* TODO: add error checking here */
+
+	return 0;
+}
+
+int32_t ctdb_control_set_dmaster(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_control_set_dmaster *p = (struct ctdb_control_set_dmaster *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = find_ctdb_db(ctdb, p->db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", p->db_id));
+		return -1;
+	}
+
+	if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) {
+		DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_set_dmaster when not frozen\n"));
+		return -1;
+	}
+
+	if (ctdb_lock_all_databases_mark(ctdb, 	ctdb_db->priority) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entired db - failing\n"));
+		return -1;
+	}
+
+	tdb_traverse(ctdb_db->ltdb->tdb, traverse_setdmaster, &p->dmaster);
+
+	ctdb_lock_all_databases_unmark(ctdb, ctdb_db->priority);
+	
+	return 0;
+}
+
+struct ctdb_set_recmode_state {
+	struct ctdb_context *ctdb;
+	struct ctdb_req_control *c;
+	uint32_t recmode;
+	int fd[2];
+	struct timed_event *te;
+	struct fd_event *fde;
+	pid_t child;
+	struct timeval start_time;
+};
+
+/*
+  called if our set_recmode child times out. this would happen if
+  ctdb_recovery_lock() would block.
+ */
+static void ctdb_set_recmode_timeout(struct event_context *ev, struct timed_event *te, 
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_set_recmode_state *state = talloc_get_type(private_data, 
+					   struct ctdb_set_recmode_state);
+
+	/* we consider this a success, not a failure, as we failed to
+	   set the recovery lock which is what we wanted.  This can be
+	   caused by the cluster filesystem being very slow to
+	   arbitrate locks immediately after a node failure.	   
+	 */
+	DEBUG(DEBUG_ERR,(__location__ " set_recmode child process hung/timedout CFS slow to grant locks? (allowing recmode set anyway)\n"));
+	state->ctdb->recovery_mode = state->recmode;
+	ctdb_request_control_reply(state->ctdb, state->c, NULL, 0, NULL);
+	talloc_free(state);
+}
+
+
+/* when we free the recmode state we must kill any child process.
+*/
+static int set_recmode_destructor(struct ctdb_set_recmode_state *state)
+{
+	double l = timeval_elapsed(&state->start_time);
+
+	CTDB_UPDATE_RECLOCK_LATENCY(state->ctdb, "daemon reclock", reclock.ctdbd, l);
+
+	if (state->fd[0] != -1) {
+		state->fd[0] = -1;
+	}
+	if (state->fd[1] != -1) {
+		state->fd[1] = -1;
+	}
+	kill(state->child, SIGKILL);
+	return 0;
+}
+
+/* this is called when the client process has completed ctdb_recovery_lock()
+   and has written data back to us through the pipe.
+*/
+static void set_recmode_handler(struct event_context *ev, struct fd_event *fde, 
+			     uint16_t flags, void *private_data)
+{
+	struct ctdb_set_recmode_state *state= talloc_get_type(private_data, 
+					     struct ctdb_set_recmode_state);
+	char c = 0;
+	int ret;
+
+	/* we got a response from our child process so we can abort the
+	   timeout.
+	*/
+	talloc_free(state->te);
+	state->te = NULL;
+
+
+	/* read the childs status when trying to lock the reclock file.
+	   child wrote 0 if everything is fine and 1 if it did manage
+	   to lock the file, which would be a problem since that means
+	   we got a request to exit from recovery but we could still lock
+	   the file   which at this time SHOULD be locked by the recovery
+	   daemon on the recmaster
+	*/		
+	ret = read(state->fd[0], &c, 1);
+	if (ret != 1 || c != 0) {
+		ctdb_request_control_reply(state->ctdb, state->c, NULL, -1, "managed to lock reclock file from inside daemon");
+		talloc_free(state);
+		return;
+	}
+
+	state->ctdb->recovery_mode = state->recmode;
+
+	/* release any deferred attach calls from clients */
+	if (state->recmode == CTDB_RECOVERY_NORMAL) {
+		ctdb_process_deferred_attach(state->ctdb);
+	}
+
+	ctdb_request_control_reply(state->ctdb, state->c, NULL, 0, NULL);
+	talloc_free(state);
+	return;
+}
+
+static void
+ctdb_drop_all_ips_event(struct event_context *ev, struct timed_event *te, 
+			       struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+
+	DEBUG(DEBUG_ERR,(__location__ " Been in recovery mode for too long. Dropping all IPS\n"));
+	talloc_free(ctdb->release_ips_ctx);
+	ctdb->release_ips_ctx = NULL;
+
+	ctdb_release_all_ips(ctdb);
+}
+
+/*
+ * Set up an event to drop all public ips if we remain in recovery for too
+ * long
+ */
+int ctdb_deferred_drop_all_ips(struct ctdb_context *ctdb)
+{
+	if (ctdb->release_ips_ctx != NULL) {
+		talloc_free(ctdb->release_ips_ctx);
+	}
+	ctdb->release_ips_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY(ctdb, ctdb->release_ips_ctx);
+
+	event_add_timed(ctdb->ev, ctdb->release_ips_ctx, timeval_current_ofs(ctdb->tunable.recovery_drop_all_ips, 0), ctdb_drop_all_ips_event, ctdb);
+	return 0;
+}
+
+/*
+  set the recovery mode
+ */
+int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, 
+				 struct ctdb_req_control *c,
+				 TDB_DATA indata, bool *async_reply,
+				 const char **errormsg)
+{
+	uint32_t recmode = *(uint32_t *)indata.dptr;
+	int i, ret;
+	struct ctdb_set_recmode_state *state;
+	pid_t parent = getpid();
+
+	/* if we enter recovery but stay in recovery for too long
+	   we will eventually drop all our ip addresses
+	*/
+	if (recmode == CTDB_RECOVERY_NORMAL) {
+		talloc_free(ctdb->release_ips_ctx);
+		ctdb->release_ips_ctx = NULL;
+	} else {
+		if (ctdb_deferred_drop_all_ips(ctdb) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to set up deferred drop all ips\n"));
+		}
+	}
+
+	if (recmode != ctdb->recovery_mode) {
+		DEBUG(DEBUG_NOTICE,(__location__ " Recovery mode set to %s\n", 
+			 recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"ACTIVE"));
+	}
+
+	if (recmode != CTDB_RECOVERY_NORMAL ||
+	    ctdb->recovery_mode != CTDB_RECOVERY_ACTIVE) {
+		ctdb->recovery_mode = recmode;
+		return 0;
+	}
+
+	/* some special handling when ending recovery mode */
+
+	/* force the databases to thaw */
+	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb->freeze_handles[i] != NULL) {
+			ctdb_control_thaw(ctdb, i);
+		}
+	}
+
+	state = talloc(ctdb, struct ctdb_set_recmode_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->start_time = timeval_current();
+	state->fd[0] = -1;
+	state->fd[1] = -1;
+
+	/* release any deferred attach calls from clients */
+	if (recmode == CTDB_RECOVERY_NORMAL) {
+		ctdb_process_deferred_attach(ctdb);
+	}
+
+	if (ctdb->tunable.verify_recovery_lock == 0) {
+		/* dont need to verify the reclock file */
+		ctdb->recovery_mode = recmode;
+		return 0;
+	}
+
+	/* For the rest of what needs to be done, we need to do this in
+	   a child process since 
+	   1, the call to ctdb_recovery_lock() can block if the cluster
+	      filesystem is in the process of recovery.
+	*/
+	ret = pipe(state->fd);
+	if (ret != 0) {
+		talloc_free(state);
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to open pipe for set_recmode child\n"));
+		return -1;
+	}
+
+	state->child = fork();
+	if (state->child == (pid_t)-1) {
+		close(state->fd[0]);
+		close(state->fd[1]);
+		talloc_free(state);
+		return -1;
+	}
+
+	if (state->child == 0) {
+		char cc = 0;
+		close(state->fd[0]);
+
+		debug_extra = talloc_asprintf(NULL, "set_recmode:");
+		/* we should not be able to get the lock on the reclock file, 
+		  as it should  be held by the recovery master 
+		*/
+		if (ctdb_recovery_lock(ctdb, false)) {
+			DEBUG(DEBUG_CRIT,("ERROR: recovery lock file %s not locked when recovering!\n", ctdb->recovery_lock_file));
+			cc = 1;
+		}
+
+		write(state->fd[1], &cc, 1);
+		/* make sure we die when our parent dies */
+		while (kill(parent, 0) == 0 || errno != ESRCH) {
+			sleep(5);
+			write(state->fd[1], &cc, 1);
+		}
+		_exit(0);
+	}
+	close(state->fd[1]);
+	set_close_on_exec(state->fd[0]);
+
+	state->fd[1] = -1;
+
+	talloc_set_destructor(state, set_recmode_destructor);
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d for setrecmode\n", state->fd[0]));
+
+	state->te = event_add_timed(ctdb->ev, state, timeval_current_ofs(5, 0),
+				    ctdb_set_recmode_timeout, state);
+
+	state->fde = event_add_fd(ctdb->ev, state, state->fd[0],
+				EVENT_FD_READ,
+				set_recmode_handler,
+				(void *)state);
+
+	if (state->fde == NULL) {
+		talloc_free(state);
+		return -1;
+	}
+	tevent_fd_set_auto_close(state->fde);
+
+	state->ctdb    = ctdb;
+	state->recmode = recmode;
+	state->c       = talloc_steal(state, c);
+
+	*async_reply = true;
+
+	return 0;
+}
+
+
+/*
+  try and get the recovery lock in shared storage - should only work
+  on the recovery master recovery daemon. Anywhere else is a bug
+ */
+bool ctdb_recovery_lock(struct ctdb_context *ctdb, bool keep)
+{
+	struct flock lock;
+
+	if (keep) {
+		DEBUG(DEBUG_ERR, ("Take the recovery lock\n"));
+	}
+	if (ctdb->recovery_lock_fd != -1) {
+		close(ctdb->recovery_lock_fd);
+		ctdb->recovery_lock_fd = -1;
+	}
+
+	ctdb->recovery_lock_fd = open(ctdb->recovery_lock_file, O_RDWR|O_CREAT, 0600);
+	if (ctdb->recovery_lock_fd == -1) {
+		DEBUG(DEBUG_ERR,("ctdb_recovery_lock: Unable to open %s - (%s)\n", 
+			 ctdb->recovery_lock_file, strerror(errno)));
+		return false;
+	}
+
+	set_close_on_exec(ctdb->recovery_lock_fd);
+
+	lock.l_type = F_WRLCK;
+	lock.l_whence = SEEK_SET;
+	lock.l_start = 0;
+	lock.l_len = 1;
+	lock.l_pid = 0;
+
+	if (fcntl(ctdb->recovery_lock_fd, F_SETLK, &lock) != 0) {
+		close(ctdb->recovery_lock_fd);
+		ctdb->recovery_lock_fd = -1;
+		if (keep) {
+			DEBUG(DEBUG_CRIT,("ctdb_recovery_lock: Failed to get recovery lock on '%s'\n", ctdb->recovery_lock_file));
+		}
+		return false;
+	}
+
+	if (!keep) {
+		close(ctdb->recovery_lock_fd);
+		ctdb->recovery_lock_fd = -1;
+	}
+
+	if (keep) {
+		DEBUG(DEBUG_NOTICE, ("Recovery lock taken successfully\n"));
+	}
+
+	DEBUG(DEBUG_NOTICE,("ctdb_recovery_lock: Got recovery lock on '%s'\n", ctdb->recovery_lock_file));
+
+	return true;
+}
+
+/*
+  delete a record as part of the vacuum process
+  only delete if we are not lmaster or dmaster, and our rsn is <= the provided rsn
+  use non-blocking locks
+
+  return 0 if the record was successfully deleted (i.e. it does not exist
+  when the function returns)
+  or !0 is the record still exists in the tdb after returning.
+ */
+static int delete_tdb_record(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, struct ctdb_rec_data *rec)
+{
+	TDB_DATA key, data;
+	struct ctdb_ltdb_header *hdr, *hdr2;
+	
+	/* these are really internal tdb functions - but we need them here for
+	   non-blocking lock of the freelist */
+	int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
+	int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
+
+
+	key.dsize = rec->keylen;
+	key.dptr  = &rec->data[0];
+	data.dsize = rec->datalen;
+	data.dptr = &rec->data[rec->keylen];
+
+	if (ctdb_lmaster(ctdb, &key) == ctdb->pnn) {
+		DEBUG(DEBUG_INFO,(__location__ " Called delete on record where we are lmaster\n"));
+		return -1;
+	}
+
+	if (data.dsize != sizeof(struct ctdb_ltdb_header)) {
+		DEBUG(DEBUG_ERR,(__location__ " Bad record size\n"));
+		return -1;
+	}
+
+	hdr = (struct ctdb_ltdb_header *)data.dptr;
+
+	/* use a non-blocking lock */
+	if (tdb_chainlock_nonblock(ctdb_db->ltdb->tdb, key) != 0) {
+		return -1;
+	}
+
+	data = tdb_fetch(ctdb_db->ltdb->tdb, key);
+	if (data.dptr == NULL) {
+		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+		return 0;
+	}
+
+	if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
+		if (tdb_lock_nonblock(ctdb_db->ltdb->tdb, -1, F_WRLCK) == 0) {
+			tdb_delete(ctdb_db->ltdb->tdb, key);
+			tdb_unlock(ctdb_db->ltdb->tdb, -1, F_WRLCK);
+			DEBUG(DEBUG_CRIT,(__location__ " Deleted corrupt record\n"));
+		}
+		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+		free(data.dptr);
+		return 0;
+	}
+	
+	hdr2 = (struct ctdb_ltdb_header *)data.dptr;
+
+	if (hdr2->rsn > hdr->rsn) {
+		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+		DEBUG(DEBUG_INFO,(__location__ " Skipping record with rsn=%llu - called with rsn=%llu\n",
+			 (unsigned long long)hdr2->rsn, (unsigned long long)hdr->rsn));
+		free(data.dptr);
+		return -1;		
+	}
+
+	if (hdr2->dmaster == ctdb->pnn) {
+		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+		DEBUG(DEBUG_INFO,(__location__ " Attempted delete record where we are the dmaster\n"));
+		free(data.dptr);
+		return -1;				
+	}
+
+	if (tdb_lock_nonblock(ctdb_db->ltdb->tdb, -1, F_WRLCK) != 0) {
+		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+		free(data.dptr);
+		return -1;				
+	}
+
+	if (tdb_delete(ctdb_db->ltdb->tdb, key) != 0) {
+		tdb_unlock(ctdb_db->ltdb->tdb, -1, F_WRLCK);
+		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+		DEBUG(DEBUG_INFO,(__location__ " Failed to delete record\n"));
+		free(data.dptr);
+		return -1;						
+	}
+
+	tdb_unlock(ctdb_db->ltdb->tdb, -1, F_WRLCK);
+	tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+	free(data.dptr);
+	return 0;	
+}
+
+
+
+struct recovery_callback_state {
+	struct ctdb_req_control *c;
+};
+
+
+/*
+  called when the 'recovered' event script has finished
+ */
+static void ctdb_end_recovery_callback(struct ctdb_context *ctdb, int status, void *p)
+{
+	struct recovery_callback_state *state = talloc_get_type(p, struct recovery_callback_state);
+
+	ctdb_enable_monitoring(ctdb);
+	CTDB_INCREMENT_STAT(ctdb, num_recoveries);
+
+	if (status != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " recovered event script failed (status %d)\n", status));
+		if (status == -ETIME) {
+			ctdb_ban_self(ctdb);
+		}
+	}
+
+	ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
+	talloc_free(state);
+
+	gettimeofday(&ctdb->last_recovery_finished, NULL);
+}
+
+/*
+  recovery has finished
+ */
+int32_t ctdb_control_end_recovery(struct ctdb_context *ctdb, 
+				struct ctdb_req_control *c,
+				bool *async_reply)
+{
+	int ret;
+	struct recovery_callback_state *state;
+
+	DEBUG(DEBUG_NOTICE,("Recovery has finished\n"));
+
+	ctdb_persistent_finish_trans3_commits(ctdb);
+
+	state = talloc(ctdb, struct recovery_callback_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->c    = c;
+
+	ctdb_disable_monitoring(ctdb);
+
+	ret = ctdb_event_script_callback(ctdb, state,
+					 ctdb_end_recovery_callback, 
+					 state, 
+					 false,
+					 CTDB_EVENT_RECOVERED, "%s", "");
+
+	if (ret != 0) {
+		ctdb_enable_monitoring(ctdb);
+
+		DEBUG(DEBUG_ERR,(__location__ " Failed to end recovery\n"));
+		talloc_free(state);
+		return -1;
+	}
+
+	/* tell the control that we will be reply asynchronously */
+	state->c    = talloc_steal(state, c);
+	*async_reply = true;
+	return 0;
+}
+
+/*
+  called when the 'startrecovery' event script has finished
+ */
+static void ctdb_start_recovery_callback(struct ctdb_context *ctdb, int status, void *p)
+{
+	struct recovery_callback_state *state = talloc_get_type(p, struct recovery_callback_state);
+
+	if (status != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " startrecovery event script failed (status %d)\n", status));
+	}
+
+	ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
+	talloc_free(state);
+}
+
+/*
+  run the startrecovery eventscript
+ */
+int32_t ctdb_control_start_recovery(struct ctdb_context *ctdb, 
+				struct ctdb_req_control *c,
+				bool *async_reply)
+{
+	int ret;
+	struct recovery_callback_state *state;
+
+	DEBUG(DEBUG_NOTICE,(__location__ " startrecovery eventscript has been invoked\n"));
+	gettimeofday(&ctdb->last_recovery_started, NULL);
+
+	state = talloc(ctdb, struct recovery_callback_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->c    = talloc_steal(state, c);
+
+	ctdb_disable_monitoring(ctdb);
+
+	ret = ctdb_event_script_callback(ctdb, state,
+					 ctdb_start_recovery_callback, 
+					 state, false,
+					 CTDB_EVENT_START_RECOVERY,
+					 "%s", "");
+
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to start recovery\n"));
+		talloc_free(state);
+		return -1;
+	}
+
+	/* tell the control that we will be reply asynchronously */
+	*async_reply = true;
+	return 0;
+}
+
+/*
+ try to delete all these records as part of the vacuuming process
+ and return the records we failed to delete
+*/
+int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata)
+{
+	struct ctdb_marshall_buffer *reply = (struct ctdb_marshall_buffer *)indata.dptr;
+	struct ctdb_db_context *ctdb_db;
+	int i;
+	struct ctdb_rec_data *rec;
+	struct ctdb_marshall_buffer *records;
+
+	if (indata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
+		DEBUG(DEBUG_ERR,(__location__ " invalid data in try_delete_records\n"));
+		return -1;
+	}
+
+	ctdb_db = find_ctdb_db(ctdb, reply->db_id);
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", reply->db_id));
+		return -1;
+	}
+
+
+	DEBUG(DEBUG_DEBUG,("starting try_delete_records of %u records for dbid 0x%x\n",
+		 reply->count, reply->db_id));
+
+
+	/* create a blob to send back the records we couldnt delete */	
+	records = (struct ctdb_marshall_buffer *)
+			talloc_zero_size(outdata, 
+				    offsetof(struct ctdb_marshall_buffer, data));
+	if (records == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		return -1;
+	}
+	records->db_id = ctdb_db->db_id;
+
+
+	rec = (struct ctdb_rec_data *)&reply->data[0];
+	for (i=0;i<reply->count;i++) {
+		TDB_DATA key, data;
+
+		key.dptr = &rec->data[0];
+		key.dsize = rec->keylen;
+		data.dptr = &rec->data[key.dsize];
+		data.dsize = rec->datalen;
+
+		if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
+			DEBUG(DEBUG_CRIT,(__location__ " bad ltdb record in indata\n"));
+			return -1;
+		}
+
+		/* If we cant delete the record we must add it to the reply
+		   so the lmaster knows it may not purge this record
+		*/
+		if (delete_tdb_record(ctdb, ctdb_db, rec) != 0) {
+			size_t old_size;
+			struct ctdb_ltdb_header *hdr;
+
+			hdr = (struct ctdb_ltdb_header *)data.dptr;
+			data.dptr += sizeof(*hdr);
+			data.dsize -= sizeof(*hdr);
+
+			DEBUG(DEBUG_INFO, (__location__ " Failed to vacuum delete record with hash 0x%08x\n", ctdb_hash(&key)));
+
+			old_size = talloc_get_size(records);
+			records = talloc_realloc_size(outdata, records, old_size + rec->length);
+			if (records == NULL) {
+				DEBUG(DEBUG_ERR,(__location__ " Failed to expand\n"));
+				return -1;
+			}
+			records->count++;
+			memcpy(old_size+(uint8_t *)records, rec, rec->length);
+		} 
+
+		rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+	}	    
+
+
+	outdata->dptr = (uint8_t *)records;
+	outdata->dsize = talloc_get_size(records);
+
+	return 0;
+}
+
+/*
+  report capabilities
+ */
+int32_t ctdb_control_get_capabilities(struct ctdb_context *ctdb, TDB_DATA *outdata)
+{
+	uint32_t *capabilities = NULL;
+
+	capabilities = talloc(outdata, uint32_t);
+	CTDB_NO_MEMORY(ctdb, capabilities);
+	*capabilities = ctdb->capabilities;
+
+	outdata->dsize = sizeof(uint32_t);
+	outdata->dptr = (uint8_t *)capabilities;
+
+	return 0;	
+}
+
+static void ctdb_recd_ping_timeout(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
+{
+	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
+	uint32_t *count = talloc_get_type(ctdb->recd_ping_count, uint32_t);
+
+	DEBUG(DEBUG_ERR, ("Recovery daemon ping timeout. Count : %u\n", *count));
+
+	if (*count < ctdb->tunable.recd_ping_failcount) {
+		(*count)++;
+		event_add_timed(ctdb->ev, ctdb->recd_ping_count, 
+			timeval_current_ofs(ctdb->tunable.recd_ping_timeout, 0),
+			ctdb_recd_ping_timeout, ctdb);
+		return;
+	}
+
+	DEBUG(DEBUG_ERR, ("Final timeout for recovery daemon ping. Restarting recovery daemon. (This can be caused if the cluster filesystem has hung)\n"));
+
+	ctdb_stop_recoverd(ctdb);
+	ctdb_start_recoverd(ctdb);
+}
+
+/* The recovery daemon will ping us at regular intervals.
+   If we havent been pinged for a while we assume the recovery
+   daemon is inoperable and we shut down.
+*/
+int32_t ctdb_control_recd_ping(struct ctdb_context *ctdb)
+{
+	talloc_free(ctdb->recd_ping_count);
+
+	ctdb->recd_ping_count = talloc_zero(ctdb, uint32_t);
+	CTDB_NO_MEMORY(ctdb, ctdb->recd_ping_count);
+
+	if (ctdb->tunable.recd_ping_timeout != 0) {
+		event_add_timed(ctdb->ev, ctdb->recd_ping_count, 
+			timeval_current_ofs(ctdb->tunable.recd_ping_timeout, 0),
+			ctdb_recd_ping_timeout, ctdb);
+	}
+
+	return 0;
+}
+
+
+
+int32_t ctdb_control_set_recmaster(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata)
+{
+	CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
+
+	ctdb->recovery_master = ((uint32_t *)(&indata.dptr[0]))[0];
+	return 0;
+}
+
+
+struct stop_node_callback_state {
+	struct ctdb_req_control *c;
+};
+
+/*
+  called when the 'stopped' event script has finished
+ */
+static void ctdb_stop_node_callback(struct ctdb_context *ctdb, int status, void *p)
+{
+	struct stop_node_callback_state *state = talloc_get_type(p, struct stop_node_callback_state);
+
+	if (status != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " stopped event script failed (status %d)\n", status));
+		ctdb->nodes[ctdb->pnn]->flags &= ~NODE_FLAGS_STOPPED;
+		if (status == -ETIME) {
+			ctdb_ban_self(ctdb);
+		}
+	}
+
+	ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
+	talloc_free(state);
+}
+
+int32_t ctdb_control_stop_node(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply)
+{
+	int ret;
+	struct stop_node_callback_state *state;
+
+	DEBUG(DEBUG_INFO,(__location__ " Stopping node\n"));
+
+	state = talloc(ctdb, struct stop_node_callback_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->c    = talloc_steal(state, c);
+
+	ctdb_disable_monitoring(ctdb);
+
+	ret = ctdb_event_script_callback(ctdb, state,
+					 ctdb_stop_node_callback, 
+					 state, false,
+					 CTDB_EVENT_STOPPED, "%s", "");
+
+	if (ret != 0) {
+		ctdb_enable_monitoring(ctdb);
+
+		DEBUG(DEBUG_ERR,(__location__ " Failed to stop node\n"));
+		talloc_free(state);
+		return -1;
+	}
+
+	ctdb->nodes[ctdb->pnn]->flags |= NODE_FLAGS_STOPPED;
+
+	*async_reply = true;
+
+	return 0;
+}
+
+int32_t ctdb_control_continue_node(struct ctdb_context *ctdb)
+{
+	DEBUG(DEBUG_INFO,(__location__ " Continue node\n"));
+	ctdb->nodes[ctdb->pnn]->flags &= ~NODE_FLAGS_STOPPED;
+
+	return 0;
+}
+

Added: branches/ctdb/squeeze-backports/server/ctdb_recoverd.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_recoverd.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_recoverd.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,3643 @@
+/* 
+   ctdb recovery daemon
+
+   Copyright (C) Ronnie Sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/network.h"
+#include "system/wait.h"
+#include "popt.h"
+#include "cmdline.h"
+#include "../include/ctdb_client.h"
+#include "../include/ctdb_private.h"
+#include "db_wrap.h"
+#include "dlinklist.h"
+
+
+/* list of "ctdb ipreallocate" processes to call back when we have
+   finished the takeover run.
+*/
+struct ip_reallocate_list {
+	struct ip_reallocate_list *next;
+	struct rd_memdump_reply *rd;
+};
+
+struct ctdb_banning_state {
+	uint32_t count;
+	struct timeval last_reported_time;
+};
+
+/*
+  private state of recovery daemon
+ */
+struct ctdb_recoverd {
+	struct ctdb_context *ctdb;
+	uint32_t recmaster;
+	uint32_t num_active;
+	uint32_t num_connected;
+	uint32_t last_culprit_node;
+	struct ctdb_node_map *nodemap;
+	struct timeval priority_time;
+	bool need_takeover_run;
+	bool need_recovery;
+	uint32_t node_flags;
+	struct timed_event *send_election_te;
+	struct timed_event *election_timeout;
+	struct vacuum_info *vacuum_info;
+	TALLOC_CTX *ip_reallocate_ctx;
+	struct ip_reallocate_list *reallocate_callers;
+	TALLOC_CTX *ip_check_disable_ctx;
+	struct ctdb_control_get_ifaces *ifaces;
+};
+
+#define CONTROL_TIMEOUT() timeval_current_ofs(ctdb->tunable.recover_timeout, 0)
+#define MONITOR_TIMEOUT() timeval_current_ofs(ctdb->tunable.recover_interval, 0)
+
+static void ctdb_restart_recd(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data);
+
+/*
+  ban a node for a period of time
+ */
+static void ctdb_ban_node(struct ctdb_recoverd *rec, uint32_t pnn, uint32_t ban_time)
+{
+	int ret;
+	struct ctdb_context *ctdb = rec->ctdb;
+	struct ctdb_ban_time bantime;
+       
+	DEBUG(DEBUG_NOTICE,("Banning node %u for %u seconds\n", pnn, ban_time));
+
+	if (!ctdb_validate_pnn(ctdb, pnn)) {
+		DEBUG(DEBUG_ERR,("Bad pnn %u in ctdb_ban_node\n", pnn));
+		return;
+	}
+
+	bantime.pnn  = pnn;
+	bantime.time = ban_time;
+
+	ret = ctdb_ctrl_set_ban(ctdb, CONTROL_TIMEOUT(), pnn, &bantime);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to ban node %d\n", pnn));
+		return;
+	}
+
+}
+
+enum monitor_result { MONITOR_OK, MONITOR_RECOVERY_NEEDED, MONITOR_ELECTION_NEEDED, MONITOR_FAILED};
+
+
+/*
+  run the "recovered" eventscript on all nodes
+ */
+static int run_recovered_eventscript(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, const char *caller)
+{
+	TALLOC_CTX *tmp_ctx;
+	uint32_t *nodes;
+
+	tmp_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY(ctdb, tmp_ctx);
+
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_END_RECOVERY,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, tdb_null,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'recovered' event when called from %s\n", caller));
+
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  remember the trouble maker
+ */
+static void ctdb_set_culprit_count(struct ctdb_recoverd *rec, uint32_t culprit, uint32_t count)
+{
+	struct ctdb_context *ctdb = talloc_get_type(rec->ctdb, struct ctdb_context);
+	struct ctdb_banning_state *ban_state;
+
+	if (culprit > ctdb->num_nodes) {
+		DEBUG(DEBUG_ERR,("Trying to set culprit %d but num_nodes is %d\n", culprit, ctdb->num_nodes));
+		return;
+	}
+
+	if (ctdb->nodes[culprit]->ban_state == NULL) {
+		ctdb->nodes[culprit]->ban_state = talloc_zero(ctdb->nodes[culprit], struct ctdb_banning_state);
+		CTDB_NO_MEMORY_VOID(ctdb, ctdb->nodes[culprit]->ban_state);
+
+		
+	}
+	ban_state = ctdb->nodes[culprit]->ban_state;
+	if (timeval_elapsed(&ban_state->last_reported_time) > ctdb->tunable.recovery_grace_period) {
+		/* this was the first time in a long while this node
+		   misbehaved so we will forgive any old transgressions.
+		*/
+		ban_state->count = 0;
+	}
+
+	ban_state->count += count;
+	ban_state->last_reported_time = timeval_current();
+	rec->last_culprit_node = culprit;
+}
+
+/*
+  remember the trouble maker
+ */
+static void ctdb_set_culprit(struct ctdb_recoverd *rec, uint32_t culprit)
+{
+	ctdb_set_culprit_count(rec, culprit, 1);
+}
+
+
+/* this callback is called for every node that failed to execute the
+   start recovery event
+*/
+static void startrecovery_fail_callback(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(callback_data, struct ctdb_recoverd);
+
+	DEBUG(DEBUG_ERR, (__location__ " Node %u failed the startrecovery event. Setting it as recovery fail culprit\n", node_pnn));
+
+	ctdb_set_culprit(rec, node_pnn);
+}
+
+/*
+  run the "startrecovery" eventscript on all nodes
+ */
+static int run_startrecovery_eventscript(struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap)
+{
+	TALLOC_CTX *tmp_ctx;
+	uint32_t *nodes;
+	struct ctdb_context *ctdb = rec->ctdb;
+
+	tmp_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY(ctdb, tmp_ctx);
+
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_START_RECOVERY,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, tdb_null,
+					NULL,
+					startrecovery_fail_callback,
+					rec) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'startrecovery' event. Recovery failed.\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+static void async_getcap_callback(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data)
+{
+	if ( (outdata.dsize != sizeof(uint32_t)) || (outdata.dptr == NULL) ) {
+		DEBUG(DEBUG_ERR, (__location__ " Invalid length/pointer for getcap callback : %u %p\n",  (unsigned)outdata.dsize, outdata.dptr));
+		return;
+	}
+	if (node_pnn < ctdb->num_nodes) {
+		ctdb->nodes[node_pnn]->capabilities = *((uint32_t *)outdata.dptr);
+	}
+}
+
+/*
+  update the node capabilities for all connected nodes
+ */
+static int update_capabilities(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap)
+{
+	uint32_t *nodes;
+	TALLOC_CTX *tmp_ctx;
+
+	tmp_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY(ctdb, tmp_ctx);
+
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_GET_CAPABILITIES,
+					nodes, 0,
+					CONTROL_TIMEOUT(),
+					false, tdb_null,
+					async_getcap_callback, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to read node capabilities.\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+static void set_recmode_fail_callback(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(callback_data, struct ctdb_recoverd);
+
+	DEBUG(DEBUG_ERR,("Failed to freeze node %u during recovery. Set it as ban culprit for %d credits\n", node_pnn, rec->nodemap->num));
+	ctdb_set_culprit_count(rec, node_pnn, rec->nodemap->num);
+}
+
+static void transaction_start_fail_callback(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(callback_data, struct ctdb_recoverd);
+
+	DEBUG(DEBUG_ERR,("Failed to start recovery transaction on node %u. Set it as ban culprit for %d credits\n", node_pnn, rec->nodemap->num));
+	ctdb_set_culprit_count(rec, node_pnn, rec->nodemap->num);
+}
+
+/*
+  change recovery mode on all nodes
+ */
+static int set_recovery_mode(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap, uint32_t rec_mode)
+{
+	TDB_DATA data;
+	uint32_t *nodes;
+	TALLOC_CTX *tmp_ctx;
+
+	tmp_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY(ctdb, tmp_ctx);
+
+	/* freeze all nodes */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (rec_mode == CTDB_RECOVERY_ACTIVE) {
+		int i;
+
+		for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+			if (ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE,
+						nodes, i,
+						CONTROL_TIMEOUT(),
+						false, tdb_null,
+						NULL,
+						set_recmode_fail_callback,
+						rec) != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Unable to freeze nodes. Recovery failed.\n"));
+				talloc_free(tmp_ctx);
+				return -1;
+			}
+		}
+	}
+
+
+	data.dsize = sizeof(uint32_t);
+	data.dptr = (unsigned char *)&rec_mode;
+
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_SET_RECMODE,
+					nodes, 0,
+					CONTROL_TIMEOUT(),
+					false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode. Recovery failed.\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  change recovery master on all node
+ */
+static int set_recovery_master(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, uint32_t pnn)
+{
+	TDB_DATA data;
+	TALLOC_CTX *tmp_ctx;
+	uint32_t *nodes;
+
+	tmp_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY(ctdb, tmp_ctx);
+
+	data.dsize = sizeof(uint32_t);
+	data.dptr = (unsigned char *)&pnn;
+
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_SET_RECMASTER,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set recmaster. Recovery failed.\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/* update all remote nodes to use the same db priority that we have
+   this can fail if the remove node has not yet been upgraded to 
+   support this function, so we always return success and never fail
+   a recovery if this call fails.
+*/
+static int update_db_priority_on_remote_nodes(struct ctdb_context *ctdb,
+	struct ctdb_node_map *nodemap, 
+	uint32_t pnn, struct ctdb_dbid_map *dbmap, TALLOC_CTX *mem_ctx)
+{
+	int db;
+	uint32_t *nodes;
+
+	nodes = list_of_active_nodes(ctdb, nodemap, mem_ctx, true);
+
+	/* step through all local databases */
+	for (db=0; db<dbmap->num;db++) {
+		TDB_DATA data;
+		struct ctdb_db_priority db_prio;
+		int ret;
+
+		db_prio.db_id     = dbmap->dbs[db].dbid;
+		ret = ctdb_ctrl_get_db_priority(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, dbmap->dbs[db].dbid, &db_prio.priority);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to read database priority from local node for db 0x%08x\n", dbmap->dbs[db].dbid));
+			continue;
+		}
+
+		DEBUG(DEBUG_INFO,("Update DB priority for db 0x%08x to %u\n", dbmap->dbs[db].dbid, db_prio.priority)); 
+
+		data.dptr  = (uint8_t *)&db_prio;
+		data.dsize = sizeof(db_prio);
+
+		if (ctdb_client_async_control(ctdb,
+					CTDB_CONTROL_SET_DB_PRIORITY,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to set DB priority for 0x%08x\n", db_prio.db_id));
+		}
+	}
+
+	return 0;
+}			
+
+/*
+  ensure all other nodes have attached to any databases that we have
+ */
+static int create_missing_remote_databases(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, 
+					   uint32_t pnn, struct ctdb_dbid_map *dbmap, TALLOC_CTX *mem_ctx)
+{
+	int i, j, db, ret;
+	struct ctdb_dbid_map *remote_dbmap;
+
+	/* verify that all other nodes have all our databases */
+	for (j=0; j<nodemap->num; j++) {
+		/* we dont need to ourself ourselves */
+		if (nodemap->nodes[j].pnn == pnn) {
+			continue;
+		}
+		/* dont check nodes that are unavailable */
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+
+		ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
+					 mem_ctx, &remote_dbmap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to get dbids from node %u\n", pnn));
+			return -1;
+		}
+
+		/* step through all local databases */
+		for (db=0; db<dbmap->num;db++) {
+			const char *name;
+
+
+			for (i=0;i<remote_dbmap->num;i++) {
+				if (dbmap->dbs[db].dbid == remote_dbmap->dbs[i].dbid) {
+					break;
+				}
+			}
+			/* the remote node already have this database */
+			if (i!=remote_dbmap->num) {
+				continue;
+			}
+			/* ok so we need to create this database */
+			ctdb_ctrl_getdbname(ctdb, CONTROL_TIMEOUT(), pnn, dbmap->dbs[db].dbid, 
+					    mem_ctx, &name);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Unable to get dbname from node %u\n", pnn));
+				return -1;
+			}
+			ctdb_ctrl_createdb(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
+					   mem_ctx, name,
+					   dbmap->dbs[db].flags & CTDB_DB_FLAGS_PERSISTENT);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Unable to create remote db:%s\n", name));
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+  ensure we are attached to any databases that anyone else is attached to
+ */
+static int create_missing_local_databases(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, 
+					  uint32_t pnn, struct ctdb_dbid_map **dbmap, TALLOC_CTX *mem_ctx)
+{
+	int i, j, db, ret;
+	struct ctdb_dbid_map *remote_dbmap;
+
+	/* verify that we have all database any other node has */
+	for (j=0; j<nodemap->num; j++) {
+		/* we dont need to ourself ourselves */
+		if (nodemap->nodes[j].pnn == pnn) {
+			continue;
+		}
+		/* dont check nodes that are unavailable */
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+
+		ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
+					 mem_ctx, &remote_dbmap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to get dbids from node %u\n", pnn));
+			return -1;
+		}
+
+		/* step through all databases on the remote node */
+		for (db=0; db<remote_dbmap->num;db++) {
+			const char *name;
+
+			for (i=0;i<(*dbmap)->num;i++) {
+				if (remote_dbmap->dbs[db].dbid == (*dbmap)->dbs[i].dbid) {
+					break;
+				}
+			}
+			/* we already have this db locally */
+			if (i!=(*dbmap)->num) {
+				continue;
+			}
+			/* ok so we need to create this database and
+			   rebuild dbmap
+			 */
+			ctdb_ctrl_getdbname(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
+					    remote_dbmap->dbs[db].dbid, mem_ctx, &name);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Unable to get dbname from node %u\n", 
+					  nodemap->nodes[j].pnn));
+				return -1;
+			}
+			ctdb_ctrl_createdb(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, name, 
+					   remote_dbmap->dbs[db].flags & CTDB_DB_FLAGS_PERSISTENT);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Unable to create local db:%s\n", name));
+				return -1;
+			}
+			ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, dbmap);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Unable to reread dbmap on node %u\n", pnn));
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+  pull the remote database contents from one node into the recdb
+ */
+static int pull_one_remote_database(struct ctdb_context *ctdb, uint32_t srcnode, 
+				    struct tdb_wrap *recdb, uint32_t dbid,
+				    bool persistent)
+{
+	int ret;
+	TDB_DATA outdata;
+	struct ctdb_marshall_buffer *reply;
+	struct ctdb_rec_data *rec;
+	int i;
+	TALLOC_CTX *tmp_ctx = talloc_new(recdb);
+
+	ret = ctdb_ctrl_pulldb(ctdb, srcnode, dbid, CTDB_LMASTER_ANY, tmp_ctx,
+			       CONTROL_TIMEOUT(), &outdata);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Unable to copy db from node %u\n", srcnode));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	reply = (struct ctdb_marshall_buffer *)outdata.dptr;
+
+	if (outdata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
+		DEBUG(DEBUG_ERR,(__location__ " invalid data in pulldb reply\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	
+	rec = (struct ctdb_rec_data *)&reply->data[0];
+	
+	for (i=0;
+	     i<reply->count;
+	     rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec), i++) {
+		TDB_DATA key, data;
+		struct ctdb_ltdb_header *hdr;
+		TDB_DATA existing;
+		
+		key.dptr = &rec->data[0];
+		key.dsize = rec->keylen;
+		data.dptr = &rec->data[key.dsize];
+		data.dsize = rec->datalen;
+		
+		hdr = (struct ctdb_ltdb_header *)data.dptr;
+
+		if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
+			DEBUG(DEBUG_CRIT,(__location__ " bad ltdb record\n"));
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+
+		/* fetch the existing record, if any */
+		existing = tdb_fetch(recdb->tdb, key);
+		
+		if (existing.dptr != NULL) {
+			struct ctdb_ltdb_header header;
+			if (existing.dsize < sizeof(struct ctdb_ltdb_header)) {
+				DEBUG(DEBUG_CRIT,(__location__ " Bad record size %u from node %u\n", 
+					 (unsigned)existing.dsize, srcnode));
+				free(existing.dptr);
+				talloc_free(tmp_ctx);
+				return -1;
+			}
+			header = *(struct ctdb_ltdb_header *)existing.dptr;
+			free(existing.dptr);
+			if (!(header.rsn < hdr->rsn ||
+			      (header.dmaster != ctdb->recovery_master && header.rsn == hdr->rsn))) {
+				continue;
+			}
+		}
+		
+		if (tdb_store(recdb->tdb, key, data, TDB_REPLACE) != 0) {
+			DEBUG(DEBUG_CRIT,(__location__ " Failed to store record\n"));
+			talloc_free(tmp_ctx);
+			return -1;				
+		}
+	}
+
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+/*
+  pull all the remote database contents into the recdb
+ */
+static int pull_remote_database(struct ctdb_context *ctdb,
+				struct ctdb_recoverd *rec, 
+				struct ctdb_node_map *nodemap, 
+				struct tdb_wrap *recdb, uint32_t dbid,
+				bool persistent)
+{
+	int j;
+
+	/* pull all records from all other nodes across onto this node
+	   (this merges based on rsn)
+	*/
+	for (j=0; j<nodemap->num; j++) {
+		/* dont merge from nodes that are unavailable */
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (pull_one_remote_database(ctdb, nodemap->nodes[j].pnn, recdb, dbid, persistent) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to pull remote database from node %u\n", 
+				 nodemap->nodes[j].pnn));
+			ctdb_set_culprit_count(rec, nodemap->nodes[j].pnn, nodemap->num);
+			return -1;
+		}
+	}
+	
+	return 0;
+}
+
+
+/*
+  update flags on all active nodes
+ */
+static int update_flags_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, uint32_t pnn, uint32_t flags)
+{
+	int ret;
+
+	ret = ctdb_ctrl_modflags(ctdb, CONTROL_TIMEOUT(), pnn, flags, ~flags);
+		if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to update nodeflags on remote nodes\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  ensure all nodes have the same vnnmap we do
+ */
+static int update_vnnmap_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, 
+				      uint32_t pnn, struct ctdb_vnn_map *vnnmap, TALLOC_CTX *mem_ctx)
+{
+	int j, ret;
+
+	/* push the new vnn map out to all the nodes */
+	for (j=0; j<nodemap->num; j++) {
+		/* dont push to nodes that are unavailable */
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+
+		ret = ctdb_ctrl_setvnnmap(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, mem_ctx, vnnmap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to set vnnmap for node %u\n", pnn));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+struct vacuum_info {
+	struct vacuum_info *next, *prev;
+	struct ctdb_recoverd *rec;
+	uint32_t srcnode;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_marshall_buffer *recs;
+	struct ctdb_rec_data *r;
+};
+
+static void vacuum_fetch_next(struct vacuum_info *v);
+
+/*
+  called when a vacuum fetch has completed - just free it and do the next one
+ */
+static void vacuum_fetch_callback(struct ctdb_client_call_state *state)
+{
+	struct vacuum_info *v = talloc_get_type(state->async.private_data, struct vacuum_info);
+	talloc_free(state);
+	vacuum_fetch_next(v);
+}
+
+
+/*
+  process the next element from the vacuum list
+*/
+static void vacuum_fetch_next(struct vacuum_info *v)
+{
+	struct ctdb_call call;
+	struct ctdb_rec_data *r;
+
+	while (v->recs->count) {
+		struct ctdb_client_call_state *state;
+		TDB_DATA data;
+		struct ctdb_ltdb_header *hdr;
+
+		ZERO_STRUCT(call);
+		call.call_id = CTDB_NULL_FUNC;
+		call.flags = CTDB_IMMEDIATE_MIGRATION;
+		call.flags |= CTDB_CALL_FLAG_VACUUM_MIGRATION;
+
+		r = v->r;
+		v->r = (struct ctdb_rec_data *)(r->length + (uint8_t *)r);
+		v->recs->count--;
+
+		call.key.dptr = &r->data[0];
+		call.key.dsize = r->keylen;
+
+		/* ensure we don't block this daemon - just skip a record if we can't get
+		   the chainlock */
+		if (tdb_chainlock_nonblock(v->ctdb_db->ltdb->tdb, call.key) != 0) {
+			continue;
+		}
+
+		data = tdb_fetch(v->ctdb_db->ltdb->tdb, call.key);
+		if (data.dptr == NULL) {
+			tdb_chainunlock(v->ctdb_db->ltdb->tdb, call.key);
+			continue;
+		}
+
+		if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
+			free(data.dptr);
+			tdb_chainunlock(v->ctdb_db->ltdb->tdb, call.key);
+			continue;
+		}
+		
+		hdr = (struct ctdb_ltdb_header *)data.dptr;
+		if (hdr->dmaster == v->rec->ctdb->pnn) {
+			/* its already local */
+			free(data.dptr);
+			tdb_chainunlock(v->ctdb_db->ltdb->tdb, call.key);
+			continue;
+		}
+
+		free(data.dptr);
+
+		state = ctdb_call_send(v->ctdb_db, &call);
+		tdb_chainunlock(v->ctdb_db->ltdb->tdb, call.key);
+		if (state == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to setup vacuum fetch call\n"));
+			talloc_free(v);
+			return;
+		}
+		state->async.fn = vacuum_fetch_callback;
+		state->async.private_data = v;
+		return;
+	}
+
+	talloc_free(v);
+}
+
+
+/*
+  destroy a vacuum info structure
+ */
+static int vacuum_info_destructor(struct vacuum_info *v)
+{
+	DLIST_REMOVE(v->rec->vacuum_info, v);
+	return 0;
+}
+
+
+/*
+  handler for vacuum fetch
+*/
+static void vacuum_fetch_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+				 TDB_DATA data, void *private_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	struct ctdb_marshall_buffer *recs;
+	int ret, i;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	const char *name;
+	struct ctdb_dbid_map *dbmap=NULL;
+	bool persistent = false;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_rec_data *r;
+	uint32_t srcnode;
+	struct vacuum_info *v;
+
+	recs = (struct ctdb_marshall_buffer *)data.dptr;
+	r = (struct ctdb_rec_data *)&recs->data[0];
+
+	if (recs->count == 0) {
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	srcnode = r->reqid;
+
+	for (v=rec->vacuum_info;v;v=v->next) {
+		if (srcnode == v->srcnode && recs->db_id == v->ctdb_db->db_id) {
+			/* we're already working on records from this node */
+			talloc_free(tmp_ctx);
+			return;
+		}
+	}
+
+	/* work out if the database is persistent */
+	ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, tmp_ctx, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get dbids from local node\n"));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	for (i=0;i<dbmap->num;i++) {
+		if (dbmap->dbs[i].dbid == recs->db_id) {
+			persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
+			break;
+		}
+	}
+	if (i == dbmap->num) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to find db_id 0x%x on local node\n", recs->db_id));
+		talloc_free(tmp_ctx);
+		return;		
+	}
+
+	/* find the name of this database */
+	if (ctdb_ctrl_getdbname(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, recs->db_id, tmp_ctx, &name) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get name of db 0x%x\n", recs->db_id));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	/* attach to it */
+	ctdb_db = ctdb_attach(ctdb, CONTROL_TIMEOUT(), name, persistent, 0);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to attach to database '%s'\n", name));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	v = talloc_zero(rec, struct vacuum_info);
+	if (v == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Out of memory\n"));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	v->rec = rec;
+	v->srcnode = srcnode;
+	v->ctdb_db = ctdb_db;
+	v->recs = talloc_memdup(v, recs, data.dsize);
+	if (v->recs == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Out of memory\n"));
+		talloc_free(v);
+		talloc_free(tmp_ctx);
+		return;		
+	}
+	v->r = 	(struct ctdb_rec_data *)&v->recs->data[0];
+
+	DLIST_ADD(rec->vacuum_info, v);
+
+	talloc_set_destructor(v, vacuum_info_destructor);
+
+	vacuum_fetch_next(v);
+	talloc_free(tmp_ctx);
+}
+
+
+/*
+  called when ctdb_wait_timeout should finish
+ */
+static void ctdb_wait_handler(struct event_context *ev, struct timed_event *te, 
+			      struct timeval yt, void *p)
+{
+	uint32_t *timed_out = (uint32_t *)p;
+	(*timed_out) = 1;
+}
+
+/*
+  wait for a given number of seconds
+ */
+static void ctdb_wait_timeout(struct ctdb_context *ctdb, double secs)
+{
+	uint32_t timed_out = 0;
+	time_t usecs = (secs - (time_t)secs) * 1000000;
+	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(secs, usecs), ctdb_wait_handler, &timed_out);
+	while (!timed_out) {
+		event_loop_once(ctdb->ev);
+	}
+}
+
+/*
+  called when an election times out (ends)
+ */
+static void ctdb_election_timeout(struct event_context *ev, struct timed_event *te, 
+				  struct timeval t, void *p)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(p, struct ctdb_recoverd);
+	rec->election_timeout = NULL;
+	fast_start = false;
+
+	DEBUG(DEBUG_WARNING,(__location__ " Election timed out\n"));
+}
+
+
+/*
+  wait for an election to finish. It finished election_timeout seconds after
+  the last election packet is received
+ */
+static void ctdb_wait_election(struct ctdb_recoverd *rec)
+{
+	struct ctdb_context *ctdb = rec->ctdb;
+	while (rec->election_timeout) {
+		event_loop_once(ctdb->ev);
+	}
+}
+
+/*
+  Update our local flags from all remote connected nodes. 
+  This is only run when we are or we belive we are the recovery master
+ */
+static int update_local_flags(struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap)
+{
+	int j;
+	struct ctdb_context *ctdb = rec->ctdb;
+	TALLOC_CTX *mem_ctx = talloc_new(ctdb);
+
+	/* get the nodemap for all active remote nodes and verify
+	   they are the same as for this node
+	 */
+	for (j=0; j<nodemap->num; j++) {
+		struct ctdb_node_map *remote_nodemap=NULL;
+		int ret;
+
+		if (nodemap->nodes[j].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+		if (nodemap->nodes[j].pnn == ctdb->pnn) {
+			continue;
+		}
+
+		ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
+					   mem_ctx, &remote_nodemap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from remote node %u\n", 
+				  nodemap->nodes[j].pnn));
+			ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+			talloc_free(mem_ctx);
+			return MONITOR_FAILED;
+		}
+		if (nodemap->nodes[j].flags != remote_nodemap->nodes[j].flags) {
+			/* We should tell our daemon about this so it
+			   updates its flags or else we will log the same 
+			   message again in the next iteration of recovery.
+			   Since we are the recovery master we can just as
+			   well update the flags on all nodes.
+			*/
+			ret = ctdb_ctrl_modflags(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, nodemap->nodes[j].flags, ~nodemap->nodes[j].flags);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Unable to update nodeflags on remote nodes\n"));
+				return -1;
+			}
+
+			/* Update our local copy of the flags in the recovery
+			   daemon.
+			*/
+			DEBUG(DEBUG_NOTICE,("Remote node %u had flags 0x%x, local had 0x%x - updating local\n",
+				 nodemap->nodes[j].pnn, remote_nodemap->nodes[j].flags,
+				 nodemap->nodes[j].flags));
+			nodemap->nodes[j].flags = remote_nodemap->nodes[j].flags;
+		}
+		talloc_free(remote_nodemap);
+	}
+	talloc_free(mem_ctx);
+	return MONITOR_OK;
+}
+
+
+/* Create a new random generation ip. 
+   The generation id can not be the INVALID_GENERATION id
+*/
+static uint32_t new_generation(void)
+{
+	uint32_t generation;
+
+	while (1) {
+		generation = random();
+
+		if (generation != INVALID_GENERATION) {
+			break;
+		}
+	}
+
+	return generation;
+}
+
+
+/*
+  create a temporary working database
+ */
+static struct tdb_wrap *create_recdb(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx)
+{
+	char *name;
+	struct tdb_wrap *recdb;
+	unsigned tdb_flags;
+
+	/* open up the temporary recovery database */
+	name = talloc_asprintf(mem_ctx, "%s/recdb.tdb.%u",
+			       ctdb->db_directory_state,
+			       ctdb->pnn);
+	if (name == NULL) {
+		return NULL;
+	}
+	unlink(name);
+
+	tdb_flags = TDB_NOLOCK;
+	if (ctdb->valgrinding) {
+		tdb_flags |= TDB_NOMMAP;
+	}
+	tdb_flags |= TDB_DISALLOW_NESTING;
+
+	recdb = tdb_wrap_open(mem_ctx, name, ctdb->tunable.database_hash_size, 
+			      tdb_flags, O_RDWR|O_CREAT|O_EXCL, 0600);
+	if (recdb == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to create temp recovery database '%s'\n", name));
+	}
+
+	talloc_free(name);
+
+	return recdb;
+}
+
+
+/* 
+   a traverse function for pulling all relevent records from recdb
+ */
+struct recdb_data {
+	struct ctdb_context *ctdb;
+	struct ctdb_marshall_buffer *recdata;
+	uint32_t len;
+	bool failed;
+	bool persistent;
+};
+
+static int traverse_recdb(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *p)
+{
+	struct recdb_data *params = (struct recdb_data *)p;
+	struct ctdb_rec_data *rec;
+	struct ctdb_ltdb_header *hdr;
+
+	/* skip empty records */
+	if (data.dsize <= sizeof(struct ctdb_ltdb_header)) {
+		return 0;
+	}
+
+	/* update the dmaster field to point to us */
+	hdr = (struct ctdb_ltdb_header *)data.dptr;
+	if (!params->persistent) {
+		hdr->dmaster = params->ctdb->pnn;
+		hdr->flags |= CTDB_REC_FLAG_MIGRATED_WITH_DATA;
+	}
+
+	/* add the record to the blob ready to send to the nodes */
+	rec = ctdb_marshall_record(params->recdata, 0, key, NULL, data);
+	if (rec == NULL) {
+		params->failed = true;
+		return -1;
+	}
+	params->recdata = talloc_realloc_size(NULL, params->recdata, rec->length + params->len);
+	if (params->recdata == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to expand recdata to %u (%u records)\n", 
+			 rec->length + params->len, params->recdata->count));
+		params->failed = true;
+		return -1;
+	}
+	params->recdata->count++;
+	memcpy(params->len+(uint8_t *)params->recdata, rec, rec->length);
+	params->len += rec->length;
+	talloc_free(rec);
+
+	return 0;
+}
+
+/*
+  push the recdb database out to all nodes
+ */
+static int push_recdb_database(struct ctdb_context *ctdb, uint32_t dbid,
+			       bool persistent,
+			       struct tdb_wrap *recdb, struct ctdb_node_map *nodemap)
+{
+	struct recdb_data params;
+	struct ctdb_marshall_buffer *recdata;
+	TDB_DATA outdata;
+	TALLOC_CTX *tmp_ctx;
+	uint32_t *nodes;
+
+	tmp_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY(ctdb, tmp_ctx);
+
+	recdata = talloc_zero(recdb, struct ctdb_marshall_buffer);
+	CTDB_NO_MEMORY(ctdb, recdata);
+
+	recdata->db_id = dbid;
+
+	params.ctdb = ctdb;
+	params.recdata = recdata;
+	params.len = offsetof(struct ctdb_marshall_buffer, data);
+	params.failed = false;
+	params.persistent = persistent;
+
+	if (tdb_traverse_read(recdb->tdb, traverse_recdb, &params) == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to traverse recdb database\n"));
+		talloc_free(params.recdata);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (params.failed) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to traverse recdb database\n"));
+		talloc_free(params.recdata);
+		talloc_free(tmp_ctx);
+		return -1;		
+	}
+
+	recdata = params.recdata;
+
+	outdata.dptr = (void *)recdata;
+	outdata.dsize = params.len;
+
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_PUSH_DB,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, outdata,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to push recdb records to nodes for db 0x%x\n", dbid));
+		talloc_free(recdata);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - pushed remote database 0x%x of size %u\n", 
+		  dbid, recdata->count));
+
+	talloc_free(recdata);
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+
+/*
+  go through a full recovery on one database 
+ */
+static int recover_database(struct ctdb_recoverd *rec, 
+			    TALLOC_CTX *mem_ctx,
+			    uint32_t dbid,
+			    bool persistent,
+			    uint32_t pnn, 
+			    struct ctdb_node_map *nodemap,
+			    uint32_t transaction_id)
+{
+	struct tdb_wrap *recdb;
+	int ret;
+	struct ctdb_context *ctdb = rec->ctdb;
+	TDB_DATA data;
+	struct ctdb_control_wipe_database w;
+	uint32_t *nodes;
+
+	recdb = create_recdb(ctdb, mem_ctx);
+	if (recdb == NULL) {
+		return -1;
+	}
+
+	/* pull all remote databases onto the recdb */
+	ret = pull_remote_database(ctdb, rec, nodemap, recdb, dbid, persistent);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to pull remote database 0x%x\n", dbid));
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - pulled remote database 0x%x\n", dbid));
+
+	/* wipe all the remote databases. This is safe as we are in a transaction */
+	w.db_id = dbid;
+	w.transaction_id = transaction_id;
+
+	data.dptr = (void *)&w;
+	data.dsize = sizeof(w);
+
+	nodes = list_of_active_nodes(ctdb, nodemap, recdb, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_WIPE_DATABASE,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to wipe database. Recovery failed.\n"));
+		talloc_free(recdb);
+		return -1;
+	}
+	
+	/* push out the correct database. This sets the dmaster and skips 
+	   the empty records */
+	ret = push_recdb_database(ctdb, dbid, persistent, recdb, nodemap);
+	if (ret != 0) {
+		talloc_free(recdb);
+		return -1;
+	}
+
+	/* all done with this database */
+	talloc_free(recdb);
+
+	return 0;
+}
+
+/*
+  reload the nodes file 
+*/
+static void reload_nodes_file(struct ctdb_context *ctdb)
+{
+	ctdb->nodes = NULL;
+	ctdb_load_nodes_file(ctdb);
+}
+
+static int ctdb_reload_remote_public_ips(struct ctdb_context *ctdb,
+					 struct ctdb_recoverd *rec,
+					 struct ctdb_node_map *nodemap,
+					 uint32_t *culprit)
+{
+	int j;
+	int ret;
+
+	if (ctdb->num_nodes != nodemap->num) {
+		DEBUG(DEBUG_ERR, (__location__ " ctdb->num_nodes (%d) != nodemap->num (%d) invalid param\n",
+				  ctdb->num_nodes, nodemap->num));
+		if (culprit) {
+			*culprit = ctdb->pnn;
+		}
+		return -1;
+	}
+
+	for (j=0; j<nodemap->num; j++) {
+		/* release any existing data */
+		if (ctdb->nodes[j]->known_public_ips) {
+			talloc_free(ctdb->nodes[j]->known_public_ips);
+			ctdb->nodes[j]->known_public_ips = NULL;
+		}
+		if (ctdb->nodes[j]->available_public_ips) {
+			talloc_free(ctdb->nodes[j]->available_public_ips);
+			ctdb->nodes[j]->available_public_ips = NULL;
+		}
+
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+
+		/* grab a new shiny list of public ips from the node */
+		ret = ctdb_ctrl_get_public_ips_flags(ctdb,
+					CONTROL_TIMEOUT(),
+					ctdb->nodes[j]->pnn,
+					ctdb->nodes,
+					0,
+					&ctdb->nodes[j]->known_public_ips);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to read known public ips from node : %u\n",
+				ctdb->nodes[j]->pnn));
+			if (culprit) {
+				*culprit = ctdb->nodes[j]->pnn;
+			}
+			return -1;
+		}
+
+		if (ctdb->tunable.disable_ip_failover == 0) {
+			if (rec->ip_check_disable_ctx == NULL) {
+				if (verify_remote_ip_allocation(ctdb, ctdb->nodes[j]->known_public_ips)) {
+					DEBUG(DEBUG_ERR,("Node %d has inconsistent public ip allocation and needs update.\n", ctdb->nodes[j]->pnn));
+					rec->need_takeover_run = true;
+				}
+			}
+		}
+
+		/* grab a new shiny list of public ips from the node */
+		ret = ctdb_ctrl_get_public_ips_flags(ctdb,
+					CONTROL_TIMEOUT(),
+					ctdb->nodes[j]->pnn,
+					ctdb->nodes,
+					CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE,
+					&ctdb->nodes[j]->available_public_ips);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to read available public ips from node : %u\n",
+				ctdb->nodes[j]->pnn));
+			if (culprit) {
+				*culprit = ctdb->nodes[j]->pnn;
+			}
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* when we start a recovery, make sure all nodes use the same reclock file
+   setting
+*/
+static int sync_recovery_lock_file_across_cluster(struct ctdb_recoverd *rec)
+{
+	struct ctdb_context *ctdb = rec->ctdb;
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	TDB_DATA data;
+	uint32_t *nodes;
+
+	if (ctdb->recovery_lock_file == NULL) {
+		data.dptr  = NULL;
+		data.dsize = 0;
+	} else {
+		data.dsize = strlen(ctdb->recovery_lock_file) + 1;
+		data.dptr  = (uint8_t *)ctdb->recovery_lock_file;
+	}
+
+	nodes = list_of_active_nodes(ctdb, rec->nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_SET_RECLOCK_FILE,
+					nodes, 0,
+					CONTROL_TIMEOUT(),
+					false, data,
+					NULL, NULL,
+					rec) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to sync reclock file settings\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+
+/*
+  we are the recmaster, and recovery is needed - start a recovery run
+ */
+static int do_recovery(struct ctdb_recoverd *rec, 
+		       TALLOC_CTX *mem_ctx, uint32_t pnn,
+		       struct ctdb_node_map *nodemap, struct ctdb_vnn_map *vnnmap)
+{
+	struct ctdb_context *ctdb = rec->ctdb;
+	int i, j, ret;
+	uint32_t generation;
+	struct ctdb_dbid_map *dbmap;
+	TDB_DATA data;
+	uint32_t *nodes;
+	struct timeval start_time;
+	uint32_t culprit = (uint32_t)-1;
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Starting do_recovery\n"));
+
+	/* if recovery fails, force it again */
+	rec->need_recovery = true;
+
+	for (i=0; i<ctdb->num_nodes; i++) {
+		struct ctdb_banning_state *ban_state;
+
+		if (ctdb->nodes[i]->ban_state == NULL) {
+			continue;
+		}
+		ban_state = (struct ctdb_banning_state *)ctdb->nodes[i]->ban_state;
+		if (ban_state->count < 2*ctdb->num_nodes) {
+			continue;
+		}
+		DEBUG(DEBUG_NOTICE,("Node %u has caused %u recoveries recently - banning it for %u seconds\n",
+			ctdb->nodes[i]->pnn, ban_state->count,
+			ctdb->tunable.recovery_ban_period));
+		ctdb_ban_node(rec, ctdb->nodes[i]->pnn, ctdb->tunable.recovery_ban_period);
+		ban_state->count = 0;
+	}
+
+
+        if (ctdb->tunable.verify_recovery_lock != 0) {
+		DEBUG(DEBUG_ERR,("Taking out recovery lock from recovery daemon\n"));
+		start_time = timeval_current();
+		if (!ctdb_recovery_lock(ctdb, true)) {
+			DEBUG(DEBUG_ERR,("Unable to get recovery lock - aborting recovery "
+					 "and ban ourself for %u seconds\n",
+					 ctdb->tunable.recovery_ban_period));
+			ctdb_ban_node(rec, pnn, ctdb->tunable.recovery_ban_period);
+			return -1;
+		}
+		ctdb_ctrl_report_recd_lock_latency(ctdb, CONTROL_TIMEOUT(), timeval_elapsed(&start_time));
+		DEBUG(DEBUG_NOTICE,("Recovery lock taken successfully by recovery daemon\n"));
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery initiated due to problem with node %u\n", rec->last_culprit_node));
+
+	/* get a list of all databases */
+	ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get dbids from node :%u\n", pnn));
+		return -1;
+	}
+
+	/* we do the db creation before we set the recovery mode, so the freeze happens
+	   on all databases we will be dealing with. */
+
+	/* verify that we have all the databases any other node has */
+	ret = create_missing_local_databases(ctdb, nodemap, pnn, &dbmap, mem_ctx);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to create missing local databases\n"));
+		return -1;
+	}
+
+	/* verify that all other nodes have all our databases */
+	ret = create_missing_remote_databases(ctdb, nodemap, pnn, dbmap, mem_ctx);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to create missing remote databases\n"));
+		return -1;
+	}
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - created remote databases\n"));
+
+	/* update the database priority for all remote databases */
+	ret = update_db_priority_on_remote_nodes(ctdb, nodemap, pnn, dbmap, mem_ctx);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set db priority on remote nodes\n"));
+	}
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated db priority for all databases\n"));
+
+
+	/* update all other nodes to use the same setting for reclock files
+	   as the local recovery master.
+	*/
+	sync_recovery_lock_file_across_cluster(rec);
+
+	/* set recovery mode to active on all nodes */
+	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to active on cluster\n"));
+		return -1;
+	}
+
+	/* execute the "startrecovery" event script on all nodes */
+	ret = run_startrecovery_eventscript(rec, nodemap);
+	if (ret!=0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'startrecovery' event on cluster\n"));
+		return -1;
+	}
+
+	/*
+	  update all nodes to have the same flags that we have
+	 */
+	for (i=0;i<nodemap->num;i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+
+		ret = update_flags_on_all_nodes(ctdb, nodemap, i, nodemap->nodes[i].flags);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to update flags on all nodes for node %d\n", i));
+			return -1;
+		}
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated flags\n"));
+
+	/* pick a new generation number */
+	generation = new_generation();
+
+	/* change the vnnmap on this node to use the new generation 
+	   number but not on any other nodes.
+	   this guarantees that if we abort the recovery prematurely
+	   for some reason (a node stops responding?)
+	   that we can just return immediately and we will reenter
+	   recovery shortly again.
+	   I.e. we deliberately leave the cluster with an inconsistent
+	   generation id to allow us to abort recovery at any stage and
+	   just restart it from scratch.
+	 */
+	vnnmap->generation = generation;
+	ret = ctdb_ctrl_setvnnmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, vnnmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set vnnmap for node %u\n", pnn));
+		return -1;
+	}
+
+	data.dptr = (void *)&generation;
+	data.dsize = sizeof(uint32_t);
+
+	nodes = list_of_active_nodes(ctdb, nodemap, mem_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_START,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, data,
+					NULL,
+					transaction_start_fail_callback,
+					rec) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to start transactions. Recovery failed.\n"));
+		if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_CANCEL,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, tdb_null,
+					NULL,
+					NULL,
+					NULL) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to cancel recovery transaction\n"));
+		}
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE,(__location__ " started transactions on all nodes\n"));
+
+	for (i=0;i<dbmap->num;i++) {
+		ret = recover_database(rec, mem_ctx,
+				       dbmap->dbs[i].dbid,
+				       dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT,
+				       pnn, nodemap, generation);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Failed to recover database 0x%x\n", dbmap->dbs[i].dbid));
+			return -1;
+		}
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - starting database commits\n"));
+
+	/* commit all the changes */
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_COMMIT,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to commit recovery changes. Recovery failed.\n"));
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - committed databases\n"));
+	
+
+	/* update the capabilities for all nodes */
+	ret = update_capabilities(ctdb, nodemap);
+	if (ret!=0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to update node capabilities.\n"));
+		return -1;
+	}
+
+	/* build a new vnn map with all the currently active and
+	   unbanned nodes */
+	generation = new_generation();
+	vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
+	CTDB_NO_MEMORY(ctdb, vnnmap);
+	vnnmap->generation = generation;
+	vnnmap->size = 0;
+	vnnmap->map = talloc_zero_array(vnnmap, uint32_t, vnnmap->size);
+	CTDB_NO_MEMORY(ctdb, vnnmap->map);
+	for (i=j=0;i<nodemap->num;i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (!(ctdb->nodes[i]->capabilities & CTDB_CAP_LMASTER)) {
+			/* this node can not be an lmaster */
+			DEBUG(DEBUG_DEBUG, ("Node %d cant be a LMASTER, skipping it\n", i));
+			continue;
+		}
+
+		vnnmap->size++;
+		vnnmap->map = talloc_realloc(vnnmap, vnnmap->map, uint32_t, vnnmap->size);
+		CTDB_NO_MEMORY(ctdb, vnnmap->map);
+		vnnmap->map[j++] = nodemap->nodes[i].pnn;
+
+	}
+	if (vnnmap->size == 0) {
+		DEBUG(DEBUG_NOTICE, ("No suitable lmasters found. Adding local node (recmaster) anyway.\n"));
+		vnnmap->size++;
+		vnnmap->map = talloc_realloc(vnnmap, vnnmap->map, uint32_t, vnnmap->size);
+		CTDB_NO_MEMORY(ctdb, vnnmap->map);
+		vnnmap->map[0] = pnn;
+	}	
+
+	/* update to the new vnnmap on all nodes */
+	ret = update_vnnmap_on_all_nodes(ctdb, nodemap, pnn, vnnmap, mem_ctx);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to update vnnmap on all nodes\n"));
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated vnnmap\n"));
+
+	/* update recmaster to point to us for all nodes */
+	ret = set_recovery_master(ctdb, nodemap, pnn);
+	if (ret!=0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery master\n"));
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated recmaster\n"));
+
+	/*
+	  update all nodes to have the same flags that we have
+	 */
+	for (i=0;i<nodemap->num;i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+
+		ret = update_flags_on_all_nodes(ctdb, nodemap, i, nodemap->nodes[i].flags);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to update flags on all nodes for node %d\n", i));
+			return -1;
+		}
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated flags\n"));
+
+	/* disable recovery mode */
+	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_NORMAL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to normal on cluster\n"));
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - disabled recovery mode\n"));
+
+	/*
+	  tell nodes to takeover their public IPs
+	 */
+	ret = ctdb_reload_remote_public_ips(ctdb, rec, nodemap, &culprit);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
+				 culprit));
+		rec->need_takeover_run = true;
+		return -1;
+	}
+	rec->need_takeover_run = false;
+	ret = ctdb_takeover_run(ctdb, nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to setup public takeover addresses. ctdb_takeover_run() failed.\n"));
+		rec->need_takeover_run = true;
+	}
+
+	/* execute the "recovered" event script on all nodes */
+	ret = run_recovered_eventscript(ctdb, nodemap, "do_recovery");
+	if (ret!=0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'recovered' event on cluster. Recovery process failed.\n"));
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery - finished the recovered event\n"));
+
+	/* send a message to all clients telling them that the cluster 
+	   has been reconfigured */
+	ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_RECONFIGURE, tdb_null);
+
+	DEBUG(DEBUG_NOTICE, (__location__ " Recovery complete\n"));
+
+	rec->need_recovery = false;
+
+	/* we managed to complete a full recovery, make sure to forgive
+	   any past sins by the nodes that could now participate in the
+	   recovery.
+	*/
+	DEBUG(DEBUG_ERR,("Resetting ban count to 0 for all nodes\n"));
+	for (i=0;i<nodemap->num;i++) {
+		struct ctdb_banning_state *ban_state;
+
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+
+		ban_state = (struct ctdb_banning_state *)ctdb->nodes[nodemap->nodes[i].pnn]->ban_state;
+		if (ban_state == NULL) {
+			continue;
+		}
+
+		ban_state->count = 0;
+	}
+
+
+	/* We just finished a recovery successfully. 
+	   We now wait for rerecovery_timeout before we allow 
+	   another recovery to take place.
+	*/
+	DEBUG(DEBUG_NOTICE, ("Just finished a recovery. New recoveries will now be supressed for the rerecovery timeout (%d seconds)\n", ctdb->tunable.rerecovery_timeout));
+	ctdb_wait_timeout(ctdb, ctdb->tunable.rerecovery_timeout);
+	DEBUG(DEBUG_NOTICE, ("The rerecovery timeout has elapsed. We now allow recoveries to trigger again.\n"));
+
+	return 0;
+}
+
+
+/*
+  elections are won by first checking the number of connected nodes, then
+  the priority time, then the pnn
+ */
+struct election_message {
+	uint32_t num_connected;
+	struct timeval priority_time;
+	uint32_t pnn;
+	uint32_t node_flags;
+};
+
+/*
+  form this nodes election data
+ */
+static void ctdb_election_data(struct ctdb_recoverd *rec, struct election_message *em)
+{
+	int ret, i;
+	struct ctdb_node_map *nodemap;
+	struct ctdb_context *ctdb = rec->ctdb;
+
+	ZERO_STRUCTP(em);
+
+	em->pnn = rec->ctdb->pnn;
+	em->priority_time = rec->priority_time;
+
+	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, rec, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " unable to get election data\n"));
+		return;
+	}
+
+	rec->node_flags = nodemap->nodes[ctdb->pnn].flags;
+	em->node_flags = rec->node_flags;
+
+	for (i=0;i<nodemap->num;i++) {
+		if (!(nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED)) {
+			em->num_connected++;
+		}
+	}
+
+	/* we shouldnt try to win this election if we cant be a recmaster */
+	if ((ctdb->capabilities & CTDB_CAP_RECMASTER) == 0) {
+		em->num_connected = 0;
+		em->priority_time = timeval_current();
+	}
+
+	talloc_free(nodemap);
+}
+
+/*
+  see if the given election data wins
+ */
+static bool ctdb_election_win(struct ctdb_recoverd *rec, struct election_message *em)
+{
+	struct election_message myem;
+	int cmp = 0;
+
+	ctdb_election_data(rec, &myem);
+
+	/* we cant win if we dont have the recmaster capability */
+	if ((rec->ctdb->capabilities & CTDB_CAP_RECMASTER) == 0) {
+		return false;
+	}
+
+	/* we cant win if we are banned */
+	if (rec->node_flags & NODE_FLAGS_BANNED) {
+		return false;
+	}	
+
+	/* we cant win if we are stopped */
+	if (rec->node_flags & NODE_FLAGS_STOPPED) {
+		return false;
+	}	
+
+	/* we will automatically win if the other node is banned */
+	if (em->node_flags & NODE_FLAGS_BANNED) {
+		return true;
+	}
+
+	/* we will automatically win if the other node is banned */
+	if (em->node_flags & NODE_FLAGS_STOPPED) {
+		return true;
+	}
+
+	/* try to use the most connected node */
+	if (cmp == 0) {
+		cmp = (int)myem.num_connected - (int)em->num_connected;
+	}
+
+	/* then the longest running node */
+	if (cmp == 0) {
+		cmp = timeval_compare(&em->priority_time, &myem.priority_time);
+	}
+
+	if (cmp == 0) {
+		cmp = (int)myem.pnn - (int)em->pnn;
+	}
+
+	return cmp > 0;
+}
+
+/*
+  send out an election request
+ */
+static int send_election_request(struct ctdb_recoverd *rec, uint32_t pnn, bool update_recmaster)
+{
+	int ret;
+	TDB_DATA election_data;
+	struct election_message emsg;
+	uint64_t srvid;
+	struct ctdb_context *ctdb = rec->ctdb;
+
+	srvid = CTDB_SRVID_RECOVERY;
+
+	ctdb_election_data(rec, &emsg);
+
+	election_data.dsize = sizeof(struct election_message);
+	election_data.dptr  = (unsigned char *)&emsg;
+
+
+	/* send an election message to all active nodes */
+	DEBUG(DEBUG_INFO,(__location__ " Send election request to all active nodes\n"));
+	ctdb_client_send_message(ctdb, CTDB_BROADCAST_ALL, srvid, election_data);
+
+
+	/* A new node that is already frozen has entered the cluster.
+	   The existing nodes are not frozen and dont need to be frozen
+	   until the election has ended and we start the actual recovery
+	*/
+	if (update_recmaster == true) {
+		/* first we assume we will win the election and set 
+		   recoverymaster to be ourself on the current node
+		 */
+		ret = ctdb_ctrl_setrecmaster(ctdb, CONTROL_TIMEOUT(), pnn, pnn);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " failed to send recmaster election request\n"));
+			return -1;
+		}
+	}
+
+
+	return 0;
+}
+
+/*
+  this function will unban all nodes in the cluster
+*/
+static void unban_all_nodes(struct ctdb_context *ctdb)
+{
+	int ret, i;
+	struct ctdb_node_map *nodemap;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	
+	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " failed to get nodemap to unban all nodes\n"));
+		return;
+	}
+
+	for (i=0;i<nodemap->num;i++) {
+		if ( (!(nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED))
+		  && (nodemap->nodes[i].flags & NODE_FLAGS_BANNED) ) {
+			ctdb_ctrl_modflags(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[i].pnn, 0, NODE_FLAGS_BANNED);
+		}
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+
+/*
+  we think we are winning the election - send a broadcast election request
+ */
+static void election_send_request(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(p, struct ctdb_recoverd);
+	int ret;
+
+	ret = send_election_request(rec, ctdb_get_pnn(rec->ctdb), false);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send election request!\n"));
+	}
+
+	talloc_free(rec->send_election_te);
+	rec->send_election_te = NULL;
+}
+
+/*
+  handler for memory dumps
+*/
+static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA *dump;
+	int ret;
+	struct rd_memdump_reply *rd;
+
+	if (data.dsize != sizeof(struct rd_memdump_reply)) {
+		DEBUG(DEBUG_ERR, (__location__ " Wrong size of return address.\n"));
+		talloc_free(tmp_ctx);
+		return;
+	}
+	rd = (struct rd_memdump_reply *)data.dptr;
+
+	dump = talloc_zero(tmp_ctx, TDB_DATA);
+	if (dump == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to allocate memory for memdump\n"));
+		talloc_free(tmp_ctx);
+		return;
+	}
+	ret = ctdb_dump_memory(ctdb, dump);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " ctdb_dump_memory() failed\n"));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+DEBUG(DEBUG_ERR, ("recovery master memory dump\n"));		
+
+	ret = ctdb_client_send_message(ctdb, rd->pnn, rd->srvid, *dump);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send rd memdump reply message\n"));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  handler for reload_nodes
+*/
+static void reload_nodes_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+
+	DEBUG(DEBUG_ERR, (__location__ " Reload nodes file from recovery daemon\n"));
+
+	reload_nodes_file(rec->ctdb);
+}
+
+
+static void reenable_ip_check(struct event_context *ev, struct timed_event *te, 
+			      struct timeval yt, void *p)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(p, struct ctdb_recoverd);
+
+	talloc_free(rec->ip_check_disable_ctx);
+	rec->ip_check_disable_ctx = NULL;
+}
+
+
+static void recd_update_ip_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	struct ctdb_public_ip *ip;
+
+	if (rec->recmaster != rec->ctdb->pnn) {
+		DEBUG(DEBUG_INFO,("Not recmaster, ignore update ip message\n"));
+		return;
+	}
+
+	if (data.dsize != sizeof(struct ctdb_public_ip)) {
+		DEBUG(DEBUG_ERR,(__location__ " Incorrect size of recd update ip message. Was %zd but expected %zd bytes\n", data.dsize, sizeof(struct ctdb_public_ip)));
+		return;
+	}
+
+	ip = (struct ctdb_public_ip *)data.dptr;
+
+	update_ip_assignment_tree(rec->ctdb, ip);
+}
+
+
+static void disable_ip_check_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	uint32_t timeout;
+
+	if (rec->ip_check_disable_ctx != NULL) {
+		talloc_free(rec->ip_check_disable_ctx);
+		rec->ip_check_disable_ctx = NULL;
+	}
+
+	if (data.dsize != sizeof(uint32_t)) {
+		DEBUG(DEBUG_ERR,(__location__ " Wrong size for data :%lu "
+				 "expexting %lu\n", (long unsigned)data.dsize,
+				 (long unsigned)sizeof(uint32_t)));
+		return;
+	}
+	if (data.dptr == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " No data recaived\n"));
+		return;
+	}
+
+	timeout = *((uint32_t *)data.dptr);
+	DEBUG(DEBUG_NOTICE,("Disabling ip check for %u seconds\n", timeout));
+
+	rec->ip_check_disable_ctx = talloc_new(rec);
+	CTDB_NO_MEMORY_VOID(ctdb, rec->ip_check_disable_ctx);
+
+	event_add_timed(ctdb->ev, rec->ip_check_disable_ctx, timeval_current_ofs(timeout, 0), reenable_ip_check, rec);
+}
+
+
+/*
+  handler for ip reallocate, just add it to the list of callers and 
+  handle this later in the monitor_cluster loop so we do not recurse
+  with other callers to takeover_run()
+*/
+static void ip_reallocate_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	struct ip_reallocate_list *caller;
+
+	if (data.dsize != sizeof(struct rd_memdump_reply)) {
+		DEBUG(DEBUG_ERR, (__location__ " Wrong size of return address.\n"));
+		return;
+	}
+
+	if (rec->ip_reallocate_ctx == NULL) {
+		rec->ip_reallocate_ctx = talloc_new(rec);
+		CTDB_NO_MEMORY_FATAL(ctdb, rec->ip_reallocate_ctx);
+	}
+
+	caller = talloc(rec->ip_reallocate_ctx, struct ip_reallocate_list);
+	CTDB_NO_MEMORY_FATAL(ctdb, caller);
+
+	caller->rd   = (struct rd_memdump_reply *)talloc_steal(caller, data.dptr);
+	caller->next = rec->reallocate_callers;
+	rec->reallocate_callers = caller;
+
+	return;
+}
+
+static void process_ipreallocate_requests(struct ctdb_context *ctdb, struct ctdb_recoverd *rec)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA result;
+	int32_t ret;
+	struct ip_reallocate_list *callers;
+	uint32_t culprit;
+
+	DEBUG(DEBUG_INFO, ("recovery master forced ip reallocation\n"));
+
+	/* update the list of public ips that a node can handle for
+	   all connected nodes
+	*/
+	ret = ctdb_reload_remote_public_ips(ctdb, rec, rec->nodemap, &culprit);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
+				 culprit));
+		rec->need_takeover_run = true;
+	}
+	if (ret == 0) {
+		ret = ctdb_takeover_run(ctdb, rec->nodemap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to reallocate addresses: ctdb_takeover_run() failed.\n"));
+			rec->need_takeover_run = true;
+		}
+	}
+
+	result.dsize = sizeof(int32_t);
+	result.dptr  = (uint8_t *)&ret;
+
+	for (callers=rec->reallocate_callers; callers; callers=callers->next) {
+
+		/* Someone that sent srvid==0 does not want a reply */
+		if (callers->rd->srvid == 0) {
+			continue;
+		}
+		DEBUG(DEBUG_INFO,("Sending ip reallocate reply message to "
+				  "%u:%llu\n", (unsigned)callers->rd->pnn,
+				  (unsigned long long)callers->rd->srvid));
+		ret = ctdb_client_send_message(ctdb, callers->rd->pnn, callers->rd->srvid, result);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to send ip reallocate reply "
+					 "message to %u:%llu\n",
+					 (unsigned)callers->rd->pnn,
+					 (unsigned long long)callers->rd->srvid));
+		}
+	}
+
+	talloc_free(tmp_ctx);
+	talloc_free(rec->ip_reallocate_ctx);
+	rec->ip_reallocate_ctx = NULL;
+	rec->reallocate_callers = NULL;
+	
+}
+
+
+/*
+  handler for recovery master elections
+*/
+static void election_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	int ret;
+	struct election_message *em = (struct election_message *)data.dptr;
+	TALLOC_CTX *mem_ctx;
+
+	/* we got an election packet - update the timeout for the election */
+	talloc_free(rec->election_timeout);
+	rec->election_timeout = event_add_timed(ctdb->ev, ctdb, 
+						fast_start ?
+						timeval_current_ofs(0, 500000) :
+						timeval_current_ofs(ctdb->tunable.election_timeout, 0), 
+						ctdb_election_timeout, rec);
+
+	mem_ctx = talloc_new(ctdb);
+
+	/* someone called an election. check their election data
+	   and if we disagree and we would rather be the elected node, 
+	   send a new election message to all other nodes
+	 */
+	if (ctdb_election_win(rec, em)) {
+		if (!rec->send_election_te) {
+			rec->send_election_te = event_add_timed(ctdb->ev, rec, 
+								timeval_current_ofs(0, 500000),
+								election_send_request, rec);
+		}
+		talloc_free(mem_ctx);
+		/*unban_all_nodes(ctdb);*/
+		return;
+	}
+	
+	/* we didn't win */
+	talloc_free(rec->send_election_te);
+	rec->send_election_te = NULL;
+
+        if (ctdb->tunable.verify_recovery_lock != 0) {
+		/* release the recmaster lock */
+		if (em->pnn != ctdb->pnn &&
+		    ctdb->recovery_lock_fd != -1) {
+			close(ctdb->recovery_lock_fd);
+			ctdb->recovery_lock_fd = -1;
+			unban_all_nodes(ctdb);
+		}
+	}
+
+	/* ok, let that guy become recmaster then */
+	ret = ctdb_ctrl_setrecmaster(ctdb, CONTROL_TIMEOUT(), ctdb_get_pnn(ctdb), em->pnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to send recmaster election request"));
+		talloc_free(mem_ctx);
+		return;
+	}
+
+	talloc_free(mem_ctx);
+	return;
+}
+
+
+/*
+  force the start of the election process
+ */
+static void force_election(struct ctdb_recoverd *rec, uint32_t pnn, 
+			   struct ctdb_node_map *nodemap)
+{
+	int ret;
+	struct ctdb_context *ctdb = rec->ctdb;
+
+	DEBUG(DEBUG_INFO,(__location__ " Force an election\n"));
+
+	/* set all nodes to recovery mode to stop all internode traffic */
+	ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to active on cluster\n"));
+		return;
+	}
+
+	talloc_free(rec->election_timeout);
+	rec->election_timeout = event_add_timed(ctdb->ev, ctdb, 
+						fast_start ?
+						timeval_current_ofs(0, 500000) :
+						timeval_current_ofs(ctdb->tunable.election_timeout, 0), 
+						ctdb_election_timeout, rec);
+
+	ret = send_election_request(rec, pnn, true);
+	if (ret!=0) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to initiate recmaster election"));
+		return;
+	}
+
+	/* wait for a few seconds to collect all responses */
+	ctdb_wait_election(rec);
+}
+
+
+
+/*
+  handler for when a node changes its flags
+*/
+static void monitor_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			    TDB_DATA data, void *private_data)
+{
+	int ret;
+	struct ctdb_node_flag_change *c = (struct ctdb_node_flag_change *)data.dptr;
+	struct ctdb_node_map *nodemap=NULL;
+	TALLOC_CTX *tmp_ctx;
+	uint32_t changed_flags;
+	int i;
+	struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd);
+	int disabled_flag_changed;
+
+	if (data.dsize != sizeof(*c)) {
+		DEBUG(DEBUG_ERR,(__location__ "Invalid data in ctdb_node_flag_change\n"));
+		return;
+	}
+
+	tmp_ctx = talloc_new(ctdb);
+	CTDB_NO_MEMORY_VOID(ctdb, tmp_ctx);
+
+	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ "ctdb_ctrl_getnodemap failed in monitor_handler\n"));
+		talloc_free(tmp_ctx);
+		return;		
+	}
+
+
+	for (i=0;i<nodemap->num;i++) {
+		if (nodemap->nodes[i].pnn == c->pnn) break;
+	}
+
+	if (i == nodemap->num) {
+		DEBUG(DEBUG_CRIT,(__location__ "Flag change for non-existant node %u\n", c->pnn));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	changed_flags = c->old_flags ^ c->new_flags;
+
+	if (nodemap->nodes[i].flags != c->new_flags) {
+		DEBUG(DEBUG_NOTICE,("Node %u has changed flags - now 0x%x  was 0x%x\n", c->pnn, c->new_flags, c->old_flags));
+	}
+
+	disabled_flag_changed =  (nodemap->nodes[i].flags ^ c->new_flags) & NODE_FLAGS_DISABLED;
+
+	nodemap->nodes[i].flags = c->new_flags;
+
+	ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, CONTROL_TIMEOUT(), 
+				     CTDB_CURRENT_NODE, &ctdb->recovery_master);
+
+	if (ret == 0) {
+		ret = ctdb_ctrl_getrecmode(ctdb, tmp_ctx, CONTROL_TIMEOUT(), 
+					   CTDB_CURRENT_NODE, &ctdb->recovery_mode);
+	}
+	
+	if (ret == 0 &&
+	    ctdb->recovery_master == ctdb->pnn &&
+	    ctdb->recovery_mode == CTDB_RECOVERY_NORMAL) {
+		/* Only do the takeover run if the perm disabled or unhealthy
+		   flags changed since these will cause an ip failover but not
+		   a recovery.
+		   If the node became disconnected or banned this will also
+		   lead to an ip address failover but that is handled 
+		   during recovery
+		*/
+		if (disabled_flag_changed) {
+			rec->need_takeover_run = true;
+		}
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  handler for when we need to push out flag changes ot all other nodes
+*/
+static void push_flags_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			    TDB_DATA data, void *private_data)
+{
+	int ret;
+	struct ctdb_node_flag_change *c = (struct ctdb_node_flag_change *)data.dptr;
+	struct ctdb_node_map *nodemap=NULL;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	uint32_t recmaster;
+	uint32_t *nodes;
+
+	/* find the recovery master */
+	ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, &recmaster);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get recmaster from local node\n"));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	/* read the node flags from the recmaster */
+	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), recmaster, tmp_ctx, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from node %u\n", c->pnn));
+		talloc_free(tmp_ctx);
+		return;
+	}
+	if (c->pnn >= nodemap->num) {
+		DEBUG(DEBUG_ERR,(__location__ " Nodemap from recmaster does not contain node %d\n", c->pnn));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	/* send the flags update to all connected nodes */
+	nodes = list_of_connected_nodes(ctdb, nodemap, tmp_ctx, true);
+
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_MODIFY_FLAGS,
+				      nodes, 0, CONTROL_TIMEOUT(),
+				      false, data,
+				      NULL, NULL,
+				      NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " ctdb_control to modify node flags failed\n"));
+
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+
+struct verify_recmode_normal_data {
+	uint32_t count;
+	enum monitor_result status;
+};
+
+static void verify_recmode_normal_callback(struct ctdb_client_control_state *state)
+{
+	struct verify_recmode_normal_data *rmdata = talloc_get_type(state->async.private_data, struct verify_recmode_normal_data);
+
+
+	/* one more node has responded with recmode data*/
+	rmdata->count--;
+
+	/* if we failed to get the recmode, then return an error and let
+	   the main loop try again.
+	*/
+	if (state->state != CTDB_CONTROL_DONE) {
+		if (rmdata->status == MONITOR_OK) {
+			rmdata->status = MONITOR_FAILED;
+		}
+		return;
+	}
+
+	/* if we got a response, then the recmode will be stored in the
+	   status field
+	*/
+	if (state->status != CTDB_RECOVERY_NORMAL) {
+		DEBUG(DEBUG_NOTICE, (__location__ " Node:%u was in recovery mode. Restart recovery process\n", state->c->hdr.destnode));
+		rmdata->status = MONITOR_RECOVERY_NEEDED;
+	}
+
+	return;
+}
+
+
+/* verify that all nodes are in normal recovery mode */
+static enum monitor_result verify_recmode(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap)
+{
+	struct verify_recmode_normal_data *rmdata;
+	TALLOC_CTX *mem_ctx = talloc_new(ctdb);
+	struct ctdb_client_control_state *state;
+	enum monitor_result status;
+	int j;
+	
+	rmdata = talloc(mem_ctx, struct verify_recmode_normal_data);
+	CTDB_NO_MEMORY_FATAL(ctdb, rmdata);
+	rmdata->count  = 0;
+	rmdata->status = MONITOR_OK;
+
+	/* loop over all active nodes and send an async getrecmode call to 
+	   them*/
+	for (j=0; j<nodemap->num; j++) {
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		state = ctdb_ctrl_getrecmode_send(ctdb, mem_ctx, 
+					CONTROL_TIMEOUT(), 
+					nodemap->nodes[j].pnn);
+		if (state == NULL) {
+			/* we failed to send the control, treat this as 
+			   an error and try again next iteration
+			*/			
+			DEBUG(DEBUG_ERR,("Failed to call ctdb_ctrl_getrecmode_send during monitoring\n"));
+			talloc_free(mem_ctx);
+			return MONITOR_FAILED;
+		}
+
+		/* set up the callback functions */
+		state->async.fn = verify_recmode_normal_callback;
+		state->async.private_data = rmdata;
+
+		/* one more control to wait for to complete */
+		rmdata->count++;
+	}
+
+
+	/* now wait for up to the maximum number of seconds allowed
+	   or until all nodes we expect a response from has replied
+	*/
+	while (rmdata->count > 0) {
+		event_loop_once(ctdb->ev);
+	}
+
+	status = rmdata->status;
+	talloc_free(mem_ctx);
+	return status;
+}
+
+
+struct verify_recmaster_data {
+	struct ctdb_recoverd *rec;
+	uint32_t count;
+	uint32_t pnn;
+	enum monitor_result status;
+};
+
+static void verify_recmaster_callback(struct ctdb_client_control_state *state)
+{
+	struct verify_recmaster_data *rmdata = talloc_get_type(state->async.private_data, struct verify_recmaster_data);
+
+
+	/* one more node has responded with recmaster data*/
+	rmdata->count--;
+
+	/* if we failed to get the recmaster, then return an error and let
+	   the main loop try again.
+	*/
+	if (state->state != CTDB_CONTROL_DONE) {
+		if (rmdata->status == MONITOR_OK) {
+			rmdata->status = MONITOR_FAILED;
+		}
+		return;
+	}
+
+	/* if we got a response, then the recmaster will be stored in the
+	   status field
+	*/
+	if (state->status != rmdata->pnn) {
+		DEBUG(DEBUG_ERR,("Node %d does not agree we are the recmaster. Need a new recmaster election\n", state->c->hdr.destnode));
+		ctdb_set_culprit(rmdata->rec, state->c->hdr.destnode);
+		rmdata->status = MONITOR_ELECTION_NEEDED;
+	}
+
+	return;
+}
+
+
+/* verify that all nodes agree that we are the recmaster */
+static enum monitor_result verify_recmaster(struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap, uint32_t pnn)
+{
+	struct ctdb_context *ctdb = rec->ctdb;
+	struct verify_recmaster_data *rmdata;
+	TALLOC_CTX *mem_ctx = talloc_new(ctdb);
+	struct ctdb_client_control_state *state;
+	enum monitor_result status;
+	int j;
+	
+	rmdata = talloc(mem_ctx, struct verify_recmaster_data);
+	CTDB_NO_MEMORY_FATAL(ctdb, rmdata);
+	rmdata->rec    = rec;
+	rmdata->count  = 0;
+	rmdata->pnn    = pnn;
+	rmdata->status = MONITOR_OK;
+
+	/* loop over all active nodes and send an async getrecmaster call to 
+	   them*/
+	for (j=0; j<nodemap->num; j++) {
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		state = ctdb_ctrl_getrecmaster_send(ctdb, mem_ctx, 
+					CONTROL_TIMEOUT(),
+					nodemap->nodes[j].pnn);
+		if (state == NULL) {
+			/* we failed to send the control, treat this as 
+			   an error and try again next iteration
+			*/			
+			DEBUG(DEBUG_ERR,("Failed to call ctdb_ctrl_getrecmaster_send during monitoring\n"));
+			talloc_free(mem_ctx);
+			return MONITOR_FAILED;
+		}
+
+		/* set up the callback functions */
+		state->async.fn = verify_recmaster_callback;
+		state->async.private_data = rmdata;
+
+		/* one more control to wait for to complete */
+		rmdata->count++;
+	}
+
+
+	/* now wait for up to the maximum number of seconds allowed
+	   or until all nodes we expect a response from has replied
+	*/
+	while (rmdata->count > 0) {
+		event_loop_once(ctdb->ev);
+	}
+
+	status = rmdata->status;
+	talloc_free(mem_ctx);
+	return status;
+}
+
+
+/* called to check that the local allocation of public ip addresses is ok.
+*/
+static int verify_local_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, uint32_t pnn, struct ctdb_node_map *nodemap)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	struct ctdb_control_get_ifaces *ifaces = NULL;
+	struct ctdb_all_public_ips *ips = NULL;
+	struct ctdb_uptime *uptime1 = NULL;
+	struct ctdb_uptime *uptime2 = NULL;
+	int ret, j;
+	bool need_iface_check = false;
+	bool need_takeover_run = false;
+
+	ret = ctdb_ctrl_uptime(ctdb, mem_ctx, CONTROL_TIMEOUT(),
+				CTDB_CURRENT_NODE, &uptime1);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get uptime from local node %u\n", pnn));
+		talloc_free(mem_ctx);
+		return -1;
+	}
+
+
+	/* read the interfaces from the local node */
+	ret = ctdb_ctrl_get_ifaces(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, mem_ctx, &ifaces);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get interfaces from local node %u\n", pnn));
+		talloc_free(mem_ctx);
+		return -1;
+	}
+
+	if (!rec->ifaces) {
+		need_iface_check = true;
+	} else if (rec->ifaces->num != ifaces->num) {
+		need_iface_check = true;
+	} else if (memcmp(rec->ifaces, ifaces, talloc_get_size(ifaces)) != 0) {
+		need_iface_check = true;
+	}
+
+	if (need_iface_check) {
+		DEBUG(DEBUG_NOTICE, ("The interfaces status has changed on "
+				     "local node %u - force takeover run\n",
+				     pnn));
+		need_takeover_run = true;
+	}
+
+	/* read the ip allocation from the local node */
+	ret = ctdb_ctrl_get_public_ips(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, mem_ctx, &ips);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get public ips from local node %u\n", pnn));
+		talloc_free(mem_ctx);
+		return -1;
+	}
+
+	ret = ctdb_ctrl_uptime(ctdb, mem_ctx, CONTROL_TIMEOUT(),
+				CTDB_CURRENT_NODE, &uptime2);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get uptime from local node %u\n", pnn));
+		talloc_free(mem_ctx);
+		return -1;
+	}
+
+	/* skip the check if the startrecovery time has changed */
+	if (timeval_compare(&uptime1->last_recovery_started,
+			    &uptime2->last_recovery_started) != 0) {
+		DEBUG(DEBUG_NOTICE, (__location__ " last recovery time changed while we read the public ip list. skipping public ip address check\n"));
+		talloc_free(mem_ctx);
+		return 0;
+	}
+
+	/* skip the check if the endrecovery time has changed */
+	if (timeval_compare(&uptime1->last_recovery_finished,
+			    &uptime2->last_recovery_finished) != 0) {
+		DEBUG(DEBUG_NOTICE, (__location__ " last recovery time changed while we read the public ip list. skipping public ip address check\n"));
+		talloc_free(mem_ctx);
+		return 0;
+	}
+
+	/* skip the check if we have started but not finished recovery */
+	if (timeval_compare(&uptime1->last_recovery_finished,
+			    &uptime1->last_recovery_started) != 1) {
+		DEBUG(DEBUG_INFO, (__location__ " in the middle of recovery or ip reallocation. skipping public ip address check\n"));
+		talloc_free(mem_ctx);
+
+		return 0;
+	}
+
+	talloc_free(rec->ifaces);
+	rec->ifaces = talloc_steal(rec, ifaces);
+
+	/* verify that we have the ip addresses we should have
+	   and we dont have ones we shouldnt have.
+	   if we find an inconsistency we set recmode to
+	   active on the local node and wait for the recmaster
+	   to do a full blown recovery.
+	   also if the pnn is -1 and we are healthy and can host the ip
+	   we also request a ip reallocation.
+	*/
+	if (ctdb->tunable.disable_ip_failover == 0) {
+		for (j=0; j<ips->num; j++) {
+			if (ips->ips[j].pnn == -1 && nodemap->nodes[pnn].flags == 0) {
+				DEBUG(DEBUG_CRIT,("Public address '%s' is not assigned and we could serve this ip\n",
+						ctdb_addr_to_str(&ips->ips[j].addr)));
+				need_takeover_run = true;
+			} else if (ips->ips[j].pnn == pnn) {
+				if (!ctdb_sys_have_ip(&ips->ips[j].addr)) {
+					DEBUG(DEBUG_CRIT,("Public address '%s' is missing and we should serve this ip\n",
+						ctdb_addr_to_str(&ips->ips[j].addr)));
+					need_takeover_run = true;
+				}
+			} else {
+				if (ctdb_sys_have_ip(&ips->ips[j].addr)) {
+					DEBUG(DEBUG_CRIT,("We are still serving a public address '%s' that we should not be serving.\n", 
+						ctdb_addr_to_str(&ips->ips[j].addr)));
+					need_takeover_run = true;
+				}
+			}
+		}
+	}
+
+	if (need_takeover_run) {
+		struct takeover_run_reply rd;
+		TDB_DATA data;
+
+		DEBUG(DEBUG_CRIT,("Trigger takeoverrun\n"));
+
+		rd.pnn = ctdb->pnn;
+		rd.srvid = 0;
+		data.dptr = (uint8_t *)&rd;
+		data.dsize = sizeof(rd);
+
+		ret = ctdb_client_send_message(ctdb, rec->recmaster, CTDB_SRVID_TAKEOVER_RUN, data);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to send ipreallocate to recmaster :%d\n", (int)rec->recmaster));
+		}
+	}
+	talloc_free(mem_ctx);
+	return 0;
+}
+
+
+static void async_getnodemap_callback(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data)
+{
+	struct ctdb_node_map **remote_nodemaps = callback_data;
+
+	if (node_pnn >= ctdb->num_nodes) {
+		DEBUG(DEBUG_ERR,(__location__ " pnn from invalid node\n"));
+		return;
+	}
+
+	remote_nodemaps[node_pnn] = (struct ctdb_node_map *)talloc_steal(remote_nodemaps, outdata.dptr);
+
+}
+
+static int get_remote_nodemaps(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
+	struct ctdb_node_map *nodemap,
+	struct ctdb_node_map **remote_nodemaps)
+{
+	uint32_t *nodes;
+
+	nodes = list_of_active_nodes(ctdb, nodemap, mem_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_GET_NODEMAP,
+					nodes, 0,
+					CONTROL_TIMEOUT(), false, tdb_null,
+					async_getnodemap_callback,
+					NULL,
+					remote_nodemaps) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to pull all remote nodemaps\n"));
+
+		return -1;
+	}
+
+	return 0;
+}
+
+enum reclock_child_status { RECLOCK_CHECKING, RECLOCK_OK, RECLOCK_FAILED, RECLOCK_TIMEOUT};
+struct ctdb_check_reclock_state {
+	struct ctdb_context *ctdb;
+	struct timeval start_time;
+	int fd[2];
+	pid_t child;
+	struct timed_event *te;
+	struct fd_event *fde;
+	enum reclock_child_status status;
+};
+
+/* when we free the reclock state we must kill any child process.
+*/
+static int check_reclock_destructor(struct ctdb_check_reclock_state *state)
+{
+	struct ctdb_context *ctdb = state->ctdb;
+
+	ctdb_ctrl_report_recd_lock_latency(ctdb, CONTROL_TIMEOUT(), timeval_elapsed(&state->start_time));
+
+	if (state->fd[0] != -1) {
+		close(state->fd[0]);
+		state->fd[0] = -1;
+	}
+	if (state->fd[1] != -1) {
+		close(state->fd[1]);
+		state->fd[1] = -1;
+	}
+	kill(state->child, SIGKILL);
+	return 0;
+}
+
+/*
+  called if our check_reclock child times out. this would happen if
+  i/o to the reclock file blocks.
+ */
+static void ctdb_check_reclock_timeout(struct event_context *ev, struct timed_event *te, 
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_check_reclock_state *state = talloc_get_type(private_data, 
+					   struct ctdb_check_reclock_state);
+
+	DEBUG(DEBUG_ERR,(__location__ " check_reclock child process hung/timedout CFS slow to grant locks?\n"));
+	state->status = RECLOCK_TIMEOUT;
+}
+
+/* this is called when the child process has completed checking the reclock
+   file and has written data back to us through the pipe.
+*/
+static void reclock_child_handler(struct event_context *ev, struct fd_event *fde, 
+			     uint16_t flags, void *private_data)
+{
+	struct ctdb_check_reclock_state *state= talloc_get_type(private_data, 
+					     struct ctdb_check_reclock_state);
+	char c = 0;
+	int ret;
+
+	/* we got a response from our child process so we can abort the
+	   timeout.
+	*/
+	talloc_free(state->te);
+	state->te = NULL;
+
+	ret = read(state->fd[0], &c, 1);
+	if (ret != 1 || c != RECLOCK_OK) {
+		DEBUG(DEBUG_ERR,(__location__ " reclock child process returned error %d\n", c));
+		state->status = RECLOCK_FAILED;
+
+		return;
+	}
+
+	state->status = RECLOCK_OK;
+	return;
+}
+
+static int check_recovery_lock(struct ctdb_context *ctdb)
+{
+	int ret;
+	struct ctdb_check_reclock_state *state;
+	pid_t parent = getpid();
+
+	if (ctdb->recovery_lock_fd == -1) {
+		DEBUG(DEBUG_CRIT,("recovery master doesn't have the recovery lock\n"));
+		return -1;
+	}
+
+	state = talloc(ctdb, struct ctdb_check_reclock_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->ctdb = ctdb;
+	state->start_time = timeval_current();
+	state->status = RECLOCK_CHECKING;
+	state->fd[0] = -1;
+	state->fd[1] = -1;
+
+	ret = pipe(state->fd);
+	if (ret != 0) {
+		talloc_free(state);
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to open pipe for check_reclock child\n"));
+		return -1;
+	}
+
+	state->child = ctdb_fork(ctdb);
+	if (state->child == (pid_t)-1) {
+		DEBUG(DEBUG_CRIT,(__location__ " fork() failed in check_reclock child\n"));
+		close(state->fd[0]);
+		state->fd[0] = -1;
+		close(state->fd[1]);
+		state->fd[1] = -1;
+		talloc_free(state);
+		return -1;
+	}
+
+	if (state->child == 0) {
+		char cc = RECLOCK_OK;
+		close(state->fd[0]);
+		state->fd[0] = -1;
+
+		debug_extra = talloc_asprintf(NULL, "recovery-lock:");
+		if (pread(ctdb->recovery_lock_fd, &cc, 1, 0) == -1) {
+			DEBUG(DEBUG_CRIT,("failed read from recovery_lock_fd - %s\n", strerror(errno)));
+			cc = RECLOCK_FAILED;
+		}
+
+		write(state->fd[1], &cc, 1);
+		/* make sure we die when our parent dies */
+		while (kill(parent, 0) == 0 || errno != ESRCH) {
+			sleep(5);
+			write(state->fd[1], &cc, 1);
+		}
+		_exit(0);
+	}
+	close(state->fd[1]);
+	state->fd[1] = -1;
+	set_close_on_exec(state->fd[0]);
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d for check_recovery_lock\n", state->fd[0]));
+
+	talloc_set_destructor(state, check_reclock_destructor);
+
+	state->te = event_add_timed(ctdb->ev, state, timeval_current_ofs(15, 0),
+				    ctdb_check_reclock_timeout, state);
+	if (state->te == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to create a timed event for reclock child\n"));
+		talloc_free(state);
+		return -1;
+	}
+
+	state->fde = event_add_fd(ctdb->ev, state, state->fd[0],
+				EVENT_FD_READ,
+				reclock_child_handler,
+				(void *)state);
+
+	if (state->fde == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Failed to create an fd event for reclock child\n"));
+		talloc_free(state);
+		return -1;
+	}
+	tevent_fd_set_auto_close(state->fde);
+
+	while (state->status == RECLOCK_CHECKING) {
+		event_loop_once(ctdb->ev);
+	}
+
+	if (state->status == RECLOCK_FAILED) {
+		DEBUG(DEBUG_ERR,(__location__ " reclock child failed when checking file\n"));
+		close(ctdb->recovery_lock_fd);
+		ctdb->recovery_lock_fd = -1;
+		talloc_free(state);
+		return -1;
+	}
+
+	talloc_free(state);
+	return 0;
+}
+
+static int update_recovery_lock_file(struct ctdb_context *ctdb)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	const char *reclockfile;
+
+	if (ctdb_ctrl_getreclock(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, tmp_ctx, &reclockfile) != 0) {
+		DEBUG(DEBUG_ERR,("Failed to read reclock file from daemon\n"));
+		talloc_free(tmp_ctx);
+		return -1;	
+	}
+
+	if (reclockfile == NULL) {
+		if (ctdb->recovery_lock_file != NULL) {
+			DEBUG(DEBUG_ERR,("Reclock file disabled\n"));
+			talloc_free(ctdb->recovery_lock_file);
+			ctdb->recovery_lock_file = NULL;
+			if (ctdb->recovery_lock_fd != -1) {
+				close(ctdb->recovery_lock_fd);
+				ctdb->recovery_lock_fd = -1;
+			}
+		}
+		ctdb->tunable.verify_recovery_lock = 0;
+		talloc_free(tmp_ctx);
+		return 0;
+	}
+
+	if (ctdb->recovery_lock_file == NULL) {
+		ctdb->recovery_lock_file = talloc_strdup(ctdb, reclockfile);
+		if (ctdb->recovery_lock_fd != -1) {
+			close(ctdb->recovery_lock_fd);
+			ctdb->recovery_lock_fd = -1;
+		}
+		talloc_free(tmp_ctx);
+		return 0;
+	}
+
+
+	if (!strcmp(reclockfile, ctdb->recovery_lock_file)) {
+		talloc_free(tmp_ctx);
+		return 0;
+	}
+
+	talloc_free(ctdb->recovery_lock_file);
+	ctdb->recovery_lock_file = talloc_strdup(ctdb, reclockfile);
+	ctdb->tunable.verify_recovery_lock = 0;
+	if (ctdb->recovery_lock_fd != -1) {
+		close(ctdb->recovery_lock_fd);
+		ctdb->recovery_lock_fd = -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec,
+		      TALLOC_CTX *mem_ctx)
+{
+	uint32_t pnn;
+	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_node_map *recmaster_nodemap=NULL;
+	struct ctdb_node_map **remote_nodemaps=NULL;
+	struct ctdb_vnn_map *vnnmap=NULL;
+	struct ctdb_vnn_map *remote_vnnmap=NULL;
+	int32_t debug_level;
+	int i, j, ret;
+
+
+
+	/* verify that the main daemon is still running */
+	if (kill(ctdb->ctdbd_pid, 0) != 0) {
+		DEBUG(DEBUG_CRIT,("CTDB daemon is no longer available. Shutting down recovery daemon\n"));
+		exit(-1);
+	}
+
+	/* ping the local daemon to tell it we are alive */
+	ctdb_ctrl_recd_ping(ctdb);
+
+	if (rec->election_timeout) {
+		/* an election is in progress */
+		return;
+	}
+
+	/* read the debug level from the parent and update locally */
+	ret = ctdb_ctrl_get_debuglevel(ctdb, CTDB_CURRENT_NODE, &debug_level);
+	if (ret !=0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to read debuglevel from parent\n"));
+		return;
+	}
+	LogLevel = debug_level;
+
+
+	/* We must check if we need to ban a node here but we want to do this
+	   as early as possible so we dont wait until we have pulled the node
+	   map from the local node. thats why we have the hardcoded value 20
+	*/
+	for (i=0; i<ctdb->num_nodes; i++) {
+		struct ctdb_banning_state *ban_state;
+
+		if (ctdb->nodes[i]->ban_state == NULL) {
+			continue;
+		}
+		ban_state = (struct ctdb_banning_state *)ctdb->nodes[i]->ban_state;
+		if (ban_state->count < 20) {
+			continue;
+		}
+		DEBUG(DEBUG_NOTICE,("Node %u has caused %u recoveries recently - banning it for %u seconds\n",
+			ctdb->nodes[i]->pnn, ban_state->count,
+			ctdb->tunable.recovery_ban_period));
+		ctdb_ban_node(rec, ctdb->nodes[i]->pnn, ctdb->tunable.recovery_ban_period);
+		ban_state->count = 0;
+	}
+
+	/* get relevant tunables */
+	ret = ctdb_ctrl_get_all_tunables(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, &ctdb->tunable);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to get tunables - retrying\n"));
+		return;
+	}
+
+	/* get the current recovery lock file from the server */
+	if (update_recovery_lock_file(ctdb) != 0) {
+		DEBUG(DEBUG_ERR,("Failed to update the recovery lock file\n"));
+		return;
+	}
+
+	/* Make sure that if recovery lock verification becomes disabled when
+	   we close the file
+	*/
+        if (ctdb->tunable.verify_recovery_lock == 0) {
+		if (ctdb->recovery_lock_fd != -1) {
+			close(ctdb->recovery_lock_fd);
+			ctdb->recovery_lock_fd = -1;
+		}
+	}
+
+	pnn = ctdb_ctrl_getpnn(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE);
+	if (pnn == (uint32_t)-1) {
+		DEBUG(DEBUG_ERR,("Failed to get local pnn - retrying\n"));
+		return;
+	}
+
+	/* get the vnnmap */
+	ret = ctdb_ctrl_getvnnmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, &vnnmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get vnnmap from node %u\n", pnn));
+		return;
+	}
+
+
+	/* get number of nodes */
+	if (rec->nodemap) {
+		talloc_free(rec->nodemap);
+		rec->nodemap = NULL;
+		nodemap=NULL;
+	}
+	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), pnn, rec, &rec->nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from node %u\n", pnn));
+		return;
+	}
+	nodemap = rec->nodemap;
+
+	/* check which node is the recovery master */
+	ret = ctdb_ctrl_getrecmaster(ctdb, mem_ctx, CONTROL_TIMEOUT(), pnn, &rec->recmaster);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get recmaster from node %u\n", pnn));
+		return;
+	}
+
+	/* if we are not the recmaster we can safely ignore any ip reallocate requests */
+	if (rec->recmaster != pnn) {
+		if (rec->ip_reallocate_ctx != NULL) {
+			talloc_free(rec->ip_reallocate_ctx);
+			rec->ip_reallocate_ctx = NULL;
+			rec->reallocate_callers = NULL;
+		}
+	}
+
+	if (rec->recmaster == (uint32_t)-1) {
+		DEBUG(DEBUG_NOTICE,(__location__ " Initial recovery master set - forcing election\n"));
+		force_election(rec, pnn, nodemap);
+		return;
+	}
+
+
+	/* if the local daemon is STOPPED, we verify that the databases are
+	   also frozen and thet the recmode is set to active 
+	*/
+	if (nodemap->nodes[pnn].flags & NODE_FLAGS_STOPPED) {
+		ret = ctdb_ctrl_getrecmode(ctdb, mem_ctx, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, &ctdb->recovery_mode);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to read recmode from local node\n"));
+		}
+		if (ctdb->recovery_mode == CTDB_RECOVERY_NORMAL) {
+			DEBUG(DEBUG_ERR,("Node is stopped but recovery mode is not active. Activate recovery mode and lock databases\n"));
+
+			ret = ctdb_ctrl_freeze_priority(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, 1);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR,(__location__ " Failed to freeze node due to node being STOPPED\n"));
+				return;
+			}
+			ret = ctdb_ctrl_setrecmode(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, CTDB_RECOVERY_ACTIVE);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR,(__location__ " Failed to activate recovery mode due to node being stopped\n"));
+
+				return;
+			}
+			return;
+		}
+	}
+	/* If the local node is stopped, verify we are not the recmaster 
+	   and yield this role if so
+	*/
+	if ((nodemap->nodes[pnn].flags & NODE_FLAGS_STOPPED) && (rec->recmaster == pnn)) {
+		DEBUG(DEBUG_ERR,("Local node is STOPPED. Yielding recmaster role\n"));
+		force_election(rec, pnn, nodemap);
+		return;
+	}
+	
+	/* check that we (recovery daemon) and the local ctdb daemon
+	   agrees on whether we are banned or not
+	*/
+//qqq
+
+	/* remember our own node flags */
+	rec->node_flags = nodemap->nodes[pnn].flags;
+
+	/* count how many active nodes there are */
+	rec->num_active    = 0;
+	rec->num_connected = 0;
+	for (i=0; i<nodemap->num; i++) {
+		if (!(nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE)) {
+			rec->num_active++;
+		}
+		if (!(nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED)) {
+			rec->num_connected++;
+		}
+	}
+
+
+	/* verify that the recmaster node is still active */
+	for (j=0; j<nodemap->num; j++) {
+		if (nodemap->nodes[j].pnn==rec->recmaster) {
+			break;
+		}
+	}
+
+	if (j == nodemap->num) {
+		DEBUG(DEBUG_ERR, ("Recmaster node %u not in list. Force reelection\n", rec->recmaster));
+		force_election(rec, pnn, nodemap);
+		return;
+	}
+
+	/* if recovery master is disconnected we must elect a new recmaster */
+	if (nodemap->nodes[j].flags & NODE_FLAGS_DISCONNECTED) {
+		DEBUG(DEBUG_NOTICE, ("Recmaster node %u is disconnected. Force reelection\n", nodemap->nodes[j].pnn));
+		force_election(rec, pnn, nodemap);
+		return;
+	}
+
+	/* grap the nodemap from the recovery master to check if it is banned */
+	ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
+				   mem_ctx, &recmaster_nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from recovery master %u\n", 
+			  nodemap->nodes[j].pnn));
+		return;
+	}
+
+
+	if (recmaster_nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+		DEBUG(DEBUG_NOTICE, ("Recmaster node %u no longer available. Force reelection\n", nodemap->nodes[j].pnn));
+		force_election(rec, pnn, nodemap);
+		return;
+	}
+
+
+	/* verify that we have all ip addresses we should have and we dont
+	 * have addresses we shouldnt have.
+	 */ 
+	if (ctdb->tunable.disable_ip_failover == 0) {
+		if (rec->ip_check_disable_ctx == NULL) {
+			if (verify_local_ip_allocation(ctdb, rec, pnn, nodemap) != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Public IPs were inconsistent.\n"));
+			}
+		}
+	}
+
+
+	/* if we are not the recmaster then we do not need to check
+	   if recovery is needed
+	 */
+	if (pnn != rec->recmaster) {
+		return;
+	}
+
+
+	/* ensure our local copies of flags are right */
+	ret = update_local_flags(rec, nodemap);
+	if (ret == MONITOR_ELECTION_NEEDED) {
+		DEBUG(DEBUG_NOTICE,("update_local_flags() called for a re-election.\n"));
+		force_election(rec, pnn, nodemap);
+		return;
+	}
+	if (ret != MONITOR_OK) {
+		DEBUG(DEBUG_ERR,("Unable to update local flags\n"));
+		return;
+	}
+
+	if (ctdb->num_nodes != nodemap->num) {
+		DEBUG(DEBUG_ERR, (__location__ " ctdb->num_nodes (%d) != nodemap->num (%d) reloading nodes file\n", ctdb->num_nodes, nodemap->num));
+		reload_nodes_file(ctdb);
+		return;
+	}
+
+	/* verify that all active nodes agree that we are the recmaster */
+	switch (verify_recmaster(rec, nodemap, pnn)) {
+	case MONITOR_RECOVERY_NEEDED:
+		/* can not happen */
+		return;
+	case MONITOR_ELECTION_NEEDED:
+		force_election(rec, pnn, nodemap);
+		return;
+	case MONITOR_OK:
+		break;
+	case MONITOR_FAILED:
+		return;
+	}
+
+
+	if (rec->need_recovery) {
+		/* a previous recovery didn't finish */
+		do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+		return;
+	}
+
+	/* verify that all active nodes are in normal mode 
+	   and not in recovery mode 
+	*/
+	switch (verify_recmode(ctdb, nodemap)) {
+	case MONITOR_RECOVERY_NEEDED:
+		do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+		return;
+	case MONITOR_FAILED:
+		return;
+	case MONITOR_ELECTION_NEEDED:
+		/* can not happen */
+	case MONITOR_OK:
+		break;
+	}
+
+
+        if (ctdb->tunable.verify_recovery_lock != 0) {
+		/* we should have the reclock - check its not stale */
+		ret = check_recovery_lock(ctdb);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed check_recovery_lock. Force a recovery\n"));
+			ctdb_set_culprit(rec, ctdb->pnn);
+			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+			return;
+		}
+	}
+
+	/* if there are takeovers requested, perform it and notify the waiters */
+	if (rec->reallocate_callers) {
+		process_ipreallocate_requests(ctdb, rec);
+	}
+
+	/* get the nodemap for all active remote nodes
+	 */
+	remote_nodemaps = talloc_array(mem_ctx, struct ctdb_node_map *, nodemap->num);
+	if (remote_nodemaps == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to allocate remote nodemap array\n"));
+		return;
+	}
+	for(i=0; i<nodemap->num; i++) {
+		remote_nodemaps[i] = NULL;
+	}
+	if (get_remote_nodemaps(ctdb, mem_ctx, nodemap, remote_nodemaps) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to read remote nodemaps\n"));
+		return;
+	} 
+
+	/* verify that all other nodes have the same nodemap as we have
+	*/
+	for (j=0; j<nodemap->num; j++) {
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+
+		if (remote_nodemaps[j] == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Did not get a remote nodemap for node %d, restarting monitoring\n", j));
+			ctdb_set_culprit(rec, j);
+
+			return;
+		}
+
+ 		/* if the nodes disagree on how many nodes there are
+		   then this is a good reason to try recovery
+		 */
+		if (remote_nodemaps[j]->num != nodemap->num) {
+			DEBUG(DEBUG_ERR, (__location__ " Remote node:%u has different node count. %u vs %u of the local node\n",
+				  nodemap->nodes[j].pnn, remote_nodemaps[j]->num, nodemap->num));
+			ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+			return;
+		}
+
+		/* if the nodes disagree on which nodes exist and are
+		   active, then that is also a good reason to do recovery
+		 */
+		for (i=0;i<nodemap->num;i++) {
+			if (remote_nodemaps[j]->nodes[i].pnn != nodemap->nodes[i].pnn) {
+				DEBUG(DEBUG_ERR, (__location__ " Remote node:%u has different nodemap pnn for %d (%u vs %u).\n", 
+					  nodemap->nodes[j].pnn, i, 
+					  remote_nodemaps[j]->nodes[i].pnn, nodemap->nodes[i].pnn));
+				ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+				do_recovery(rec, mem_ctx, pnn, nodemap, 
+					    vnnmap);
+				return;
+			}
+		}
+
+		/* verify the flags are consistent
+		*/
+		for (i=0; i<nodemap->num; i++) {
+			if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+				continue;
+			}
+			
+			if (nodemap->nodes[i].flags != remote_nodemaps[j]->nodes[i].flags) {
+				DEBUG(DEBUG_ERR, (__location__ " Remote node:%u has different flags for node %u. It has 0x%02x vs our 0x%02x\n", 
+				  nodemap->nodes[j].pnn, 
+				  nodemap->nodes[i].pnn, 
+				  remote_nodemaps[j]->nodes[i].flags,
+				  nodemap->nodes[j].flags));
+				if (i == j) {
+					DEBUG(DEBUG_ERR,("Use flags 0x%02x from remote node %d for cluster update of its own flags\n", remote_nodemaps[j]->nodes[i].flags, j));
+					update_flags_on_all_nodes(ctdb, nodemap, nodemap->nodes[i].pnn, remote_nodemaps[j]->nodes[i].flags);
+					ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+					do_recovery(rec, mem_ctx, pnn, nodemap, 
+						    vnnmap);
+					return;
+				} else {
+					DEBUG(DEBUG_ERR,("Use flags 0x%02x from local recmaster node for cluster update of node %d flags\n", nodemap->nodes[i].flags, i));
+					update_flags_on_all_nodes(ctdb, nodemap, nodemap->nodes[i].pnn, nodemap->nodes[i].flags);
+					ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+					do_recovery(rec, mem_ctx, pnn, nodemap, 
+						    vnnmap);
+					return;
+				}
+			}
+		}
+	}
+
+
+	/* there better be the same number of lmasters in the vnn map
+	   as there are active nodes or we will have to do a recovery
+	 */
+	if (vnnmap->size != rec->num_active) {
+		DEBUG(DEBUG_ERR, (__location__ " The vnnmap count is different from the number of active nodes. %u vs %u\n", 
+			  vnnmap->size, rec->num_active));
+		ctdb_set_culprit(rec, ctdb->pnn);
+		do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+		return;
+	}
+
+	/* verify that all active nodes in the nodemap also exist in 
+	   the vnnmap.
+	 */
+	for (j=0; j<nodemap->num; j++) {
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (nodemap->nodes[j].pnn == pnn) {
+			continue;
+		}
+
+		for (i=0; i<vnnmap->size; i++) {
+			if (vnnmap->map[i] == nodemap->nodes[j].pnn) {
+				break;
+			}
+		}
+		if (i == vnnmap->size) {
+			DEBUG(DEBUG_ERR, (__location__ " Node %u is active in the nodemap but did not exist in the vnnmap\n", 
+				  nodemap->nodes[j].pnn));
+			ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+			return;
+		}
+	}
+
+	
+	/* verify that all other nodes have the same vnnmap
+	   and are from the same generation
+	 */
+	for (j=0; j<nodemap->num; j++) {
+		if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (nodemap->nodes[j].pnn == pnn) {
+			continue;
+		}
+
+		ret = ctdb_ctrl_getvnnmap(ctdb, CONTROL_TIMEOUT(), nodemap->nodes[j].pnn, 
+					  mem_ctx, &remote_vnnmap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to get vnnmap from remote node %u\n", 
+				  nodemap->nodes[j].pnn));
+			return;
+		}
+
+		/* verify the vnnmap generation is the same */
+		if (vnnmap->generation != remote_vnnmap->generation) {
+			DEBUG(DEBUG_ERR, (__location__ " Remote node %u has different generation of vnnmap. %u vs %u (ours)\n", 
+				  nodemap->nodes[j].pnn, remote_vnnmap->generation, vnnmap->generation));
+			ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+			return;
+		}
+
+		/* verify the vnnmap size is the same */
+		if (vnnmap->size != remote_vnnmap->size) {
+			DEBUG(DEBUG_ERR, (__location__ " Remote node %u has different size of vnnmap. %u vs %u (ours)\n", 
+				  nodemap->nodes[j].pnn, remote_vnnmap->size, vnnmap->size));
+			ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+			return;
+		}
+
+		/* verify the vnnmap is the same */
+		for (i=0;i<vnnmap->size;i++) {
+			if (remote_vnnmap->map[i] != vnnmap->map[i]) {
+				DEBUG(DEBUG_ERR, (__location__ " Remote node %u has different vnnmap.\n", 
+					  nodemap->nodes[j].pnn));
+				ctdb_set_culprit(rec, nodemap->nodes[j].pnn);
+				do_recovery(rec, mem_ctx, pnn, nodemap, 
+					    vnnmap);
+				return;
+			}
+		}
+	}
+
+	/* we might need to change who has what IP assigned */
+	if (rec->need_takeover_run) {
+		uint32_t culprit = (uint32_t)-1;
+
+		rec->need_takeover_run = false;
+
+		/* update the list of public ips that a node can handle for
+		   all connected nodes
+		*/
+		ret = ctdb_reload_remote_public_ips(ctdb, rec, nodemap, &culprit);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
+					 culprit));
+			rec->need_takeover_run = true;
+			return;
+		}
+
+		/* execute the "startrecovery" event script on all nodes */
+		ret = run_startrecovery_eventscript(rec, nodemap);
+		if (ret!=0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'startrecovery' event on cluster\n"));
+			ctdb_set_culprit(rec, ctdb->pnn);
+			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+			return;
+		}
+
+		ret = ctdb_takeover_run(ctdb, nodemap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to setup public takeover addresses. Try again later\n"));
+			return;
+		}
+
+		/* execute the "recovered" event script on all nodes */
+		ret = run_recovered_eventscript(ctdb, nodemap, "monitor_cluster");
+#if 0
+// we cant check whether the event completed successfully
+// since this script WILL fail if the node is in recovery mode
+// and if that race happens, the code here would just cause a second
+// cascading recovery.
+		if (ret!=0) {
+			DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'recovered' event on cluster. Update of public ips failed.\n"));
+			ctdb_set_culprit(rec, ctdb->pnn);
+			do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
+		}
+#endif
+	}
+}
+
+/*
+  the main monitoring loop
+ */
+static void monitor_cluster(struct ctdb_context *ctdb)
+{
+	struct ctdb_recoverd *rec;
+
+	DEBUG(DEBUG_NOTICE,("monitor_cluster starting\n"));
+
+	rec = talloc_zero(ctdb, struct ctdb_recoverd);
+	CTDB_NO_MEMORY_FATAL(ctdb, rec);
+
+	rec->ctdb = ctdb;
+
+	rec->priority_time = timeval_current();
+
+	/* register a message port for sending memory dumps */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_MEM_DUMP, mem_dump_handler, rec);
+
+	/* register a message port for recovery elections */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RECOVERY, election_handler, rec);
+
+	/* when nodes are disabled/enabled */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_SET_NODE_FLAGS, monitor_handler, rec);
+
+	/* when we are asked to puch out a flag change */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_PUSH_NODE_FLAGS, push_flags_handler, rec);
+
+	/* register a message port for vacuum fetch */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_VACUUM_FETCH, vacuum_fetch_handler, rec);
+
+	/* register a message port for reloadnodes  */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RELOAD_NODES, reload_nodes_handler, rec);
+
+	/* register a message port for performing a takeover run */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_TAKEOVER_RUN, ip_reallocate_handler, rec);
+
+	/* register a message port for disabling the ip check for a short while */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_DISABLE_IP_CHECK, disable_ip_check_handler, rec);
+
+	/* register a message port for updating the recovery daemons node assignment for an ip */
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RECD_UPDATE_IP, recd_update_ip_handler, rec);
+
+	for (;;) {
+		TALLOC_CTX *mem_ctx = talloc_new(ctdb);
+		struct timeval start;
+		double elapsed;
+
+		if (!mem_ctx) {
+			DEBUG(DEBUG_CRIT,(__location__
+					  " Failed to create temp context\n"));
+			exit(-1);
+		}
+
+		start = timeval_current();
+		main_loop(ctdb, rec, mem_ctx);
+		talloc_free(mem_ctx);
+
+		/* we only check for recovery once every second */
+		elapsed = timeval_elapsed(&start);
+		if (elapsed < ctdb->tunable.recover_interval) {
+			ctdb_wait_timeout(ctdb, ctdb->tunable.recover_interval
+					  - elapsed);
+		}
+	}
+}
+
+/*
+  event handler for when the main ctdbd dies
+ */
+static void ctdb_recoverd_parent(struct event_context *ev, struct fd_event *fde, 
+				 uint16_t flags, void *private_data)
+{
+	DEBUG(DEBUG_ALERT,("recovery daemon parent died - exiting\n"));
+	_exit(1);
+}
+
+/*
+  called regularly to verify that the recovery daemon is still running
+ */
+static void ctdb_check_recd(struct event_context *ev, struct timed_event *te, 
+			      struct timeval yt, void *p)
+{
+	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
+
+	if (kill(ctdb->recoverd_pid, 0) != 0) {
+		DEBUG(DEBUG_ERR,("Recovery daemon (pid:%d) is no longer running. Trying to restart recovery daemon.\n", (int)ctdb->recoverd_pid));
+
+		event_add_timed(ctdb->ev, ctdb, timeval_zero(), 
+				ctdb_restart_recd, ctdb);
+
+		return;
+	}
+
+	event_add_timed(ctdb->ev, ctdb, 
+			timeval_current_ofs(30, 0),
+			ctdb_check_recd, ctdb);
+}
+
+static void recd_sig_child_handler(struct event_context *ev,
+	struct signal_event *se, int signum, int count,
+	void *dont_care, 
+	void *private_data)
+{
+//	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	int status;
+	pid_t pid = -1;
+
+	while (pid != 0) {
+		pid = waitpid(-1, &status, WNOHANG);
+		if (pid == -1) {
+			if (errno != ECHILD) {
+				DEBUG(DEBUG_ERR, (__location__ " waitpid() returned error. errno:%s(%d)\n", strerror(errno),errno));
+			}
+			return;
+		}
+		if (pid > 0) {
+			DEBUG(DEBUG_DEBUG, ("RECD SIGCHLD from %d\n", (int)pid));
+		}
+	}
+}
+
+/*
+  startup the recovery daemon as a child of the main ctdb daemon
+ */
+int ctdb_start_recoverd(struct ctdb_context *ctdb)
+{
+	int fd[2];
+	struct signal_event *se;
+	struct tevent_fd *fde;
+
+	if (pipe(fd) != 0) {
+		return -1;
+	}
+
+	ctdb->ctdbd_pid = getpid();
+
+	ctdb->recoverd_pid = fork();
+	if (ctdb->recoverd_pid == -1) {
+		return -1;
+	}
+	
+	if (ctdb->recoverd_pid != 0) {
+		close(fd[0]);
+		event_add_timed(ctdb->ev, ctdb, 
+				timeval_current_ofs(30, 0),
+				ctdb_check_recd, ctdb);
+		return 0;
+	}
+
+	close(fd[1]);
+
+	srandom(getpid() ^ time(NULL));
+
+	if (switch_from_server_to_client(ctdb, "recoverd") != 0) {
+		DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch recovery daemon into client mode. shutting down.\n"));
+		exit(1);
+	}
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to recovery daemon\n", fd[0]));
+
+	fde = event_add_fd(ctdb->ev, ctdb, fd[0], EVENT_FD_READ,
+		     ctdb_recoverd_parent, &fd[0]);	
+	tevent_fd_set_auto_close(fde);
+
+	/* set up a handler to pick up sigchld */
+	se = event_add_signal(ctdb->ev, ctdb,
+				     SIGCHLD, 0,
+				     recd_sig_child_handler,
+				     ctdb);
+	if (se == NULL) {
+		DEBUG(DEBUG_CRIT,("Failed to set up signal handler for SIGCHLD in recovery daemon\n"));
+		exit(1);
+	}
+
+	monitor_cluster(ctdb);
+
+	DEBUG(DEBUG_ALERT,("ERROR: ctdb_recoverd finished!?\n"));
+	return -1;
+}
+
+/*
+  shutdown the recovery daemon
+ */
+void ctdb_stop_recoverd(struct ctdb_context *ctdb)
+{
+	if (ctdb->recoverd_pid == 0) {
+		return;
+	}
+
+	DEBUG(DEBUG_NOTICE,("Shutting down recovery daemon\n"));
+	kill(ctdb->recoverd_pid, SIGTERM);
+}
+
+static void ctdb_restart_recd(struct event_context *ev, struct timed_event *te, 
+		       struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+
+	DEBUG(DEBUG_ERR,("Restarting recovery daemon\n"));
+	ctdb_stop_recoverd(ctdb);
+	ctdb_start_recoverd(ctdb);
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_server.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_server.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_server.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,728 @@
+/* 
+   ctdb main protocol code
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/tevent/tevent.h"
+#include "lib/util/dlinklist.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "../include/ctdb_private.h"
+
+/*
+  choose the transport we will use
+*/
+int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport)
+{
+	ctdb->transport = talloc_strdup(ctdb, transport);
+	CTDB_NO_MEMORY(ctdb, ctdb->transport);
+
+	return 0;
+}
+
+/*
+  Check whether an ip is a valid node ip
+  Returns the node id for this ip address or -1
+*/
+int ctdb_ip_to_nodeid(struct ctdb_context *ctdb, const char *nodeip)
+{
+	int nodeid;
+
+	for (nodeid=0;nodeid<ctdb->num_nodes;nodeid++) {
+		if (ctdb->nodes[nodeid]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		if (!strcmp(ctdb->nodes[nodeid]->address.address, nodeip)) {
+			return nodeid;
+		}
+	}
+
+	return -1;
+}
+
+/*
+  choose the recovery lock file
+*/
+int ctdb_set_recovery_lock_file(struct ctdb_context *ctdb, const char *file)
+{
+	if (ctdb->recovery_lock_file != NULL) {
+		talloc_free(ctdb->recovery_lock_file);
+		ctdb->recovery_lock_file = NULL;
+	}
+
+	if (file == NULL) {
+		DEBUG(DEBUG_ALERT,("Recovery lock file set to \"\". Disabling recovery lock checking\n"));
+		ctdb->tunable.verify_recovery_lock = 0;
+		return 0;
+	}
+
+	ctdb->recovery_lock_file = talloc_strdup(ctdb, file);
+	CTDB_NO_MEMORY(ctdb, ctdb->recovery_lock_file);
+
+	return 0;
+}
+
+/*
+  set the directory for the local databases
+*/
+int ctdb_set_tdb_dir(struct ctdb_context *ctdb, const char *dir)
+{
+	ctdb->db_directory = talloc_strdup(ctdb, dir);
+	if (ctdb->db_directory == NULL) {
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  set the directory for the persistent databases
+*/
+int ctdb_set_tdb_dir_persistent(struct ctdb_context *ctdb, const char *dir)
+{
+	ctdb->db_directory_persistent = talloc_strdup(ctdb, dir);
+	if (ctdb->db_directory_persistent == NULL) {
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  set the directory for internal state databases
+*/
+int ctdb_set_tdb_dir_state(struct ctdb_context *ctdb, const char *dir)
+{
+	ctdb->db_directory_state = talloc_strdup(ctdb, dir);
+	if (ctdb->db_directory_state == NULL) {
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  add a node to the list of nodes
+*/
+static int ctdb_add_node(struct ctdb_context *ctdb, char *nstr)
+{
+	struct ctdb_node *node, **nodep;
+
+	nodep = talloc_realloc(ctdb, ctdb->nodes, struct ctdb_node *, ctdb->num_nodes+1);
+	CTDB_NO_MEMORY(ctdb, nodep);
+
+	ctdb->nodes = nodep;
+	nodep = &ctdb->nodes[ctdb->num_nodes];
+	(*nodep) = talloc_zero(ctdb->nodes, struct ctdb_node);
+	CTDB_NO_MEMORY(ctdb, *nodep);
+	node = *nodep;
+
+	if (ctdb_parse_address(ctdb, node, nstr, &node->address) != 0) {
+		return -1;
+	}
+	node->ctdb = ctdb;
+	node->name = talloc_asprintf(node, "%s:%u", 
+				     node->address.address, 
+				     node->address.port);
+	/* this assumes that the nodes are kept in sorted order, and no gaps */
+	node->pnn = ctdb->num_nodes;
+
+	/* nodes start out disconnected and unhealthy */
+	node->flags = (NODE_FLAGS_DISCONNECTED | NODE_FLAGS_UNHEALTHY);
+
+	if (ctdb->address.address &&
+	    ctdb_same_address(&ctdb->address, &node->address)) {
+		/* for automatic binding to interfaces, see tcp_connect.c */
+		ctdb->pnn = node->pnn;
+		node->flags &= ~NODE_FLAGS_DISCONNECTED;
+
+		/* do we start out in DISABLED mode? */
+		if (ctdb->start_as_disabled != 0) {
+			DEBUG(DEBUG_INFO, ("This node is configured to start in DISABLED state\n"));
+			node->flags |= NODE_FLAGS_DISABLED;
+		}
+		/* do we start out in STOPPED mode? */
+		if (ctdb->start_as_stopped != 0) {
+			DEBUG(DEBUG_INFO, ("This node is configured to start in STOPPED state\n"));
+			node->flags |= NODE_FLAGS_STOPPED;
+		}
+	}
+
+	ctdb->num_nodes++;
+	node->dead_count = 0;
+
+	return 0;
+}
+
+/*
+  add an entry for a "deleted" node to the list of nodes.
+  a "deleted" node is a node that is commented out from the nodes file.
+  this is used to prevent that subsequent nodes in the nodes list
+  change their pnn value if a node is "delete" by commenting it out and then
+  using "ctdb reloadnodes" at runtime.
+*/
+static int ctdb_add_deleted_node(struct ctdb_context *ctdb)
+{
+	struct ctdb_node *node, **nodep;
+
+	nodep = talloc_realloc(ctdb, ctdb->nodes, struct ctdb_node *, ctdb->num_nodes+1);
+	CTDB_NO_MEMORY(ctdb, nodep);
+
+	ctdb->nodes = nodep;
+	nodep = &ctdb->nodes[ctdb->num_nodes];
+	(*nodep) = talloc_zero(ctdb->nodes, struct ctdb_node);
+	CTDB_NO_MEMORY(ctdb, *nodep);
+	node = *nodep;
+	
+	if (ctdb_parse_address(ctdb, node, "0.0.0.0", &node->address) != 0) {
+		DEBUG(DEBUG_ERR,("Failed to setup deleted node %d\n", ctdb->num_nodes));
+		return -1;
+	}
+	node->ctdb = ctdb;
+	node->name = talloc_strdup(node, "0.0.0.0:0");
+
+	/* this assumes that the nodes are kept in sorted order, and no gaps */
+	node->pnn = ctdb->num_nodes;
+
+	/* this node is permanently deleted/disconnected */
+	node->flags = NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED;
+
+	ctdb->num_nodes++;
+	node->dead_count = 0;
+
+	return 0;
+}
+
+
+/*
+  setup the node list from a file
+*/
+int ctdb_set_nlist(struct ctdb_context *ctdb, const char *nlist)
+{
+	char **lines;
+	int nlines;
+	int i, j, num_present;
+
+	talloc_free(ctdb->nodes);
+	ctdb->nodes     = NULL;
+	ctdb->num_nodes = 0;
+
+	lines = file_lines_load(nlist, &nlines, ctdb);
+	if (lines == NULL) {
+		ctdb_set_error(ctdb, "Failed to load nlist '%s'\n", nlist);
+		return -1;
+	}
+	while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
+		nlines--;
+	}
+
+	num_present = 0;
+	for (i=0; i < nlines; i++) {
+		char *node;
+
+		node = lines[i];
+		/* strip leading spaces */
+		while((*node == ' ') || (*node == '\t')) {
+			node++;
+		}
+		if (*node == '#') {
+			if (ctdb_add_deleted_node(ctdb) != 0) {
+				talloc_free(lines);
+				return -1;
+			}
+			continue;
+		}
+		if (strcmp(node, "") == 0) {
+			continue;
+		}
+		if (ctdb_add_node(ctdb, node) != 0) {
+			talloc_free(lines);
+			return -1;
+		}
+		num_present++;
+	}
+
+	/* initialize the vnn mapping table now that we have the nodes list,
+	   skipping any deleted nodes
+	*/
+	ctdb->vnn_map = talloc(ctdb, struct ctdb_vnn_map);
+	CTDB_NO_MEMORY(ctdb, ctdb->vnn_map);
+
+	ctdb->vnn_map->generation = INVALID_GENERATION;
+	ctdb->vnn_map->size = num_present;
+	ctdb->vnn_map->map = talloc_array(ctdb->vnn_map, uint32_t, ctdb->vnn_map->size);
+	CTDB_NO_MEMORY(ctdb, ctdb->vnn_map->map);
+
+	for(i=0, j=0; i < ctdb->vnn_map->size; i++) {
+		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		ctdb->vnn_map->map[j] = i;
+		j++;
+	}
+	
+	talloc_free(lines);
+	return 0;
+}
+
+
+/*
+  setup the local node address
+*/
+int ctdb_set_address(struct ctdb_context *ctdb, const char *address)
+{
+	if (ctdb_parse_address(ctdb, ctdb, address, &ctdb->address) != 0) {
+		return -1;
+	}
+	
+	ctdb->name = talloc_asprintf(ctdb, "%s:%u", 
+				     ctdb->address.address, 
+				     ctdb->address.port);
+	return 0;
+}
+
+
+/*
+  return the number of active nodes
+*/
+uint32_t ctdb_get_num_active_nodes(struct ctdb_context *ctdb)
+{
+	int i;
+	uint32_t count=0;
+	for (i=0; i < ctdb->num_nodes; i++) {
+		if (!(ctdb->nodes[i]->flags & NODE_FLAGS_INACTIVE)) {
+			count++;
+		}
+	}
+	return count;
+}
+
+
+/*
+  called when we need to process a packet. This can be a requeued packet
+  after a lockwait, or a real packet from another node
+*/
+void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	TALLOC_CTX *tmp_ctx;
+
+	/* place the packet as a child of the tmp_ctx. We then use
+	   talloc_free() below to free it. If any of the calls want
+	   to keep it, then they will steal it somewhere else, and the
+	   talloc_free() will only free the tmp_ctx */
+	tmp_ctx = talloc_new(ctdb);
+	talloc_steal(tmp_ctx, hdr);
+
+	DEBUG(DEBUG_DEBUG,(__location__ " ctdb request %u of type %u length %u from "
+		 "node %u to %u\n", hdr->reqid, hdr->operation, hdr->length,
+		 hdr->srcnode, hdr->destnode));
+
+	switch (hdr->operation) {
+	case CTDB_REQ_CALL:
+	case CTDB_REPLY_CALL:
+	case CTDB_REQ_DMASTER:
+	case CTDB_REPLY_DMASTER:
+		/* we dont allow these calls when banned */
+		if (ctdb->nodes[ctdb->pnn]->flags & NODE_FLAGS_BANNED) {
+			DEBUG(DEBUG_DEBUG,(__location__ " ctdb operation %u"
+				" request %u"
+				" length %u from node %u to %u while node"
+				" is banned\n",
+				 hdr->operation, hdr->reqid,
+				 hdr->length, 
+				 hdr->srcnode, hdr->destnode));
+			goto done;
+		}
+
+		/* for ctdb_call inter-node operations verify that the
+		   remote node that sent us the call is running in the
+		   same generation instance as this node
+		*/
+		if (ctdb->vnn_map->generation != hdr->generation) {
+			DEBUG(DEBUG_DEBUG,(__location__ " ctdb operation %u"
+				" request %u"
+				" length %u from node %u to %u had an"
+				" invalid generation id:%u while our"
+				" generation id is:%u\n", 
+				 hdr->operation, hdr->reqid,
+				 hdr->length, 
+				 hdr->srcnode, hdr->destnode, 
+				 hdr->generation, ctdb->vnn_map->generation));
+			goto done;
+		}
+	}
+
+	switch (hdr->operation) {
+	case CTDB_REQ_CALL:
+		CTDB_INCREMENT_STAT(ctdb, node.req_call);
+		ctdb_request_call(ctdb, hdr);
+		break;
+
+	case CTDB_REPLY_CALL:
+		CTDB_INCREMENT_STAT(ctdb, node.reply_call);
+		ctdb_reply_call(ctdb, hdr);
+		break;
+
+	case CTDB_REPLY_ERROR:
+		CTDB_INCREMENT_STAT(ctdb, node.reply_error);
+		ctdb_reply_error(ctdb, hdr);
+		break;
+
+	case CTDB_REQ_DMASTER:
+		CTDB_INCREMENT_STAT(ctdb, node.req_dmaster);
+		ctdb_request_dmaster(ctdb, hdr);
+		break;
+
+	case CTDB_REPLY_DMASTER:
+		CTDB_INCREMENT_STAT(ctdb, node.reply_dmaster);
+		ctdb_reply_dmaster(ctdb, hdr);
+		break;
+
+	case CTDB_REQ_MESSAGE:
+		CTDB_INCREMENT_STAT(ctdb, node.req_message);
+		ctdb_request_message(ctdb, hdr);
+		break;
+
+	case CTDB_REQ_CONTROL:
+		CTDB_INCREMENT_STAT(ctdb, node.req_control);
+		ctdb_request_control(ctdb, hdr);
+		break;
+
+	case CTDB_REPLY_CONTROL:
+		CTDB_INCREMENT_STAT(ctdb, node.reply_control);
+		ctdb_reply_control(ctdb, hdr);
+		break;
+
+	case CTDB_REQ_KEEPALIVE:
+		CTDB_INCREMENT_STAT(ctdb, keepalive_packets_recv);
+		break;
+
+	default:
+		DEBUG(DEBUG_CRIT,("%s: Packet with unknown operation %u\n", 
+			 __location__, hdr->operation));
+		break;
+	}
+
+done:
+	talloc_free(tmp_ctx);
+}
+
+
+/*
+  called by the transport layer when a node is dead
+*/
+void ctdb_node_dead(struct ctdb_node *node)
+{
+	if (node->flags & NODE_FLAGS_DISCONNECTED) {
+		DEBUG(DEBUG_INFO,("%s: node %s is already marked disconnected: %u connected\n", 
+			 node->ctdb->name, node->name, 
+			 node->ctdb->num_connected));
+		return;
+	}
+	node->ctdb->num_connected--;
+	node->flags |= NODE_FLAGS_DISCONNECTED | NODE_FLAGS_UNHEALTHY;
+	node->rx_cnt = 0;
+	node->dead_count = 0;
+
+	DEBUG(DEBUG_NOTICE,("%s: node %s is dead: %u connected\n", 
+		 node->ctdb->name, node->name, node->ctdb->num_connected));
+	ctdb_daemon_cancel_controls(node->ctdb, node);
+
+	if (node->ctdb->methods == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Can not restart transport while shutting down daemon.\n"));
+		return;
+	}
+
+	node->ctdb->methods->restart(node);
+}
+
+/*
+  called by the transport layer when a node is connected
+*/
+void ctdb_node_connected(struct ctdb_node *node)
+{
+	if (!(node->flags & NODE_FLAGS_DISCONNECTED)) {
+		DEBUG(DEBUG_INFO,("%s: node %s is already marked connected: %u connected\n", 
+			 node->ctdb->name, node->name, 
+			 node->ctdb->num_connected));
+		return;
+	}
+	node->ctdb->num_connected++;
+	node->dead_count = 0;
+	node->flags &= ~NODE_FLAGS_DISCONNECTED;
+	node->flags |= NODE_FLAGS_UNHEALTHY;
+	DEBUG(DEBUG_INFO,("%s: connected to %s - %u connected\n", 
+		 node->ctdb->name, node->name, node->ctdb->num_connected));
+}
+
+struct queue_next {
+	struct ctdb_context *ctdb;
+	struct ctdb_req_header *hdr;
+};
+
+
+/*
+  triggered when a deferred packet is due
+ */
+static void queue_next_trigger(struct event_context *ev, struct timed_event *te, 
+			       struct timeval t, void *private_data)
+{
+	struct queue_next *q = talloc_get_type(private_data, struct queue_next);
+	ctdb_input_pkt(q->ctdb, q->hdr);
+	talloc_free(q);
+}	
+
+/*
+  defer a packet, so it is processed on the next event loop
+  this is used for sending packets to ourselves
+ */
+static void ctdb_defer_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct queue_next *q;
+	q = talloc(ctdb, struct queue_next);
+	if (q == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to allocate deferred packet\n"));
+		return;
+	}
+	q->ctdb = ctdb;
+	q->hdr = talloc_memdup(ctdb, hdr, hdr->length);
+	if (q->hdr == NULL) {
+		DEBUG(DEBUG_ERR,("Error copying deferred packet to self\n"));
+		return;
+	}
+#if 0
+	/* use this to put packets directly into our recv function */
+	ctdb_input_pkt(q->ctdb, q->hdr);
+#else
+	event_add_timed(ctdb->ev, q, timeval_zero(), queue_next_trigger, q);
+#endif
+}
+
+
+/*
+  broadcast a packet to all nodes
+*/
+static void ctdb_broadcast_packet_all(struct ctdb_context *ctdb, 
+				      struct ctdb_req_header *hdr)
+{
+	int i;
+	for (i=0; i < ctdb->num_nodes; i++) {
+		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		hdr->destnode = ctdb->nodes[i]->pnn;
+		ctdb_queue_packet(ctdb, hdr);
+	}
+}
+
+/*
+  broadcast a packet to all nodes in the current vnnmap
+*/
+static void ctdb_broadcast_packet_vnnmap(struct ctdb_context *ctdb, 
+					 struct ctdb_req_header *hdr)
+{
+	int i;
+	for (i=0;i<ctdb->vnn_map->size;i++) {
+		hdr->destnode = ctdb->vnn_map->map[i];
+		ctdb_queue_packet(ctdb, hdr);
+	}
+}
+
+/*
+  broadcast a packet to all connected nodes
+*/
+static void ctdb_broadcast_packet_connected(struct ctdb_context *ctdb, 
+					    struct ctdb_req_header *hdr)
+{
+	int i;
+	for (i=0; i < ctdb->num_nodes; i++) {
+		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		if (!(ctdb->nodes[i]->flags & NODE_FLAGS_DISCONNECTED)) {
+			hdr->destnode = ctdb->nodes[i]->pnn;
+			ctdb_queue_packet(ctdb, hdr);
+		}
+	}
+}
+
+/*
+  queue a packet or die
+*/
+void ctdb_queue_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+	struct ctdb_node *node;
+
+	switch (hdr->destnode) {
+	case CTDB_BROADCAST_ALL:
+		ctdb_broadcast_packet_all(ctdb, hdr);
+		return;
+	case CTDB_BROADCAST_VNNMAP:
+		ctdb_broadcast_packet_vnnmap(ctdb, hdr);
+		return;
+	case CTDB_BROADCAST_CONNECTED:
+		ctdb_broadcast_packet_connected(ctdb, hdr);
+		return;
+	}
+
+	CTDB_INCREMENT_STAT(ctdb, node_packets_sent);
+
+	if (!ctdb_validate_pnn(ctdb, hdr->destnode)) {
+	  	DEBUG(DEBUG_CRIT,(__location__ " cant send to node %u that does not exist\n", 
+			 hdr->destnode));
+		return;
+	}
+
+	node = ctdb->nodes[hdr->destnode];
+
+	if (node->flags & NODE_FLAGS_DELETED) {
+		DEBUG(DEBUG_ERR, (__location__ " Can not queue packet to DELETED node %d\n", hdr->destnode));
+		return;
+	}
+
+	if (node->pnn == ctdb->pnn) {
+		ctdb_defer_packet(ctdb, hdr);
+		return;
+	}
+
+	if (ctdb->methods == NULL) {
+		DEBUG(DEBUG_ALERT, (__location__ " Can not queue packet. "
+				    "Transport is DOWN\n"));
+		return;
+	}
+
+	node->tx_cnt++;
+	if (ctdb->methods->queue_pkt(node, (uint8_t *)hdr, hdr->length) != 0) {
+		ctdb_fatal(ctdb, "Unable to queue packet\n");
+	}
+}
+
+
+
+
+/*
+  a valgrind hack to allow us to get opcode specific backtraces
+  very ugly, and relies on no compiler optimisation!
+*/
+void ctdb_queue_packet_opcode(struct ctdb_context *ctdb, struct ctdb_req_header *hdr, unsigned opcode)
+{
+	switch (opcode) {
+#define DO_OP(x) case x: ctdb_queue_packet(ctdb, hdr); break
+		DO_OP(1);
+		DO_OP(2);
+		DO_OP(3);
+		DO_OP(4);
+		DO_OP(5);
+		DO_OP(6);
+		DO_OP(7);
+		DO_OP(8);
+		DO_OP(9);
+		DO_OP(10);
+		DO_OP(11);
+		DO_OP(12);
+		DO_OP(13);
+		DO_OP(14);
+		DO_OP(15);
+		DO_OP(16);
+		DO_OP(17);
+		DO_OP(18);
+		DO_OP(19);
+		DO_OP(20);
+		DO_OP(21);
+		DO_OP(22);
+		DO_OP(23);
+		DO_OP(24);
+		DO_OP(25);
+		DO_OP(26);
+		DO_OP(27);
+		DO_OP(28);
+		DO_OP(29);
+		DO_OP(30);
+		DO_OP(31);
+		DO_OP(32);
+		DO_OP(33);
+		DO_OP(34);
+		DO_OP(35);
+		DO_OP(36);
+		DO_OP(37);
+		DO_OP(38);
+		DO_OP(39);
+		DO_OP(40);
+		DO_OP(41);
+		DO_OP(42);
+		DO_OP(43);
+		DO_OP(44);
+		DO_OP(45);
+		DO_OP(46);
+		DO_OP(47);
+		DO_OP(48);
+		DO_OP(49);
+		DO_OP(50);
+		DO_OP(51);
+		DO_OP(52);
+		DO_OP(53);
+		DO_OP(54);
+		DO_OP(55);
+		DO_OP(56);
+		DO_OP(57);
+		DO_OP(58);
+		DO_OP(59);
+		DO_OP(60);
+		DO_OP(61);
+		DO_OP(62);
+		DO_OP(63);
+		DO_OP(64);
+		DO_OP(65);
+		DO_OP(66);
+		DO_OP(67);
+		DO_OP(68);
+		DO_OP(69);
+		DO_OP(70);
+		DO_OP(71);
+		DO_OP(72);
+		DO_OP(73);
+		DO_OP(74);
+		DO_OP(75);
+		DO_OP(76);
+		DO_OP(77);
+		DO_OP(78);
+		DO_OP(79);
+		DO_OP(80);
+		DO_OP(81);
+		DO_OP(82);
+		DO_OP(83);
+		DO_OP(84);
+		DO_OP(85);
+		DO_OP(86);
+		DO_OP(87);
+		DO_OP(88);
+		DO_OP(89);
+		DO_OP(90);
+		DO_OP(91);
+		DO_OP(92);
+		DO_OP(93);
+		DO_OP(94);
+		DO_OP(95);
+		DO_OP(96);
+		DO_OP(97);
+		DO_OP(98);
+		DO_OP(99);
+		DO_OP(100);
+	default: 
+		ctdb_queue_packet(ctdb, hdr);
+		break;
+	}
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_serverids.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_serverids.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_serverids.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,189 @@
+/* 
+   ctdb_control protocol code to manage server ids
+
+   Copyright (C) Ronnie Sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "../include/ctdb_private.h"
+#include "../common/rb_tree.h"
+
+
+#define SERVER_ID_KEY_SIZE 3
+static uint32_t *get_server_id_key(struct ctdb_server_id *server_id)
+{
+	static uint32_t key[SERVER_ID_KEY_SIZE];
+
+	key[0] = server_id->type;
+	key[1] = server_id->pnn;
+	key[2] = server_id->server_id;
+
+	return &key[0];
+}
+
+/* add a server_id to the tree.
+   if we had already 'data' in the tree then this is a duplicate and we can
+   just talloc_free the structure in parm and leave data in the tree.
+   othervise if this is a new node we return parm and that is inserted
+   into the tree.
+*/
+static void *add_server_id_callback(void *parm, void *data)
+{
+	if (data) {
+		talloc_free(parm);
+		return data;
+	}
+	return parm;
+}
+
+/*
+  register a server id
+  a serverid that is registered with ctdb will be automatically unregistered
+  once the client domain socket dissappears.
+ */
+int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb, 
+				 uint32_t client_id,
+				 TDB_DATA indata)
+{
+	struct ctdb_server_id *server_id;
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+
+
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Could not find client parent structure. You can not send this control to a remote node\n"));
+		return 1;
+	}
+
+	/* hang the server_id structure off client before storing it in the
+	   tree so that is will be automatically destroyed when client
+	   is destroyed. 
+	   when the structure is free'd it will be automatically
+	   removed from the tree
+	*/
+	server_id = talloc_zero(client, struct ctdb_server_id);
+	CTDB_NO_MEMORY(ctdb, server_id);
+	memcpy(server_id, indata.dptr, sizeof(struct ctdb_server_id));
+
+	trbt_insertarray32_callback(ctdb->server_ids, SERVER_ID_KEY_SIZE,
+		get_server_id_key(server_id), 
+		add_server_id_callback, server_id);
+
+	return 0;
+}
+
+
+/*
+  check whether a server id exists
+ */
+int32_t ctdb_control_check_server_id(struct ctdb_context *ctdb, 
+				 TDB_DATA indata)
+{
+	struct ctdb_server_id *server_id = (struct ctdb_server_id *)indata.dptr;
+
+	return trbt_lookuparray32(ctdb->server_ids, 
+				  SERVER_ID_KEY_SIZE,
+				  get_server_id_key(server_id)) == NULL? 0 : 1;
+}
+
+/*
+  unregisters a server id
+ */
+int32_t ctdb_control_unregister_server_id(struct ctdb_context *ctdb, 
+				 TDB_DATA indata)
+{
+	struct ctdb_server_id *server_id = (struct ctdb_server_id *)indata.dptr;
+
+	talloc_free(trbt_lookuparray32(ctdb->server_ids, 
+			SERVER_ID_KEY_SIZE,
+			get_server_id_key(server_id)));
+	return 0;
+}
+
+
+
+
+struct count_server_ids {
+	int count;
+	struct ctdb_server_id_list *list;
+};
+
+static void server_id_count(void *param, void *data)
+{
+	struct count_server_ids *svid = talloc_get_type(param, 
+						struct count_server_ids);
+
+	if (svid == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Got null pointer for svid\n"));
+		return;
+	}
+
+	svid->count++;
+}
+
+static void server_id_store(void *param, void *data)
+{
+	struct count_server_ids *svid = talloc_get_type(param, 
+						struct count_server_ids);
+	struct ctdb_server_id *server_id = talloc_get_type(data, 
+						struct ctdb_server_id);
+
+	if (svid == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Got null pointer for svid\n"));
+		return;
+	}
+
+	if (svid->count >= svid->list->num) {
+		DEBUG(DEBUG_ERR, (__location__ " size of server id tree changed during traverse\n"));
+		return;
+	}
+
+	memcpy(&svid->list->server_ids[svid->count], server_id, sizeof(struct ctdb_server_id));
+	svid->count++;
+}
+
+/* 
+   returns a list of all registered server ids for a node
+*/
+int32_t ctdb_control_get_server_id_list(struct ctdb_context *ctdb, TDB_DATA *outdata)
+{
+	struct count_server_ids *svid;
+
+
+	svid = talloc_zero(outdata, struct count_server_ids);
+	CTDB_NO_MEMORY(ctdb, svid);
+
+
+	/* first we must count how many entries we have */
+	trbt_traversearray32(ctdb->server_ids, SERVER_ID_KEY_SIZE,
+			server_id_count, svid);
+
+
+	outdata->dsize = offsetof(struct ctdb_server_id_list, 
+				server_ids)
+			+ sizeof(struct ctdb_server_id) * svid->count;
+	outdata->dptr  = talloc_size(outdata, outdata->dsize);
+	CTDB_NO_MEMORY(ctdb, outdata->dptr);
+
+
+	/* now fill the structure in */
+	svid->list = (struct ctdb_server_id_list *)(outdata->dptr);
+	svid->list->num = svid->count;
+	svid->count=0;
+	trbt_traversearray32(ctdb->server_ids, SERVER_ID_KEY_SIZE,
+			server_id_store, svid);
+
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_statistics.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_statistics.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_statistics.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,79 @@
+/* 
+   ctdb statistics code
+
+   Copyright (C) Ronnie Sahlberg 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <string.h>
+#include "lib/tevent/tevent.h"
+#include "../include/ctdb_private.h"
+
+static void ctdb_statistics_update(struct event_context *ev, struct timed_event *te, 
+				   struct timeval t, void *p)
+{
+	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
+
+	memmove(&ctdb->statistics_history[1], &ctdb->statistics_history[0], (MAX_STAT_HISTORY-1)*sizeof(struct ctdb_statistics));
+	memcpy(&ctdb->statistics_history[0], &ctdb->statistics_current, sizeof(struct ctdb_statistics));
+	ctdb->statistics_history[0].statistics_current_time = timeval_current();
+
+
+	bzero(&ctdb->statistics_current, sizeof(struct ctdb_statistics));
+	ctdb->statistics_current.statistics_start_time = timeval_current();
+
+	
+	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(ctdb->tunable.stat_history_interval, 0), ctdb_statistics_update, ctdb);
+}
+
+int ctdb_statistics_init(struct ctdb_context *ctdb)
+{
+	bzero(&ctdb->statistics, sizeof(struct ctdb_statistics));
+	ctdb->statistics.statistics_start_time = timeval_current();
+
+	bzero(&ctdb->statistics_current, sizeof(struct ctdb_statistics));
+	ctdb->statistics_current.statistics_start_time = timeval_current();
+
+	bzero(ctdb->statistics_history, sizeof(ctdb->statistics_history));
+
+	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(ctdb->tunable.stat_history_interval, 0), ctdb_statistics_update, ctdb);
+	return 0;
+}
+
+
+int32_t ctdb_control_get_stat_history(struct ctdb_context *ctdb, 
+				      struct ctdb_req_control *c,
+				      TDB_DATA *outdata)
+{
+	int len;
+	struct ctdb_statistics_wire *stat;
+
+	len = offsetof(struct ctdb_statistics_wire, stats) + MAX_STAT_HISTORY*sizeof(struct ctdb_statistics);
+
+	stat = talloc_size(outdata, len);
+	if (stat == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to allocate statistics history structure\n"));
+		return -1;
+	}
+
+	stat->num = MAX_STAT_HISTORY;
+	memcpy(&stat->stats[0], &ctdb->statistics_history[0], sizeof(ctdb->statistics_history));
+
+	outdata->dsize = len;
+	outdata->dptr  = (uint8_t *)stat;
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_takeover.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_takeover.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_takeover.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,3463 @@
+/* 
+   ctdb ip takeover code
+
+   Copyright (C) Ronnie Sahlberg  2007
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Martin Schwenke  2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/util/dlinklist.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+#include "../common/rb_tree.h"
+
+
+#define TAKEOVER_TIMEOUT() timeval_current_ofs(ctdb->tunable.takeover_timeout,0)
+
+#define CTDB_ARP_INTERVAL 1
+#define CTDB_ARP_REPEAT   3
+
+struct ctdb_iface {
+	struct ctdb_iface *prev, *next;
+	const char *name;
+	bool link_up;
+	uint32_t references;
+};
+
+static const char *ctdb_vnn_iface_string(const struct ctdb_vnn *vnn)
+{
+	if (vnn->iface) {
+		return vnn->iface->name;
+	}
+
+	return "__none__";
+}
+
+static int ctdb_add_local_iface(struct ctdb_context *ctdb, const char *iface)
+{
+	struct ctdb_iface *i;
+
+	/* Verify that we dont have an entry for this ip yet */
+	for (i=ctdb->ifaces;i;i=i->next) {
+		if (strcmp(i->name, iface) == 0) {
+			return 0;
+		}
+	}
+
+	/* create a new structure for this interface */
+	i = talloc_zero(ctdb, struct ctdb_iface);
+	CTDB_NO_MEMORY_FATAL(ctdb, i);
+	i->name = talloc_strdup(i, iface);
+	CTDB_NO_MEMORY(ctdb, i->name);
+	i->link_up = false;
+
+	DLIST_ADD(ctdb->ifaces, i);
+
+	return 0;
+}
+
+static struct ctdb_iface *ctdb_find_iface(struct ctdb_context *ctdb,
+					  const char *iface)
+{
+	struct ctdb_iface *i;
+
+	/* Verify that we dont have an entry for this ip yet */
+	for (i=ctdb->ifaces;i;i=i->next) {
+		if (strcmp(i->name, iface) == 0) {
+			return i;
+		}
+	}
+
+	return NULL;
+}
+
+static struct ctdb_iface *ctdb_vnn_best_iface(struct ctdb_context *ctdb,
+					      struct ctdb_vnn *vnn)
+{
+	int i;
+	struct ctdb_iface *cur = NULL;
+	struct ctdb_iface *best = NULL;
+
+	for (i=0; vnn->ifaces[i]; i++) {
+
+		cur = ctdb_find_iface(ctdb, vnn->ifaces[i]);
+		if (cur == NULL) {
+			continue;
+		}
+
+		if (!cur->link_up) {
+			continue;
+		}
+
+		if (best == NULL) {
+			best = cur;
+			continue;
+		}
+
+		if (cur->references < best->references) {
+			best = cur;
+			continue;
+		}
+	}
+
+	return best;
+}
+
+static int32_t ctdb_vnn_assign_iface(struct ctdb_context *ctdb,
+				     struct ctdb_vnn *vnn)
+{
+	struct ctdb_iface *best = NULL;
+
+	if (vnn->iface) {
+		DEBUG(DEBUG_INFO, (__location__ " public address '%s' "
+				   "still assigned to iface '%s'\n",
+				   ctdb_addr_to_str(&vnn->public_address),
+				   ctdb_vnn_iface_string(vnn)));
+		return 0;
+	}
+
+	best = ctdb_vnn_best_iface(ctdb, vnn);
+	if (best == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " public address '%s' "
+				  "cannot assign to iface any iface\n",
+				  ctdb_addr_to_str(&vnn->public_address)));
+		return -1;
+	}
+
+	vnn->iface = best;
+	best->references++;
+	vnn->pnn = ctdb->pnn;
+
+	DEBUG(DEBUG_INFO, (__location__ " public address '%s' "
+			   "now assigned to iface '%s' refs[%d]\n",
+			   ctdb_addr_to_str(&vnn->public_address),
+			   ctdb_vnn_iface_string(vnn),
+			   best->references));
+	return 0;
+}
+
+static void ctdb_vnn_unassign_iface(struct ctdb_context *ctdb,
+				    struct ctdb_vnn *vnn)
+{
+	DEBUG(DEBUG_INFO, (__location__ " public address '%s' "
+			   "now unassigned (old iface '%s' refs[%d])\n",
+			   ctdb_addr_to_str(&vnn->public_address),
+			   ctdb_vnn_iface_string(vnn),
+			   vnn->iface?vnn->iface->references:0));
+	if (vnn->iface) {
+		vnn->iface->references--;
+	}
+	vnn->iface = NULL;
+	if (vnn->pnn == ctdb->pnn) {
+		vnn->pnn = -1;
+	}
+}
+
+static bool ctdb_vnn_available(struct ctdb_context *ctdb,
+			       struct ctdb_vnn *vnn)
+{
+	int i;
+
+	if (vnn->iface && vnn->iface->link_up) {
+		return true;
+	}
+
+	for (i=0; vnn->ifaces[i]; i++) {
+		struct ctdb_iface *cur;
+
+		cur = ctdb_find_iface(ctdb, vnn->ifaces[i]);
+		if (cur == NULL) {
+			continue;
+		}
+
+		if (cur->link_up) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+struct ctdb_takeover_arp {
+	struct ctdb_context *ctdb;
+	uint32_t count;
+	ctdb_sock_addr addr;
+	struct ctdb_tcp_array *tcparray;
+	struct ctdb_vnn *vnn;
+};
+
+
+/*
+  lists of tcp endpoints
+ */
+struct ctdb_tcp_list {
+	struct ctdb_tcp_list *prev, *next;
+	struct ctdb_tcp_connection connection;
+};
+
+/*
+  list of clients to kill on IP release
+ */
+struct ctdb_client_ip {
+	struct ctdb_client_ip *prev, *next;
+	struct ctdb_context *ctdb;
+	ctdb_sock_addr addr;
+	uint32_t client_id;
+};
+
+
+/*
+  send a gratuitous arp
+ */
+static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *te, 
+				  struct timeval t, void *private_data)
+{
+	struct ctdb_takeover_arp *arp = talloc_get_type(private_data, 
+							struct ctdb_takeover_arp);
+	int i, ret;
+	struct ctdb_tcp_array *tcparray;
+	const char *iface = ctdb_vnn_iface_string(arp->vnn);
+
+	ret = ctdb_sys_send_arp(&arp->addr, iface);
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT,(__location__ " sending of arp failed on iface '%s' (%s)\n",
+				  iface, strerror(errno)));
+	}
+
+	tcparray = arp->tcparray;
+	if (tcparray) {
+		for (i=0;i<tcparray->num;i++) {
+			struct ctdb_tcp_connection *tcon;
+
+			tcon = &tcparray->connections[i];
+			DEBUG(DEBUG_INFO,("sending tcp tickle ack for %u->%s:%u\n",
+				(unsigned)ntohs(tcon->dst_addr.ip.sin_port), 
+				ctdb_addr_to_str(&tcon->src_addr),
+				(unsigned)ntohs(tcon->src_addr.ip.sin_port)));
+			ret = ctdb_sys_send_tcp(
+				&tcon->src_addr, 
+				&tcon->dst_addr,
+				0, 0, 0);
+			if (ret != 0) {
+				DEBUG(DEBUG_CRIT,(__location__ " Failed to send tcp tickle ack for %s\n",
+					ctdb_addr_to_str(&tcon->src_addr)));
+			}
+		}
+	}
+
+	arp->count++;
+
+	if (arp->count == CTDB_ARP_REPEAT) {
+		talloc_free(arp);
+		return;
+	}
+
+	event_add_timed(arp->ctdb->ev, arp->vnn->takeover_ctx, 
+			timeval_current_ofs(CTDB_ARP_INTERVAL, 100000), 
+			ctdb_control_send_arp, arp);
+}
+
+static int32_t ctdb_announce_vnn_iface(struct ctdb_context *ctdb,
+				       struct ctdb_vnn *vnn)
+{
+	struct ctdb_takeover_arp *arp;
+	struct ctdb_tcp_array *tcparray;
+
+	if (!vnn->takeover_ctx) {
+		vnn->takeover_ctx = talloc_new(vnn);
+		if (!vnn->takeover_ctx) {
+			return -1;
+		}
+	}
+
+	arp = talloc_zero(vnn->takeover_ctx, struct ctdb_takeover_arp);
+	if (!arp) {
+		return -1;
+	}
+
+	arp->ctdb = ctdb;
+	arp->addr = vnn->public_address;
+	arp->vnn  = vnn;
+
+	tcparray = vnn->tcp_array;
+	if (tcparray) {
+		/* add all of the known tcp connections for this IP to the
+		   list of tcp connections to send tickle acks for */
+		arp->tcparray = talloc_steal(arp, tcparray);
+
+		vnn->tcp_array = NULL;
+		vnn->tcp_update_needed = true;
+	}
+
+	event_add_timed(arp->ctdb->ev, vnn->takeover_ctx,
+			timeval_zero(), ctdb_control_send_arp, arp);
+
+	return 0;
+}
+
+struct takeover_callback_state {
+	struct ctdb_req_control *c;
+	ctdb_sock_addr *addr;
+	struct ctdb_vnn *vnn;
+};
+
+struct ctdb_do_takeip_state {
+	struct ctdb_req_control *c;
+	struct ctdb_vnn *vnn;
+};
+
+/*
+  called when takeip event finishes
+ */
+static void ctdb_do_takeip_callback(struct ctdb_context *ctdb, int status,
+				    void *private_data)
+{
+	struct ctdb_do_takeip_state *state =
+		talloc_get_type(private_data, struct ctdb_do_takeip_state);
+	int32_t ret;
+	TDB_DATA data;
+
+	if (status != 0) {
+		struct ctdb_node *node = ctdb->nodes[ctdb->pnn];
+	
+		if (status == -ETIME) {
+			ctdb_ban_self(ctdb);
+		}
+		DEBUG(DEBUG_ERR,(__location__ " Failed to takeover IP %s on interface %s\n",
+				 ctdb_addr_to_str(&state->vnn->public_address),
+				 ctdb_vnn_iface_string(state->vnn)));
+		ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
+
+		node->flags |= NODE_FLAGS_UNHEALTHY;
+		talloc_free(state);
+		return;
+	}
+
+	ret = ctdb_announce_vnn_iface(ctdb, state->vnn);
+	if (ret != 0) {
+		ctdb_request_control_reply(ctdb, state->c, NULL, -1, NULL);
+		talloc_free(state);
+		return;
+	}
+
+	data.dptr  = (uint8_t *)ctdb_addr_to_str(&state->vnn->public_address);
+	data.dsize = strlen((char *)data.dptr) + 1;
+	DEBUG(DEBUG_INFO,(__location__ " sending TAKE_IP for '%s'\n", data.dptr));
+
+	ctdb_daemon_send_message(ctdb, ctdb->pnn, CTDB_SRVID_TAKE_IP, data);
+
+
+	/* the control succeeded */
+	ctdb_request_control_reply(ctdb, state->c, NULL, 0, NULL);
+	talloc_free(state);
+	return;
+}
+
+/*
+  take over an ip address
+ */
+static int32_t ctdb_do_takeip(struct ctdb_context *ctdb,
+			      struct ctdb_req_control *c,
+			      struct ctdb_vnn *vnn)
+{
+	int ret;
+	struct ctdb_do_takeip_state *state;
+
+	ret = ctdb_vnn_assign_iface(ctdb, vnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Takeover of IP %s/%u failed to "
+				 "assin a usable interface\n",
+				 ctdb_addr_to_str(&vnn->public_address),
+				 vnn->public_netmask_bits));
+		return -1;
+	}
+
+	state = talloc(vnn, struct ctdb_do_takeip_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->c = talloc_steal(ctdb, c);
+	state->vnn   = vnn;
+
+	DEBUG(DEBUG_NOTICE,("Takeover of IP %s/%u on interface %s\n",
+			    ctdb_addr_to_str(&vnn->public_address),
+			    vnn->public_netmask_bits,
+			    ctdb_vnn_iface_string(vnn)));
+
+	ret = ctdb_event_script_callback(ctdb,
+					 state,
+					 ctdb_do_takeip_callback,
+					 state,
+					 false,
+					 CTDB_EVENT_TAKE_IP,
+					 "%s %s %u",
+					 ctdb_vnn_iface_string(vnn),
+					 ctdb_addr_to_str(&vnn->public_address),
+					 vnn->public_netmask_bits);
+
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to takeover IP %s on interface %s\n",
+			ctdb_addr_to_str(&vnn->public_address),
+			ctdb_vnn_iface_string(vnn)));
+		talloc_free(state);
+		return -1;
+	}
+
+	return 0;
+}
+
+struct ctdb_do_updateip_state {
+	struct ctdb_req_control *c;
+	struct ctdb_iface *old;
+	struct ctdb_vnn *vnn;
+};
+
+/*
+  called when updateip event finishes
+ */
+static void ctdb_do_updateip_callback(struct ctdb_context *ctdb, int status,
+				      void *private_data)
+{
+	struct ctdb_do_updateip_state *state =
+		talloc_get_type(private_data, struct ctdb_do_updateip_state);
+	int32_t ret;
+
+	if (status != 0) {
+		if (status == -ETIME) {
+			ctdb_ban_self(ctdb);
+		}
+		DEBUG(DEBUG_ERR,(__location__ " Failed to move IP %s from interface %s to %s\n",
+			ctdb_addr_to_str(&state->vnn->public_address),
+			state->old->name,
+			ctdb_vnn_iface_string(state->vnn)));
+
+		/*
+		 * All we can do is reset the old interface
+		 * and let the next run fix it
+		 */
+		ctdb_vnn_unassign_iface(ctdb, state->vnn);
+		state->vnn->iface = state->old;
+		state->vnn->iface->references++;
+
+		ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
+		talloc_free(state);
+		return;
+	}
+
+	ret = ctdb_announce_vnn_iface(ctdb, state->vnn);
+	if (ret != 0) {
+		ctdb_request_control_reply(ctdb, state->c, NULL, -1, NULL);
+		talloc_free(state);
+		return;
+	}
+
+	/* the control succeeded */
+	ctdb_request_control_reply(ctdb, state->c, NULL, 0, NULL);
+	talloc_free(state);
+	return;
+}
+
+/*
+  update (move) an ip address
+ */
+static int32_t ctdb_do_updateip(struct ctdb_context *ctdb,
+				struct ctdb_req_control *c,
+				struct ctdb_vnn *vnn)
+{
+	int ret;
+	struct ctdb_do_updateip_state *state;
+	struct ctdb_iface *old = vnn->iface;
+	const char *new_name;
+
+	ctdb_vnn_unassign_iface(ctdb, vnn);
+	ret = ctdb_vnn_assign_iface(ctdb, vnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("update of IP %s/%u failed to "
+				 "assin a usable interface (old iface '%s')\n",
+				 ctdb_addr_to_str(&vnn->public_address),
+				 vnn->public_netmask_bits,
+				 old->name));
+		return -1;
+	}
+
+	new_name = ctdb_vnn_iface_string(vnn);
+	if (old->name != NULL && new_name != NULL && !strcmp(old->name, new_name)) {
+		/* A benign update from one interface onto itself.
+		 * no need to run the eventscripts in this case, just return
+		 * success.
+		 */
+		ctdb_request_control_reply(ctdb, c, NULL, 0, NULL);
+		return 0;
+	}
+
+	state = talloc(vnn, struct ctdb_do_updateip_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->c = talloc_steal(ctdb, c);
+	state->old = old;
+	state->vnn = vnn;
+
+	DEBUG(DEBUG_NOTICE,("Update of IP %s/%u from "
+			    "interface %s to %s\n",
+			    ctdb_addr_to_str(&vnn->public_address),
+			    vnn->public_netmask_bits,
+			    old->name,
+			    new_name));
+
+	ret = ctdb_event_script_callback(ctdb,
+					 state,
+					 ctdb_do_updateip_callback,
+					 state,
+					 false,
+					 CTDB_EVENT_UPDATE_IP,
+					 "%s %s %s %u",
+					 state->old->name,
+					 new_name,
+					 ctdb_addr_to_str(&vnn->public_address),
+					 vnn->public_netmask_bits);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed update IP %s from interface %s to %s\n",
+				 ctdb_addr_to_str(&vnn->public_address),
+				 old->name, new_name));
+		talloc_free(state);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  Find the vnn of the node that has a public ip address
+  returns -1 if the address is not known as a public address
+ */
+static struct ctdb_vnn *find_public_ip_vnn(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
+{
+	struct ctdb_vnn *vnn;
+
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		if (ctdb_same_ip(&vnn->public_address, addr)) {
+			return vnn;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+  take over an ip address
+ */
+int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
+				 struct ctdb_req_control *c,
+				 TDB_DATA indata,
+				 bool *async_reply)
+{
+	int ret;
+	struct ctdb_public_ip *pip = (struct ctdb_public_ip *)indata.dptr;
+	struct ctdb_vnn *vnn;
+	bool have_ip = false;
+	bool do_updateip = false;
+	bool do_takeip = false;
+	struct ctdb_iface *best_iface = NULL;
+
+	if (pip->pnn != ctdb->pnn) {
+		DEBUG(DEBUG_ERR,(__location__" takeoverip called for an ip '%s' "
+				 "with pnn %d, but we're node %d\n",
+				 ctdb_addr_to_str(&pip->addr),
+				 pip->pnn, ctdb->pnn));
+		return -1;
+	}
+
+	/* update out vnn list */
+	vnn = find_public_ip_vnn(ctdb, &pip->addr);
+	if (vnn == NULL) {
+		DEBUG(DEBUG_INFO,("takeoverip called for an ip '%s' that is not a public address\n",
+			ctdb_addr_to_str(&pip->addr)));
+		return 0;
+	}
+
+	have_ip = ctdb_sys_have_ip(&pip->addr);
+	best_iface = ctdb_vnn_best_iface(ctdb, vnn);
+	if (best_iface == NULL) {
+		DEBUG(DEBUG_ERR,("takeoverip of IP %s/%u failed to find"
+				 "a usable interface (old %s, have_ip %d)\n",
+				 ctdb_addr_to_str(&vnn->public_address),
+				 vnn->public_netmask_bits,
+				 ctdb_vnn_iface_string(vnn),
+				 have_ip));
+		return -1;
+	}
+
+	if (vnn->iface == NULL && vnn->pnn == -1 && have_ip && best_iface != NULL) {
+		DEBUG(DEBUG_ERR,("Taking over newly created ip\n"));
+		have_ip = false;
+	}
+
+	if (vnn->iface == NULL && have_ip) {
+		DEBUG(DEBUG_CRIT,(__location__ " takeoverip of IP %s is known to the kernel, "
+				  "but we have no interface assigned, has someone manually configured it? Ignore for now.\n",
+				 ctdb_addr_to_str(&vnn->public_address)));
+		return 0;
+	}
+
+	if (vnn->pnn != ctdb->pnn && have_ip && vnn->pnn != -1) {
+		DEBUG(DEBUG_CRIT,(__location__ " takeoverip of IP %s is known to the kernel, "
+				  "and we have it on iface[%s], but it was assigned to node %d"
+				  "and we are node %d, banning ourself\n",
+				 ctdb_addr_to_str(&vnn->public_address),
+				 ctdb_vnn_iface_string(vnn), vnn->pnn, ctdb->pnn));
+		ctdb_ban_self(ctdb);
+		return -1;
+	}
+
+	if (vnn->pnn == -1 && have_ip) {
+		vnn->pnn = ctdb->pnn;
+		DEBUG(DEBUG_CRIT,(__location__ " takeoverip of IP %s is known to the kernel, "
+				  "and we already have it on iface[%s], update local daemon\n",
+				 ctdb_addr_to_str(&vnn->public_address),
+				  ctdb_vnn_iface_string(vnn)));
+		return 0;
+	}
+
+	if (vnn->iface) {
+		if (vnn->iface->link_up) {
+			/* only move when the rebalance gains something */
+			if (vnn->iface->references > (best_iface->references + 1)) {
+				do_updateip = true;
+			}
+		} else if (vnn->iface != best_iface) {
+			do_updateip = true;
+		}
+	}
+
+	if (!have_ip) {
+		if (do_updateip) {
+			ctdb_vnn_unassign_iface(ctdb, vnn);
+			do_updateip = false;
+		}
+		do_takeip = true;
+	}
+
+	if (do_takeip) {
+		ret = ctdb_do_takeip(ctdb, c, vnn);
+		if (ret != 0) {
+			return -1;
+		}
+	} else if (do_updateip) {
+		ret = ctdb_do_updateip(ctdb, c, vnn);
+		if (ret != 0) {
+			return -1;
+		}
+	} else {
+		/*
+		 * The interface is up and the kernel known the ip
+		 * => do nothing
+		 */
+		DEBUG(DEBUG_INFO,("Redundant takeover of IP %s/%u on interface %s (ip already held)\n",
+			ctdb_addr_to_str(&pip->addr),
+			vnn->public_netmask_bits,
+			ctdb_vnn_iface_string(vnn)));
+		return 0;
+	}
+
+	/* tell ctdb_control.c that we will be replying asynchronously */
+	*async_reply = true;
+
+	return 0;
+}
+
+/*
+  takeover an ip address old v4 style
+ */
+int32_t ctdb_control_takeover_ipv4(struct ctdb_context *ctdb, 
+				struct ctdb_req_control *c,
+				TDB_DATA indata, 
+				bool *async_reply)
+{
+	TDB_DATA data;
+	
+	data.dsize = sizeof(struct ctdb_public_ip);
+	data.dptr  = (uint8_t *)talloc_zero(c, struct ctdb_public_ip);
+	CTDB_NO_MEMORY(ctdb, data.dptr);
+	
+	memcpy(data.dptr, indata.dptr, indata.dsize);
+	return ctdb_control_takeover_ip(ctdb, c, data, async_reply);
+}
+
+/*
+  kill any clients that are registered with a IP that is being released
+ */
+static void release_kill_clients(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
+{
+	struct ctdb_client_ip *ip;
+
+	DEBUG(DEBUG_INFO,("release_kill_clients for ip %s\n",
+		ctdb_addr_to_str(addr)));
+
+	for (ip=ctdb->client_ip_list; ip; ip=ip->next) {
+		ctdb_sock_addr tmp_addr;
+
+		tmp_addr = ip->addr;
+		DEBUG(DEBUG_INFO,("checking for client %u with IP %s\n", 
+			ip->client_id,
+			ctdb_addr_to_str(&ip->addr)));
+
+		if (ctdb_same_ip(&tmp_addr, addr)) {
+			struct ctdb_client *client = ctdb_reqid_find(ctdb, 
+								     ip->client_id, 
+								     struct ctdb_client);
+			DEBUG(DEBUG_INFO,("matched client %u with IP %s and pid %u\n", 
+				ip->client_id,
+				ctdb_addr_to_str(&ip->addr),
+				client->pid));
+
+			if (client->pid != 0) {
+				DEBUG(DEBUG_INFO,(__location__ " Killing client pid %u for IP %s on client_id %u\n",
+					(unsigned)client->pid,
+					ctdb_addr_to_str(addr),
+					ip->client_id));
+				kill(client->pid, SIGKILL);
+			}
+		}
+	}
+}
+
+/*
+  called when releaseip event finishes
+ */
+static void release_ip_callback(struct ctdb_context *ctdb, int status, 
+				void *private_data)
+{
+	struct takeover_callback_state *state = 
+		talloc_get_type(private_data, struct takeover_callback_state);
+	TDB_DATA data;
+
+	if (status == -ETIME) {
+		ctdb_ban_self(ctdb);
+	}
+
+	/* send a message to all clients of this node telling them
+	   that the cluster has been reconfigured and they should
+	   release any sockets on this IP */
+	data.dptr = (uint8_t *)talloc_strdup(state, ctdb_addr_to_str(state->addr));
+	CTDB_NO_MEMORY_VOID(ctdb, data.dptr);
+	data.dsize = strlen((char *)data.dptr)+1;
+
+	DEBUG(DEBUG_INFO,(__location__ " sending RELEASE_IP for '%s'\n", data.dptr));
+
+	ctdb_daemon_send_message(ctdb, ctdb->pnn, CTDB_SRVID_RELEASE_IP, data);
+
+	/* kill clients that have registered with this IP */
+	release_kill_clients(ctdb, state->addr);
+
+	ctdb_vnn_unassign_iface(ctdb, state->vnn);
+
+	/* the control succeeded */
+	ctdb_request_control_reply(ctdb, state->c, NULL, 0, NULL);
+	talloc_free(state);
+}
+
+/*
+  release an ip address
+ */
+int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, 
+				struct ctdb_req_control *c,
+				TDB_DATA indata, 
+				bool *async_reply)
+{
+	int ret;
+	struct takeover_callback_state *state;
+	struct ctdb_public_ip *pip = (struct ctdb_public_ip *)indata.dptr;
+	struct ctdb_vnn *vnn;
+
+	/* update our vnn list */
+	vnn = find_public_ip_vnn(ctdb, &pip->addr);
+	if (vnn == NULL) {
+		DEBUG(DEBUG_INFO,("releaseip called for an ip '%s' that is not a public address\n",
+			ctdb_addr_to_str(&pip->addr)));
+		return 0;
+	}
+	vnn->pnn = pip->pnn;
+
+	/* stop any previous arps */
+	talloc_free(vnn->takeover_ctx);
+	vnn->takeover_ctx = NULL;
+
+	if (!ctdb_sys_have_ip(&pip->addr)) {
+		DEBUG(DEBUG_DEBUG,("Redundant release of IP %s/%u on interface %s (ip not held)\n", 
+			ctdb_addr_to_str(&pip->addr),
+			vnn->public_netmask_bits, 
+			ctdb_vnn_iface_string(vnn)));
+		ctdb_vnn_unassign_iface(ctdb, vnn);
+		return 0;
+	}
+
+	if (vnn->iface == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " release_ip of IP %s is known to the kernel, "
+				 "but we have no interface assigned, has someone manually configured it? Ignore for now.\n",
+				 ctdb_addr_to_str(&vnn->public_address)));
+		return 0;
+	}
+
+	DEBUG(DEBUG_NOTICE,("Release of IP %s/%u on interface %s  node:%d\n",
+		ctdb_addr_to_str(&pip->addr),
+		vnn->public_netmask_bits, 
+		ctdb_vnn_iface_string(vnn),
+		pip->pnn));
+
+	state = talloc(ctdb, struct takeover_callback_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->c = talloc_steal(state, c);
+	state->addr = talloc(state, ctdb_sock_addr);       
+	CTDB_NO_MEMORY(ctdb, state->addr);
+	*state->addr = pip->addr;
+	state->vnn   = vnn;
+
+	ret = ctdb_event_script_callback(ctdb, 
+					 state, release_ip_callback, state,
+					 false,
+					 CTDB_EVENT_RELEASE_IP,
+					 "%s %s %u",
+					 ctdb_vnn_iface_string(vnn),
+					 ctdb_addr_to_str(&pip->addr),
+					 vnn->public_netmask_bits);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to release IP %s on interface %s\n",
+			ctdb_addr_to_str(&pip->addr),
+			ctdb_vnn_iface_string(vnn)));
+		talloc_free(state);
+		return -1;
+	}
+
+	/* tell the control that we will be reply asynchronously */
+	*async_reply = true;
+	return 0;
+}
+
+/*
+  release an ip address old v4 style
+ */
+int32_t ctdb_control_release_ipv4(struct ctdb_context *ctdb, 
+				struct ctdb_req_control *c,
+				TDB_DATA indata, 
+				bool *async_reply)
+{
+	TDB_DATA data;
+	
+	data.dsize = sizeof(struct ctdb_public_ip);
+	data.dptr  = (uint8_t *)talloc_zero(c, struct ctdb_public_ip);
+	CTDB_NO_MEMORY(ctdb, data.dptr);
+	
+	memcpy(data.dptr, indata.dptr, indata.dsize);
+	return ctdb_control_release_ip(ctdb, c, data, async_reply);
+}
+
+
+static int ctdb_add_public_address(struct ctdb_context *ctdb,
+				   ctdb_sock_addr *addr,
+				   unsigned mask, const char *ifaces)
+{
+	struct ctdb_vnn      *vnn;
+	uint32_t num = 0;
+	char *tmp;
+	const char *iface;
+	int i;
+	int ret;
+
+	tmp = strdup(ifaces);
+	for (iface = strtok(tmp, ","); iface; iface = strtok(NULL, ",")) {
+		if (!ctdb_sys_check_iface_exists(iface)) {
+			DEBUG(DEBUG_CRIT,("Interface %s does not exist. Can not add public-address : %s\n", iface, ctdb_addr_to_str(addr)));
+			free(tmp);
+			return -1;
+		}
+	}
+	free(tmp);
+
+	/* Verify that we dont have an entry for this ip yet */
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		if (ctdb_same_sockaddr(addr, &vnn->public_address)) {
+			DEBUG(DEBUG_CRIT,("Same ip '%s' specified multiple times in the public address list \n", 
+				ctdb_addr_to_str(addr)));
+			return -1;
+		}		
+	}
+
+	/* create a new vnn structure for this ip address */
+	vnn = talloc_zero(ctdb, struct ctdb_vnn);
+	CTDB_NO_MEMORY_FATAL(ctdb, vnn);
+	vnn->ifaces = talloc_array(vnn, const char *, num + 2);
+	tmp = talloc_strdup(vnn, ifaces);
+	CTDB_NO_MEMORY_FATAL(ctdb, tmp);
+	for (iface = strtok(tmp, ","); iface; iface = strtok(NULL, ",")) {
+		vnn->ifaces = talloc_realloc(vnn, vnn->ifaces, const char *, num + 2);
+		CTDB_NO_MEMORY_FATAL(ctdb, vnn->ifaces);
+		vnn->ifaces[num] = talloc_strdup(vnn, iface);
+		CTDB_NO_MEMORY_FATAL(ctdb, vnn->ifaces[num]);
+		num++;
+	}
+	talloc_free(tmp);
+	vnn->ifaces[num] = NULL;
+	vnn->public_address      = *addr;
+	vnn->public_netmask_bits = mask;
+	vnn->pnn                 = -1;
+	if (ctdb_sys_have_ip(addr)) {
+		DEBUG(DEBUG_ERR,("We are already hosting public address '%s'. setting PNN to ourself:%d\n", ctdb_addr_to_str(addr), ctdb->pnn));
+		vnn->pnn = ctdb->pnn;
+	}
+
+	for (i=0; vnn->ifaces[i]; i++) {
+		ret = ctdb_add_local_iface(ctdb, vnn->ifaces[i]);
+		if (ret != 0) {
+			DEBUG(DEBUG_CRIT, (__location__ " failed to add iface[%s] "
+					   "for public_address[%s]\n",
+					   vnn->ifaces[i], ctdb_addr_to_str(addr)));
+			talloc_free(vnn);
+			return -1;
+		}
+		if (i == 0) {
+			vnn->iface = ctdb_find_iface(ctdb, vnn->ifaces[i]);
+		}
+	}
+
+	DLIST_ADD(ctdb->vnn, vnn);
+
+	return 0;
+}
+
+/*
+  setup the event script directory
+*/
+int ctdb_set_event_script_dir(struct ctdb_context *ctdb, const char *script_dir)
+{
+	ctdb->event_script_dir = talloc_strdup(ctdb, script_dir);
+	CTDB_NO_MEMORY(ctdb, ctdb->event_script_dir);
+	return 0;
+}
+
+static void ctdb_check_interfaces_event(struct event_context *ev, struct timed_event *te, 
+				  struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, 
+							struct ctdb_context);
+	struct ctdb_vnn *vnn;
+
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		int i;
+
+		for (i=0; vnn->ifaces[i] != NULL; i++) {
+			if (!ctdb_sys_check_iface_exists(vnn->ifaces[i])) {
+				DEBUG(DEBUG_CRIT,("Interface %s does not exist but is used by public ip %s\n",
+					vnn->ifaces[i],
+					ctdb_addr_to_str(&vnn->public_address)));
+			}
+		}
+	}
+
+	event_add_timed(ctdb->ev, ctdb->check_public_ifaces_ctx, 
+		timeval_current_ofs(30, 0), 
+		ctdb_check_interfaces_event, ctdb);
+}
+
+
+static int ctdb_start_monitoring_interfaces(struct ctdb_context *ctdb)
+{
+	if (ctdb->check_public_ifaces_ctx != NULL) {
+		talloc_free(ctdb->check_public_ifaces_ctx);
+		ctdb->check_public_ifaces_ctx = NULL;
+	}
+
+	ctdb->check_public_ifaces_ctx = talloc_new(ctdb);
+	if (ctdb->check_public_ifaces_ctx == NULL) {
+		ctdb_fatal(ctdb, "failed to allocate context for checking interfaces");
+	}
+
+	event_add_timed(ctdb->ev, ctdb->check_public_ifaces_ctx, 
+		timeval_current_ofs(30, 0), 
+		ctdb_check_interfaces_event, ctdb);
+
+	return 0;
+}
+
+
+/*
+  setup the public address lists from a file
+*/
+int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist)
+{
+	char **lines;
+	int nlines;
+	int i;
+
+	lines = file_lines_load(alist, &nlines, ctdb);
+	if (lines == NULL) {
+		ctdb_set_error(ctdb, "Failed to load public address list '%s'\n", alist);
+		return -1;
+	}
+	while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
+		nlines--;
+	}
+
+	for (i=0;i<nlines;i++) {
+		unsigned mask;
+		ctdb_sock_addr addr;
+		const char *addrstr;
+		const char *ifaces;
+		char *tok, *line;
+
+		line = lines[i];
+		while ((*line == ' ') || (*line == '\t')) {
+			line++;
+		}
+		if (*line == '#') {
+			continue;
+		}
+		if (strcmp(line, "") == 0) {
+			continue;
+		}
+		tok = strtok(line, " \t");
+		addrstr = tok;
+		tok = strtok(NULL, " \t");
+		if (tok == NULL) {
+			if (NULL == ctdb->default_public_interface) {
+				DEBUG(DEBUG_CRIT,("No default public interface and no interface specified at line %u of public address list\n",
+					 i+1));
+				talloc_free(lines);
+				return -1;
+			}
+			ifaces = ctdb->default_public_interface;
+		} else {
+			ifaces = tok;
+		}
+
+		if (!addrstr || !parse_ip_mask(addrstr, ifaces, &addr, &mask)) {
+			DEBUG(DEBUG_CRIT,("Badly formed line %u in public address list\n", i+1));
+			talloc_free(lines);
+			return -1;
+		}
+		if (ctdb_add_public_address(ctdb, &addr, mask, ifaces)) {
+			DEBUG(DEBUG_CRIT,("Failed to add line %u to the public address list\n", i+1));
+			talloc_free(lines);
+			return -1;
+		}
+	}
+
+
+	ctdb_start_monitoring_interfaces(ctdb);
+
+	talloc_free(lines);
+	return 0;
+}
+
+int ctdb_set_single_public_ip(struct ctdb_context *ctdb,
+			      const char *iface,
+			      const char *ip)
+{
+	struct ctdb_vnn *svnn;
+	struct ctdb_iface *cur = NULL;
+	bool ok;
+	int ret;
+
+	svnn = talloc_zero(ctdb, struct ctdb_vnn);
+	CTDB_NO_MEMORY(ctdb, svnn);
+
+	svnn->ifaces = talloc_array(svnn, const char *, 2);
+	CTDB_NO_MEMORY(ctdb, svnn->ifaces);
+	svnn->ifaces[0] = talloc_strdup(svnn->ifaces, iface);
+	CTDB_NO_MEMORY(ctdb, svnn->ifaces[0]);
+	svnn->ifaces[1] = NULL;
+
+	ok = parse_ip(ip, iface, 0, &svnn->public_address);
+	if (!ok) {
+		talloc_free(svnn);
+		return -1;
+	}
+
+	ret = ctdb_add_local_iface(ctdb, svnn->ifaces[0]);
+	if (ret != 0) {
+		DEBUG(DEBUG_CRIT, (__location__ " failed to add iface[%s] "
+				   "for single_ip[%s]\n",
+				   svnn->ifaces[0],
+				   ctdb_addr_to_str(&svnn->public_address)));
+		talloc_free(svnn);
+		return -1;
+	}
+
+	/* assume the single public ip interface is initially "good" */
+	cur = ctdb_find_iface(ctdb, iface);
+	if (cur == NULL) {
+		DEBUG(DEBUG_CRIT,("Can not find public interface %s used by --single-public-ip", iface));
+		return -1;
+	}
+	cur->link_up = true;
+
+	ret = ctdb_vnn_assign_iface(ctdb, svnn);
+	if (ret != 0) {
+		talloc_free(svnn);
+		return -1;
+	}
+
+	ctdb->single_ip_vnn = svnn;
+	return 0;
+}
+
+/* Given a physical node, return the number of
+   public addresses that is currently assigned to this node.
+*/
+static int node_ip_coverage(struct ctdb_context *ctdb, 
+	int32_t pnn,
+	struct ctdb_public_ip_list *ips)
+{
+	int num=0;
+
+	for (;ips;ips=ips->next) {
+		if (ips->pnn == pnn) {
+			num++;
+		}
+	}
+	return num;
+}
+
+
+/* Check if this is a public ip known to the node, i.e. can that
+   node takeover this ip ?
+*/
+static int can_node_serve_ip(struct ctdb_context *ctdb, int32_t pnn, 
+		struct ctdb_public_ip_list *ip)
+{
+	struct ctdb_all_public_ips *public_ips;
+	int i;
+
+	public_ips = ctdb->nodes[pnn]->available_public_ips;
+
+	if (public_ips == NULL) {
+		return -1;
+	}
+
+	for (i=0;i<public_ips->num;i++) {
+		if (ctdb_same_ip(&ip->addr, &public_ips->ips[i].addr)) {
+			/* yes, this node can serve this public ip */
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+/* search the node lists list for a node to takeover this ip.
+   pick the node that currently are serving the least number of ips
+   so that the ips get spread out evenly.
+*/
+static int find_takeover_node(struct ctdb_context *ctdb, 
+		struct ctdb_node_map *nodemap, uint32_t mask, 
+		struct ctdb_public_ip_list *ip,
+		struct ctdb_public_ip_list *all_ips)
+{
+	int pnn, min=0, num;
+	int i;
+
+	pnn    = -1;
+	for (i=0;i<nodemap->num;i++) {
+		if (nodemap->nodes[i].flags & mask) {
+			/* This node is not healty and can not be used to serve
+			   a public address 
+			*/
+			continue;
+		}
+
+		/* verify that this node can serve this ip */
+		if (can_node_serve_ip(ctdb, i, ip)) {
+			/* no it couldnt   so skip to the next node */
+			continue;
+		}
+
+		num = node_ip_coverage(ctdb, i, all_ips);
+		/* was this the first node we checked ? */
+		if (pnn == -1) {
+			pnn = i;
+			min  = num;
+		} else {
+			if (num < min) {
+				pnn = i;
+				min  = num;
+			}
+		}
+	}	
+	if (pnn == -1) {
+		DEBUG(DEBUG_WARNING,(__location__ " Could not find node to take over public address '%s'\n",
+			ctdb_addr_to_str(&ip->addr)));
+
+		return -1;
+	}
+
+	ip->pnn = pnn;
+	return 0;
+}
+
+#define IP_KEYLEN	4
+static uint32_t *ip_key(ctdb_sock_addr *ip)
+{
+	static uint32_t key[IP_KEYLEN];
+
+	bzero(key, sizeof(key));
+
+	switch (ip->sa.sa_family) {
+	case AF_INET:
+		key[3]	= htonl(ip->ip.sin_addr.s_addr);
+		break;
+	case AF_INET6:
+		key[0]	= htonl(ip->ip6.sin6_addr.s6_addr32[0]);
+		key[1]	= htonl(ip->ip6.sin6_addr.s6_addr32[1]);
+		key[2]	= htonl(ip->ip6.sin6_addr.s6_addr32[2]);
+		key[3]	= htonl(ip->ip6.sin6_addr.s6_addr32[3]);
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", ip->sa.sa_family));
+		return key;
+	}
+
+	return key;
+}
+
+static void *add_ip_callback(void *parm, void *data)
+{
+	struct ctdb_public_ip_list *this_ip = parm; 
+	struct ctdb_public_ip_list *prev_ip = data; 
+
+	if (prev_ip == NULL) {
+		return parm;
+	}
+	if (this_ip->pnn == -1) {
+		this_ip->pnn = prev_ip->pnn;
+	}
+
+	return parm;
+}
+
+void getips_count_callback(void *param, void *data)
+{
+	struct ctdb_public_ip_list **ip_list = (struct ctdb_public_ip_list **)param;
+	struct ctdb_public_ip_list *new_ip = (struct ctdb_public_ip_list *)data;
+
+	new_ip->next = *ip_list;
+	*ip_list     = new_ip;
+}
+
+static struct ctdb_public_ip_list *
+create_merged_ip_list(struct ctdb_context *ctdb)
+{
+	int i, j;
+	struct ctdb_public_ip_list *ip_list;
+	struct ctdb_all_public_ips *public_ips;
+
+	if (ctdb->ip_tree != NULL) {
+		talloc_free(ctdb->ip_tree);
+		ctdb->ip_tree = NULL;
+	}
+	ctdb->ip_tree = trbt_create(ctdb, 0);
+
+	for (i=0;i<ctdb->num_nodes;i++) {
+		public_ips = ctdb->nodes[i]->known_public_ips;
+
+		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+
+		/* there were no public ips for this node */
+		if (public_ips == NULL) {
+			continue;
+		}		
+
+		for (j=0;j<public_ips->num;j++) {
+			struct ctdb_public_ip_list *tmp_ip; 
+
+			tmp_ip = talloc_zero(ctdb->ip_tree, struct ctdb_public_ip_list);
+			CTDB_NO_MEMORY_NULL(ctdb, tmp_ip);
+			tmp_ip->pnn  = public_ips->ips[j].pnn;
+			tmp_ip->addr = public_ips->ips[j].addr;
+			tmp_ip->next = NULL;
+
+			trbt_insertarray32_callback(ctdb->ip_tree,
+				IP_KEYLEN, ip_key(&public_ips->ips[j].addr),
+				add_ip_callback,
+				tmp_ip);
+		}
+	}
+
+	ip_list = NULL;
+	trbt_traversearray32(ctdb->ip_tree, IP_KEYLEN, getips_count_callback, &ip_list);
+
+	return ip_list;
+}
+
+/* 
+ * This is the length of the longtest common prefix between the IPs.
+ * It is calculated by XOR-ing the 2 IPs together and counting the
+ * number of leading zeroes.  The implementation means that all
+ * addresses end up being 128 bits long.
+ * Not static, so we can easily link it into a unit test.
+ *
+ * FIXME? Should we consider IPv4 and IPv6 separately given that the
+ * 12 bytes of 0 prefix padding will hurt the algorithm if there are
+ * lots of nodes and IP addresses?
+ */
+uint32_t ip_distance(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
+{
+	uint32_t ip1_k[IP_KEYLEN];
+	uint32_t *t;
+	int i;
+	uint32_t x;
+
+	uint32_t distance = 0;
+
+	memcpy(ip1_k, ip_key(ip1), sizeof(ip1_k));
+	t = ip_key(ip2);
+	for (i=0; i<IP_KEYLEN; i++) {
+		x = ip1_k[i] ^ t[i];
+		if (x == 0) {
+			distance += 32;
+		} else {
+			/* Count number of leading zeroes. 
+			 * FIXME? This could be optimised...
+			 */
+			while ((x & (1 << 31)) == 0) {
+				x <<= 1;
+				distance += 1;
+			}
+		}
+	}
+
+	return distance;
+}
+
+/* Calculate the IP distance for the given IP relative to IPs on the
+   given node.  The ips argument is generally the all_ips variable
+   used in the main part of the algorithm.
+ * Not static, so we can easily link it into a unit test.
+ */
+uint32_t ip_distance_2_sum(ctdb_sock_addr *ip,
+			   struct ctdb_public_ip_list *ips,
+			   int pnn)
+{
+	struct ctdb_public_ip_list *t;
+	uint32_t d;
+
+	uint32_t sum = 0;
+
+	for (t=ips; t != NULL; t=t->next) {
+		if (t->pnn != pnn) {
+			continue;
+		}
+
+		/* Optimisation: We never calculate the distance
+		 * between an address and itself.  This allows us to
+		 * calculate the effect of removing an address from a
+		 * node by simply calculating the distance between
+		 * that address and all of the exitsing addresses.
+		 * Moreover, we assume that we're only ever dealing
+		 * with addresses from all_ips so we can identify an
+		 * address via a pointer rather than doing a more
+		 * expensive address comparison. */
+		if (&(t->addr) == ip) {
+			continue;
+		}
+
+		d = ip_distance(ip, &(t->addr));
+		sum += d * d;  /* Cheaper than pulling in math.h :-) */
+	}
+
+	return sum;
+}
+
+/* Return the LCP2 imbalance metric for addresses currently assigned
+   to the given node.
+ * Not static, so we can easily link it into a unit test.
+ */
+uint32_t lcp2_imbalance(struct ctdb_public_ip_list * all_ips, int pnn)
+{
+	struct ctdb_public_ip_list *t;
+
+	uint32_t imbalance = 0;
+
+	for (t=all_ips; t!=NULL; t=t->next) {
+		if (t->pnn != pnn) {
+			continue;
+		}
+		/* Pass the rest of the IPs rather than the whole
+		   all_ips input list.
+		*/
+		imbalance += ip_distance_2_sum(&(t->addr), t->next, pnn);
+	}
+
+	return imbalance;
+}
+
+/* Allocate any unassigned IPs just by looping through the IPs and
+ * finding the best node for each.
+ * Not static, so we can easily link it into a unit test.
+ */
+void basic_allocate_unassigned(struct ctdb_context *ctdb,
+			       struct ctdb_node_map *nodemap,
+			       uint32_t mask,
+			       struct ctdb_public_ip_list *all_ips)
+{
+	struct ctdb_public_ip_list *tmp_ip;
+
+	/* loop over all ip's and find a physical node to cover for 
+	   each unassigned ip.
+	*/
+	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+		if (tmp_ip->pnn == -1) {
+			if (find_takeover_node(ctdb, nodemap, mask, tmp_ip, all_ips)) {
+				DEBUG(DEBUG_WARNING,("Failed to find node to cover ip %s\n",
+					ctdb_addr_to_str(&tmp_ip->addr)));
+			}
+		}
+	}
+}
+
+/* Basic non-deterministic rebalancing algorithm.
+ * Not static, so we can easily link it into a unit test.
+ */
+bool basic_failback(struct ctdb_context *ctdb,
+		    struct ctdb_node_map *nodemap,
+		    uint32_t mask,
+		    struct ctdb_public_ip_list *all_ips,
+		    int num_ips,
+		    int *retries)
+{
+	int i;
+	int maxnode, maxnum=0, minnode, minnum=0, num;
+	struct ctdb_public_ip_list *tmp_ip;
+
+	/* for each ip address, loop over all nodes that can serve
+	   this ip and make sure that the difference between the node
+	   serving the most and the node serving the least ip's are
+	   not greater than 1.
+	*/
+	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+		if (tmp_ip->pnn == -1) {
+			continue;
+		}
+
+		/* Get the highest and lowest number of ips's served by any 
+		   valid node which can serve this ip.
+		*/
+		maxnode = -1;
+		minnode = -1;
+		for (i=0;i<nodemap->num;i++) {
+			if (nodemap->nodes[i].flags & mask) {
+				continue;
+			}
+
+			/* only check nodes that can actually serve this ip */
+			if (can_node_serve_ip(ctdb, i, tmp_ip)) {
+				/* no it couldnt   so skip to the next node */
+				continue;
+			}
+
+			num = node_ip_coverage(ctdb, i, all_ips);
+			if (maxnode == -1) {
+				maxnode = i;
+				maxnum  = num;
+			} else {
+				if (num > maxnum) {
+					maxnode = i;
+					maxnum  = num;
+				}
+			}
+			if (minnode == -1) {
+				minnode = i;
+				minnum  = num;
+			} else {
+				if (num < minnum) {
+					minnode = i;
+					minnum  = num;
+				}
+			}
+		}
+		if (maxnode == -1) {
+			DEBUG(DEBUG_WARNING,(__location__ " Could not find maxnode. May not be able to serve ip '%s'\n",
+				ctdb_addr_to_str(&tmp_ip->addr)));
+
+			continue;
+		}
+
+		/* If we want deterministic IPs then dont try to reallocate 
+		   them to spread out the load.
+		*/
+		if (1 == ctdb->tunable.deterministic_public_ips) {
+			continue;
+		}
+
+		/* if the spread between the smallest and largest coverage by
+		   a node is >=2 we steal one of the ips from the node with
+		   most coverage to even things out a bit.
+		   try to do this a limited number of times since we dont
+		   want to spend too much time balancing the ip coverage.
+		*/
+		if ( (maxnum > minnum+1)
+		     && (*retries < (num_ips + 5)) ){
+			struct ctdb_public_ip_list *tmp;
+
+			/* mark one of maxnode's vnn's as unassigned and try
+			   again
+			*/
+			for (tmp=all_ips;tmp;tmp=tmp->next) {
+				if (tmp->pnn == maxnode) {
+					tmp->pnn = -1;
+					(*retries)++;
+					return true;
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
+/* Do necessary LCP2 initialisation.  Bury it in a function here so
+ * that we can unit test it.
+ * Not static, so we can easily link it into a unit test.
+ */
+void lcp2_init(struct ctdb_context * tmp_ctx,
+	       struct ctdb_node_map * nodemap,
+	       uint32_t mask,
+	       struct ctdb_public_ip_list *all_ips,
+	       uint32_t **lcp2_imbalances,
+	       bool **newly_healthy)
+{
+	int i;
+	struct ctdb_public_ip_list *tmp_ip;
+
+	*newly_healthy = talloc_array(tmp_ctx, bool, nodemap->num);
+	CTDB_NO_MEMORY_FATAL(tmp_ctx, *newly_healthy);
+	*lcp2_imbalances = talloc_array(tmp_ctx, uint32_t, nodemap->num);
+	CTDB_NO_MEMORY_FATAL(tmp_ctx, *lcp2_imbalances);
+
+	for (i=0;i<nodemap->num;i++) {
+		(*lcp2_imbalances)[i] = lcp2_imbalance(all_ips, i);
+		/* First step: is the node "healthy"? */
+		(*newly_healthy)[i] = ! (bool)(nodemap->nodes[i].flags & mask);
+	}
+
+	/* 2nd step: if a ndoe has IPs assigned then it must have been
+	 * healthy before, so we remove it from consideration... */
+	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+		if (tmp_ip->pnn != -1) {
+			(*newly_healthy)[tmp_ip->pnn] = false;
+		}
+	}
+}
+
+/* Allocate any unassigned addresses using the LCP2 algorithm to find
+ * the IP/node combination that will cost the least.
+ * Not static, so we can easily link it into a unit test.
+ */
+void lcp2_allocate_unassigned(struct ctdb_context *ctdb,
+			      struct ctdb_node_map *nodemap,
+			      uint32_t mask,
+			      struct ctdb_public_ip_list *all_ips,
+			      uint32_t *lcp2_imbalances)
+{
+	struct ctdb_public_ip_list *tmp_ip;
+	int dstnode;
+
+	int minnode;
+	uint32_t mindsum, dstdsum, dstimbl, minimbl;
+	struct ctdb_public_ip_list *minip;
+
+	bool should_loop = true;
+	bool have_unassigned = true;
+
+	while (have_unassigned && should_loop) {
+		should_loop = false;
+
+		DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
+		DEBUG(DEBUG_DEBUG,(" CONSIDERING MOVES (UNASSIGNED)\n"));
+
+		minnode = -1;
+		mindsum = 0;
+		minip = NULL;
+
+		/* loop over each unassigned ip. */
+		for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+			if (tmp_ip->pnn != -1) {
+				continue;
+			}
+
+			for (dstnode=0; dstnode < nodemap->num; dstnode++) {
+				/* only check nodes that can actually serve this ip */
+				if (can_node_serve_ip(ctdb, dstnode, tmp_ip)) {
+					/* no it couldnt   so skip to the next node */
+					continue;
+				}
+				if (nodemap->nodes[dstnode].flags & mask) {
+					continue;
+				}
+
+				dstdsum = ip_distance_2_sum(&(tmp_ip->addr), all_ips, dstnode);
+				dstimbl = lcp2_imbalances[dstnode] + dstdsum;
+				DEBUG(DEBUG_DEBUG,(" %s -> %d [+%d]\n",
+						   ctdb_addr_to_str(&(tmp_ip->addr)),
+						   dstnode,
+						   dstimbl - lcp2_imbalances[dstnode]));
+
+
+				if ((minnode == -1) || (dstdsum < mindsum)) {
+					minnode = dstnode;
+					minimbl = dstimbl;
+					mindsum = dstdsum;
+					minip = tmp_ip;
+					should_loop = true;
+				}
+			}
+		}
+
+		DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
+
+		/* If we found one then assign it to the given node. */
+		if (minnode != -1) {
+			minip->pnn = minnode;
+			lcp2_imbalances[minnode] = minimbl;
+			DEBUG(DEBUG_INFO,(" %s -> %d [+%d]\n",
+					  ctdb_addr_to_str(&(minip->addr)),
+					  minnode,
+					  mindsum));
+		}
+
+		/* There might be a better way but at least this is clear. */
+		have_unassigned = false;
+		for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+			if (tmp_ip->pnn == -1) {
+				have_unassigned = true;
+			}
+		}
+	}
+
+	/* We know if we have an unassigned addresses so we might as
+	 * well optimise.
+	 */
+	if (have_unassigned) {
+		for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+			if (tmp_ip->pnn == -1) {
+				DEBUG(DEBUG_WARNING,("Failed to find node to cover ip %s\n",
+						     ctdb_addr_to_str(&tmp_ip->addr)));
+			}
+		}
+	}
+}
+
+/* LCP2 algorithm for rebalancing the cluster.  This finds the source
+ * node with the highest LCP2 imbalance, and then determines the best
+ * IP/destination node combination to move from the source node.
+ *
+ * Not static, so we can easily link it into a unit test.
+ */
+bool lcp2_failback(struct ctdb_context *ctdb,
+		   struct ctdb_node_map *nodemap,
+		   uint32_t mask,
+		   struct ctdb_public_ip_list *all_ips,
+		   uint32_t *lcp2_imbalances,
+		   bool *newly_healthy)
+{
+	int srcnode, dstnode, mindstnode, i, num_newly_healthy;
+	uint32_t srcimbl, srcdsum, maximbl, dstimbl, dstdsum;
+	uint32_t minsrcimbl, mindstimbl, b;
+	struct ctdb_public_ip_list *minip;
+	struct ctdb_public_ip_list *tmp_ip;
+
+	/* It is only worth continuing if we have suitable target
+	 * nodes to transfer IPs to.  This check is much cheaper than
+	 * continuing on...
+	 */
+	num_newly_healthy = 0;
+	for (i = 0; i < nodemap->num; i++) {
+		if (newly_healthy[i]) {
+			num_newly_healthy++;
+		}
+	}
+	if (num_newly_healthy == 0) {
+		return false;
+	}
+
+        /* Get the node with the highest imbalance metric. */
+        srcnode = -1;
+        maximbl = 0;
+	for (i=0; i < nodemap->num; i++) {
+		b = lcp2_imbalances[i];
+		if ((srcnode == -1) || (b > maximbl)) {
+			srcnode = i;
+			maximbl = b;
+		}
+	}
+
+        /* This means that all nodes had 0 or 1 addresses, so can't be
+	 * imbalanced.
+	 */
+        if (maximbl == 0) {
+		return false;
+	}
+
+	/* Find an IP and destination node that best reduces imbalance. */
+	minip = NULL;
+	minsrcimbl = 0;
+	mindstnode = -1;
+	mindstimbl = 0;
+
+	DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
+	DEBUG(DEBUG_DEBUG,(" CONSIDERING MOVES FROM %d [%d]\n", srcnode, maximbl));
+
+	for (tmp_ip=all_ips; tmp_ip; tmp_ip=tmp_ip->next) {
+		/* Only consider addresses on srcnode. */
+		if (tmp_ip->pnn != srcnode) {
+			continue;
+		}
+
+		/* What is this IP address costing the source node? */
+		srcdsum = ip_distance_2_sum(&(tmp_ip->addr), all_ips, srcnode);
+		srcimbl = maximbl - srcdsum;
+
+		/* Consider this IP address would cost each potential
+		 * destination node.  Destination nodes are limited to
+		 * those that are newly healthy, since we don't want
+		 * to do gratuitous failover of IPs just to make minor
+		 * balance improvements.
+		 */
+		for (dstnode=0; dstnode < nodemap->num; dstnode++) {
+			if (! newly_healthy[dstnode]) {
+				continue;
+			}
+			/* only check nodes that can actually serve this ip */
+			if (can_node_serve_ip(ctdb, dstnode, tmp_ip)) {
+				/* no it couldnt   so skip to the next node */
+				continue;
+			}
+
+			dstdsum = ip_distance_2_sum(&(tmp_ip->addr), all_ips, dstnode);
+			dstimbl = lcp2_imbalances[dstnode] + dstdsum;
+			DEBUG(DEBUG_DEBUG,(" %d [%d] -> %s -> %d [+%d]\n",
+					   srcnode, srcimbl - lcp2_imbalances[srcnode],
+					   ctdb_addr_to_str(&(tmp_ip->addr)),
+					   dstnode, dstimbl - lcp2_imbalances[dstnode]));
+
+			if ((dstimbl < maximbl) && (dstdsum < srcdsum) && \
+			    ((mindstnode == -1) ||				\
+			     ((srcimbl + dstimbl) < (minsrcimbl + mindstimbl)))) {
+
+				minip = tmp_ip;
+				minsrcimbl = srcimbl;
+				mindstnode = dstnode;
+				mindstimbl = dstimbl;
+			}
+		}
+	}
+	DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n"));
+
+        if (mindstnode != -1) {
+		/* We found a move that makes things better... */
+		DEBUG(DEBUG_INFO,("%d [%d] -> %s -> %d [+%d]\n",
+				  srcnode, minsrcimbl - lcp2_imbalances[srcnode],
+				  ctdb_addr_to_str(&(minip->addr)),
+				  mindstnode, mindstimbl - lcp2_imbalances[mindstnode]));
+
+
+		lcp2_imbalances[srcnode] = srcimbl;
+		lcp2_imbalances[mindstnode] = mindstimbl;
+		minip->pnn = mindstnode;
+
+		return true;
+	}
+
+        return false;
+	
+}
+
+/* The calculation part of the IP allocation algorithm.
+ * Not static, so we can easily link it into a unit test.
+ */
+void ctdb_takeover_run_core(struct ctdb_context *ctdb,
+			    struct ctdb_node_map *nodemap,
+			    struct ctdb_public_ip_list **all_ips_p)
+{
+	int i, num_healthy, retries, num_ips;
+	uint32_t mask;
+	struct ctdb_public_ip_list *all_ips, *tmp_ip;
+	uint32_t *lcp2_imbalances;
+	bool *newly_healthy;
+
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+	/* Count how many completely healthy nodes we have */
+	num_healthy = 0;
+	for (i=0;i<nodemap->num;i++) {
+		if (!(nodemap->nodes[i].flags & (NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED))) {
+			num_healthy++;
+		}
+	}
+
+	if (num_healthy > 0) {
+		/* We have healthy nodes, so only consider them for 
+		   serving public addresses
+		*/
+		mask = NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED;
+	} else {
+		/* We didnt have any completely healthy nodes so
+		   use "disabled" nodes as a fallback
+		*/
+		mask = NODE_FLAGS_INACTIVE;
+	}
+
+	/* since nodes only know about those public addresses that
+	   can be served by that particular node, no single node has
+	   a full list of all public addresses that exist in the cluster.
+	   Walk over all node structures and create a merged list of
+	   all public addresses that exist in the cluster.
+
+	   keep the tree of ips around as ctdb->ip_tree
+	*/
+	all_ips = create_merged_ip_list(ctdb);
+	*all_ips_p = all_ips; /* minimal code changes */
+
+	/* Count how many ips we have */
+	num_ips = 0;
+	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+		num_ips++;
+	}
+
+	/* If we want deterministic ip allocations, i.e. that the ip addresses
+	   will always be allocated the same way for a specific set of
+	   available/unavailable nodes.
+	*/
+	if (1 == ctdb->tunable.deterministic_public_ips) {		
+		DEBUG(DEBUG_NOTICE,("Deterministic IPs enabled. Resetting all ip allocations\n"));
+		for (i=0,tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next,i++) {
+			tmp_ip->pnn = i%nodemap->num;
+		}
+	}
+
+
+	/* mark all public addresses with a masked node as being served by
+	   node -1
+	*/
+	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+		if (tmp_ip->pnn == -1) {
+			continue;
+		}
+		if (nodemap->nodes[tmp_ip->pnn].flags & mask) {
+			tmp_ip->pnn = -1;
+		}
+	}
+
+	/* verify that the assigned nodes can serve that public ip
+	   and set it to -1 if not
+	*/
+	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+		if (tmp_ip->pnn == -1) {
+			continue;
+		}
+		if (can_node_serve_ip(ctdb, tmp_ip->pnn, tmp_ip) != 0) {
+			/* this node can not serve this ip. */
+			tmp_ip->pnn = -1;
+		}
+	}
+
+        if (1 == ctdb->tunable.lcp2_public_ip_assignment) {
+		lcp2_init(tmp_ctx, nodemap, mask, all_ips, &lcp2_imbalances, &newly_healthy);
+	}
+
+	/* now we must redistribute all public addresses with takeover node
+	   -1 among the nodes available
+	*/
+	retries = 0;
+try_again:
+	if (1 == ctdb->tunable.lcp2_public_ip_assignment) {
+		lcp2_allocate_unassigned(ctdb, nodemap, mask, all_ips, lcp2_imbalances);
+	} else {
+		basic_allocate_unassigned(ctdb, nodemap, mask, all_ips);
+	}
+
+	/* If we dont want ips to fail back after a node becomes healthy
+	   again, we wont even try to reallocat the ip addresses so that
+	   they are evenly spread out.
+	   This can NOT be used at the same time as DeterministicIPs !
+	*/
+	if (1 == ctdb->tunable.no_ip_failback) {
+		if (1 == ctdb->tunable.deterministic_public_ips) {
+			DEBUG(DEBUG_ERR, ("ERROR: You can not use 'DeterministicIPs' and 'NoIPFailback' at the same time\n"));
+		}
+		goto finished;
+	}
+
+
+	/* now, try to make sure the ip adresses are evenly distributed
+	   across the node.
+	*/
+	if (1 == ctdb->tunable.lcp2_public_ip_assignment) {
+		if (lcp2_failback(ctdb, nodemap, mask, all_ips, lcp2_imbalances, newly_healthy)) {
+			goto try_again;
+		}
+	} else {
+		if (basic_failback(ctdb, nodemap, mask, all_ips, num_ips, &retries)) {
+			goto try_again;
+		}
+	}
+
+	/* finished distributing the public addresses, now just send the 
+	   info out to the nodes
+	*/
+finished:
+
+	/* at this point ->pnn is the node which will own each IP
+	   or -1 if there is no node that can cover this ip
+	*/
+
+	return;
+}
+
+/*
+  make any IP alias changes for public addresses that are necessary 
+ */
+int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap)
+{
+	int i;
+	struct ctdb_public_ip ip;
+	struct ctdb_public_ipv4 ipv4;
+	uint32_t *nodes;
+	struct ctdb_public_ip_list *all_ips, *tmp_ip;
+	TDB_DATA data;
+	struct timeval timeout;
+	struct client_async_data *async_data;
+	struct ctdb_client_control_state *state;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+	/*
+	 * ip failover is completely disabled, just send out the 
+	 * ipreallocated event.
+	 */
+	if (ctdb->tunable.disable_ip_failover != 0) {
+		goto ipreallocated;
+	}
+
+	ZERO_STRUCT(ip);
+
+	/* Do the IP reassignment calculations */
+	ctdb_takeover_run_core(ctdb, nodemap, &all_ips);
+
+	/* now tell all nodes to delete any alias that they should not
+	   have.  This will be a NOOP on nodes that don't currently
+	   hold the given alias */
+	async_data = talloc_zero(tmp_ctx, struct client_async_data);
+	CTDB_NO_MEMORY_FATAL(ctdb, async_data);
+
+	for (i=0;i<nodemap->num;i++) {
+		/* don't talk to unconnected nodes, but do talk to banned nodes */
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+
+		for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+			if (tmp_ip->pnn == nodemap->nodes[i].pnn) {
+				/* This node should be serving this
+				   vnn so dont tell it to release the ip
+				*/
+				continue;
+			}
+			if (tmp_ip->addr.sa.sa_family == AF_INET) {
+				ipv4.pnn = tmp_ip->pnn;
+				ipv4.sin = tmp_ip->addr.ip;
+
+				timeout = TAKEOVER_TIMEOUT();
+				data.dsize = sizeof(ipv4);
+				data.dptr  = (uint8_t *)&ipv4;
+				state = ctdb_control_send(ctdb, nodemap->nodes[i].pnn,
+						0, CTDB_CONTROL_RELEASE_IPv4, 0,
+						data, async_data,
+						&timeout, NULL);
+			} else {
+				ip.pnn  = tmp_ip->pnn;
+				ip.addr = tmp_ip->addr;
+
+				timeout = TAKEOVER_TIMEOUT();
+				data.dsize = sizeof(ip);
+				data.dptr  = (uint8_t *)&ip;
+				state = ctdb_control_send(ctdb, nodemap->nodes[i].pnn,
+						0, CTDB_CONTROL_RELEASE_IP, 0,
+						data, async_data,
+						&timeout, NULL);
+			}
+
+			if (state == NULL) {
+				DEBUG(DEBUG_ERR,(__location__ " Failed to call async control CTDB_CONTROL_RELEASE_IP to node %u\n", nodemap->nodes[i].pnn));
+				talloc_free(tmp_ctx);
+				return -1;
+			}
+		
+			ctdb_client_async_add(async_data, state);
+		}
+	}
+	if (ctdb_client_async_wait(ctdb, async_data) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Async control CTDB_CONTROL_RELEASE_IP failed\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	talloc_free(async_data);
+
+
+	/* tell all nodes to get their own IPs */
+	async_data = talloc_zero(tmp_ctx, struct client_async_data);
+	CTDB_NO_MEMORY_FATAL(ctdb, async_data);
+	for (tmp_ip=all_ips;tmp_ip;tmp_ip=tmp_ip->next) {
+		if (tmp_ip->pnn == -1) {
+			/* this IP won't be taken over */
+			continue;
+		}
+
+		if (tmp_ip->addr.sa.sa_family == AF_INET) {
+			ipv4.pnn = tmp_ip->pnn;
+			ipv4.sin = tmp_ip->addr.ip;
+
+			timeout = TAKEOVER_TIMEOUT();
+			data.dsize = sizeof(ipv4);
+			data.dptr  = (uint8_t *)&ipv4;
+			state = ctdb_control_send(ctdb, tmp_ip->pnn,
+					0, CTDB_CONTROL_TAKEOVER_IPv4, 0,
+					data, async_data,
+					&timeout, NULL);
+		} else {
+			ip.pnn  = tmp_ip->pnn;
+			ip.addr = tmp_ip->addr;
+
+			timeout = TAKEOVER_TIMEOUT();
+			data.dsize = sizeof(ip);
+			data.dptr  = (uint8_t *)&ip;
+			state = ctdb_control_send(ctdb, tmp_ip->pnn,
+					0, CTDB_CONTROL_TAKEOVER_IP, 0,
+					data, async_data,
+					&timeout, NULL);
+		}
+		if (state == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to call async control CTDB_CONTROL_TAKEOVER_IP to node %u\n", tmp_ip->pnn));
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+		
+		ctdb_client_async_add(async_data, state);
+	}
+	if (ctdb_client_async_wait(ctdb, async_data) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Async control CTDB_CONTROL_TAKEOVER_IP failed\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+ipreallocated:
+	/* tell all nodes to update natwg */
+	/* send the flags update natgw on all connected nodes */
+	data.dptr  = discard_const("ipreallocated");
+	data.dsize = strlen((char *)data.dptr) + 1; 
+	nodes = list_of_connected_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_RUN_EVENTSCRIPTS,
+				      nodes, 0, TAKEOVER_TIMEOUT(),
+				      false, data,
+				      NULL, NULL,
+				      NULL) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " ctdb_control to updatenatgw failed\n"));
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+
+/*
+  destroy a ctdb_client_ip structure
+ */
+static int ctdb_client_ip_destructor(struct ctdb_client_ip *ip)
+{
+	DEBUG(DEBUG_DEBUG,("destroying client tcp for %s:%u (client_id %u)\n",
+		ctdb_addr_to_str(&ip->addr),
+		ntohs(ip->addr.ip.sin_port),
+		ip->client_id));
+
+	DLIST_REMOVE(ip->ctdb->client_ip_list, ip);
+	return 0;
+}
+
+/*
+  called by a client to inform us of a TCP connection that it is managing
+  that should tickled with an ACK when IP takeover is done
+  we handle both the old ipv4 style of packets as well as the new ipv4/6
+  pdus.
+ */
+int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
+				TDB_DATA indata)
+{
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+	struct ctdb_control_tcp *old_addr = NULL;
+	struct ctdb_control_tcp_addr new_addr;
+	struct ctdb_control_tcp_addr *tcp_sock = NULL;
+	struct ctdb_tcp_list *tcp;
+	struct ctdb_tcp_connection t;
+	int ret;
+	TDB_DATA data;
+	struct ctdb_client_ip *ip;
+	struct ctdb_vnn *vnn;
+	ctdb_sock_addr addr;
+
+	switch (indata.dsize) {
+	case sizeof(struct ctdb_control_tcp):
+		old_addr = (struct ctdb_control_tcp *)indata.dptr;
+		ZERO_STRUCT(new_addr);
+		tcp_sock = &new_addr;
+		tcp_sock->src.ip  = old_addr->src;
+		tcp_sock->dest.ip = old_addr->dest;
+		break;
+	case sizeof(struct ctdb_control_tcp_addr):
+		tcp_sock = (struct ctdb_control_tcp_addr *)indata.dptr;
+		break;
+	default:
+		DEBUG(DEBUG_ERR,(__location__ " Invalid data structure passed "
+				 "to ctdb_control_tcp_client. size was %d but "
+				 "only allowed sizes are %lu and %lu\n",
+				 (int)indata.dsize,
+				 (long unsigned)sizeof(struct ctdb_control_tcp),
+				 (long unsigned)sizeof(struct ctdb_control_tcp_addr)));
+		return -1;
+	}
+
+	addr = tcp_sock->src;
+	ctdb_canonicalize_ip(&addr,  &tcp_sock->src);
+	addr = tcp_sock->dest;
+	ctdb_canonicalize_ip(&addr, &tcp_sock->dest);
+
+	ZERO_STRUCT(addr);
+	memcpy(&addr, &tcp_sock->dest, sizeof(addr));
+	vnn = find_public_ip_vnn(ctdb, &addr);
+	if (vnn == NULL) {
+		switch (addr.sa.sa_family) {
+		case AF_INET:
+			if (ntohl(addr.ip.sin_addr.s_addr) != INADDR_LOOPBACK) {
+				DEBUG(DEBUG_ERR,("Could not add client IP %s. This is not a public address.\n", 
+					ctdb_addr_to_str(&addr)));
+			}
+			break;
+		case AF_INET6:
+			DEBUG(DEBUG_ERR,("Could not add client IP %s. This is not a public ipv6 address.\n", 
+				ctdb_addr_to_str(&addr)));
+			break;
+		default:
+			DEBUG(DEBUG_ERR,(__location__ " Unknown family type %d\n", addr.sa.sa_family));
+		}
+
+		return 0;
+	}
+
+	if (vnn->pnn != ctdb->pnn) {
+		DEBUG(DEBUG_ERR,("Attempt to register tcp client for IP %s we don't hold - failing (client_id %u pid %u)\n",
+			ctdb_addr_to_str(&addr),
+			client_id, client->pid));
+		/* failing this call will tell smbd to die */
+		return -1;
+	}
+
+	ip = talloc(client, struct ctdb_client_ip);
+	CTDB_NO_MEMORY(ctdb, ip);
+
+	ip->ctdb      = ctdb;
+	ip->addr      = addr;
+	ip->client_id = client_id;
+	talloc_set_destructor(ip, ctdb_client_ip_destructor);
+	DLIST_ADD(ctdb->client_ip_list, ip);
+
+	tcp = talloc(client, struct ctdb_tcp_list);
+	CTDB_NO_MEMORY(ctdb, tcp);
+
+	tcp->connection.src_addr = tcp_sock->src;
+	tcp->connection.dst_addr = tcp_sock->dest;
+
+	DLIST_ADD(client->tcp_list, tcp);
+
+	t.src_addr = tcp_sock->src;
+	t.dst_addr = tcp_sock->dest;
+
+	data.dptr = (uint8_t *)&t;
+	data.dsize = sizeof(t);
+
+	switch (addr.sa.sa_family) {
+	case AF_INET:
+		DEBUG(DEBUG_INFO,("registered tcp client for %u->%s:%u (client_id %u pid %u)\n",
+			(unsigned)ntohs(tcp_sock->dest.ip.sin_port), 
+			ctdb_addr_to_str(&tcp_sock->src),
+			(unsigned)ntohs(tcp_sock->src.ip.sin_port), client_id, client->pid));
+		break;
+	case AF_INET6:
+		DEBUG(DEBUG_INFO,("registered tcp client for %u->%s:%u (client_id %u pid %u)\n",
+			(unsigned)ntohs(tcp_sock->dest.ip6.sin6_port), 
+			ctdb_addr_to_str(&tcp_sock->src),
+			(unsigned)ntohs(tcp_sock->src.ip6.sin6_port), client_id, client->pid));
+		break;
+	default:
+		DEBUG(DEBUG_ERR,(__location__ " Unknown family %d\n", addr.sa.sa_family));
+	}
+
+
+	/* tell all nodes about this tcp connection */
+	ret = ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_CONNECTED, 0, 
+				       CTDB_CONTROL_TCP_ADD,
+				       0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to send CTDB_CONTROL_TCP_ADD\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  find a tcp address on a list
+ */
+static struct ctdb_tcp_connection *ctdb_tcp_find(struct ctdb_tcp_array *array, 
+					   struct ctdb_tcp_connection *tcp)
+{
+	int i;
+
+	if (array == NULL) {
+		return NULL;
+	}
+
+	for (i=0;i<array->num;i++) {
+		if (ctdb_same_sockaddr(&array->connections[i].src_addr, &tcp->src_addr) &&
+		    ctdb_same_sockaddr(&array->connections[i].dst_addr, &tcp->dst_addr)) {
+			return &array->connections[i];
+		}
+	}
+	return NULL;
+}
+
+
+
+/*
+  called by a daemon to inform us of a TCP connection that one of its
+  clients managing that should tickled with an ACK when IP takeover is
+  done
+ */
+int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tcp_update_needed)
+{
+	struct ctdb_tcp_connection *p = (struct ctdb_tcp_connection *)indata.dptr;
+	struct ctdb_tcp_array *tcparray;
+	struct ctdb_tcp_connection tcp;
+	struct ctdb_vnn *vnn;
+
+	vnn = find_public_ip_vnn(ctdb, &p->dst_addr);
+	if (vnn == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " got TCP_ADD control for an address which is not a public address '%s'\n",
+			ctdb_addr_to_str(&p->dst_addr)));
+
+		return -1;
+	}
+
+
+	tcparray = vnn->tcp_array;
+
+	/* If this is the first tickle */
+	if (tcparray == NULL) {
+		tcparray = talloc_size(ctdb->nodes, 
+			offsetof(struct ctdb_tcp_array, connections) +
+			sizeof(struct ctdb_tcp_connection) * 1);
+		CTDB_NO_MEMORY(ctdb, tcparray);
+		vnn->tcp_array = tcparray;
+
+		tcparray->num = 0;
+		tcparray->connections = talloc_size(tcparray, sizeof(struct ctdb_tcp_connection));
+		CTDB_NO_MEMORY(ctdb, tcparray->connections);
+
+		tcparray->connections[tcparray->num].src_addr = p->src_addr;
+		tcparray->connections[tcparray->num].dst_addr = p->dst_addr;
+		tcparray->num++;
+
+		if (tcp_update_needed) {
+			vnn->tcp_update_needed = true;
+		}
+		return 0;
+	}
+
+
+	/* Do we already have this tickle ?*/
+	tcp.src_addr = p->src_addr;
+	tcp.dst_addr = p->dst_addr;
+	if (ctdb_tcp_find(vnn->tcp_array, &tcp) != NULL) {
+		DEBUG(DEBUG_DEBUG,("Already had tickle info for %s:%u for vnn:%u\n",
+			ctdb_addr_to_str(&tcp.dst_addr),
+			ntohs(tcp.dst_addr.ip.sin_port),
+			vnn->pnn));
+		return 0;
+	}
+
+	/* A new tickle, we must add it to the array */
+	tcparray->connections = talloc_realloc(tcparray, tcparray->connections,
+					struct ctdb_tcp_connection,
+					tcparray->num+1);
+	CTDB_NO_MEMORY(ctdb, tcparray->connections);
+
+	vnn->tcp_array = tcparray;
+	tcparray->connections[tcparray->num].src_addr = p->src_addr;
+	tcparray->connections[tcparray->num].dst_addr = p->dst_addr;
+	tcparray->num++;
+				
+	DEBUG(DEBUG_INFO,("Added tickle info for %s:%u from vnn %u\n",
+		ctdb_addr_to_str(&tcp.dst_addr),
+		ntohs(tcp.dst_addr.ip.sin_port),
+		vnn->pnn));
+
+	if (tcp_update_needed) {
+		vnn->tcp_update_needed = true;
+	}
+
+	return 0;
+}
+
+
+/*
+  called by a daemon to inform us of a TCP connection that one of its
+  clients managing that should tickled with an ACK when IP takeover is
+  done
+ */
+static void ctdb_remove_tcp_connection(struct ctdb_context *ctdb, struct ctdb_tcp_connection *conn)
+{
+	struct ctdb_tcp_connection *tcpp;
+	struct ctdb_vnn *vnn = find_public_ip_vnn(ctdb, &conn->dst_addr);
+
+	if (vnn == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " unable to find public address %s\n",
+			ctdb_addr_to_str(&conn->dst_addr)));
+		return;
+	}
+
+	/* if the array is empty we cant remove it
+	   and we dont need to do anything
+	 */
+	if (vnn->tcp_array == NULL) {
+		DEBUG(DEBUG_INFO,("Trying to remove tickle that doesnt exist (array is empty) %s:%u\n",
+			ctdb_addr_to_str(&conn->dst_addr),
+			ntohs(conn->dst_addr.ip.sin_port)));
+		return;
+	}
+
+
+	/* See if we know this connection
+	   if we dont know this connection  then we dont need to do anything
+	 */
+	tcpp = ctdb_tcp_find(vnn->tcp_array, conn);
+	if (tcpp == NULL) {
+		DEBUG(DEBUG_INFO,("Trying to remove tickle that doesnt exist %s:%u\n",
+			ctdb_addr_to_str(&conn->dst_addr),
+			ntohs(conn->dst_addr.ip.sin_port)));
+		return;
+	}
+
+
+	/* We need to remove this entry from the array.
+           Instead of allocating a new array and copying data to it
+	   we cheat and just copy the last entry in the existing array
+	   to the entry that is to be removed and just shring the 
+	   ->num field
+	 */
+	*tcpp = vnn->tcp_array->connections[vnn->tcp_array->num - 1];
+	vnn->tcp_array->num--;
+
+	/* If we deleted the last entry we also need to remove the entire array
+	 */
+	if (vnn->tcp_array->num == 0) {
+		talloc_free(vnn->tcp_array);
+		vnn->tcp_array = NULL;
+	}		
+
+	vnn->tcp_update_needed = true;
+
+	DEBUG(DEBUG_INFO,("Removed tickle info for %s:%u\n",
+		ctdb_addr_to_str(&conn->src_addr),
+		ntohs(conn->src_addr.ip.sin_port)));
+}
+
+
+/*
+  called by a daemon to inform us of a TCP connection that one of its
+  clients used are no longer needed in the tickle database
+ */
+int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_tcp_connection *conn = (struct ctdb_tcp_connection *)indata.dptr;
+
+	ctdb_remove_tcp_connection(ctdb, conn);
+
+	return 0;
+}
+
+
+/*
+  called when a daemon restarts - send all tickes for all public addresses
+  we are serving immediately to the new node.
+ */
+int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn)
+{
+/*XXX here we should send all tickes we are serving to the new node */
+	return 0;
+}
+
+
+/*
+  called when a client structure goes away - hook to remove
+  elements from the tcp_list in all daemons
+ */
+void ctdb_takeover_client_destructor_hook(struct ctdb_client *client)
+{
+	while (client->tcp_list) {
+		struct ctdb_tcp_list *tcp = client->tcp_list;
+		DLIST_REMOVE(client->tcp_list, tcp);
+		ctdb_remove_tcp_connection(client->ctdb, &tcp->connection);
+	}
+}
+
+
+/*
+  release all IPs on shutdown
+ */
+void ctdb_release_all_ips(struct ctdb_context *ctdb)
+{
+	struct ctdb_vnn *vnn;
+
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		if (!ctdb_sys_have_ip(&vnn->public_address)) {
+			ctdb_vnn_unassign_iface(ctdb, vnn);
+			continue;
+		}
+		if (!vnn->iface) {
+			continue;
+		}
+		ctdb_event_script_args(ctdb, CTDB_EVENT_RELEASE_IP, "%s %s %u",
+				  ctdb_vnn_iface_string(vnn),
+				  ctdb_addr_to_str(&vnn->public_address),
+				  vnn->public_netmask_bits);
+		release_kill_clients(ctdb, &vnn->public_address);
+		ctdb_vnn_unassign_iface(ctdb, vnn);
+	}
+}
+
+
+/*
+  get list of public IPs
+ */
+int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb, 
+				    struct ctdb_req_control *c, TDB_DATA *outdata)
+{
+	int i, num, len;
+	struct ctdb_all_public_ips *ips;
+	struct ctdb_vnn *vnn;
+	bool only_available = false;
+
+	if (c->flags & CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE) {
+		only_available = true;
+	}
+
+	/* count how many public ip structures we have */
+	num = 0;
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		num++;
+	}
+
+	len = offsetof(struct ctdb_all_public_ips, ips) + 
+		num*sizeof(struct ctdb_public_ip);
+	ips = talloc_zero_size(outdata, len);
+	CTDB_NO_MEMORY(ctdb, ips);
+
+	i = 0;
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		if (only_available && !ctdb_vnn_available(ctdb, vnn)) {
+			continue;
+		}
+		ips->ips[i].pnn  = vnn->pnn;
+		ips->ips[i].addr = vnn->public_address;
+		i++;
+	}
+	ips->num = i;
+	len = offsetof(struct ctdb_all_public_ips, ips) +
+		i*sizeof(struct ctdb_public_ip);
+
+	outdata->dsize = len;
+	outdata->dptr  = (uint8_t *)ips;
+
+	return 0;
+}
+
+
+/*
+  get list of public IPs, old ipv4 style.  only returns ipv4 addresses
+ */
+int32_t ctdb_control_get_public_ipsv4(struct ctdb_context *ctdb, 
+				    struct ctdb_req_control *c, TDB_DATA *outdata)
+{
+	int i, num, len;
+	struct ctdb_all_public_ipsv4 *ips;
+	struct ctdb_vnn *vnn;
+
+	/* count how many public ip structures we have */
+	num = 0;
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		if (vnn->public_address.sa.sa_family != AF_INET) {
+			continue;
+		}
+		num++;
+	}
+
+	len = offsetof(struct ctdb_all_public_ipsv4, ips) + 
+		num*sizeof(struct ctdb_public_ipv4);
+	ips = talloc_zero_size(outdata, len);
+	CTDB_NO_MEMORY(ctdb, ips);
+
+	outdata->dsize = len;
+	outdata->dptr  = (uint8_t *)ips;
+
+	ips->num = num;
+	i = 0;
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		if (vnn->public_address.sa.sa_family != AF_INET) {
+			continue;
+		}
+		ips->ips[i].pnn = vnn->pnn;
+		ips->ips[i].sin = vnn->public_address.ip;
+		i++;
+	}
+
+	return 0;
+}
+
+int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
+					struct ctdb_req_control *c,
+					TDB_DATA indata,
+					TDB_DATA *outdata)
+{
+	int i, num, len;
+	ctdb_sock_addr *addr;
+	struct ctdb_control_public_ip_info *info;
+	struct ctdb_vnn *vnn;
+
+	addr = (ctdb_sock_addr *)indata.dptr;
+
+	vnn = find_public_ip_vnn(ctdb, addr);
+	if (vnn == NULL) {
+		/* if it is not a public ip   it could be our 'single ip' */
+		if (ctdb->single_ip_vnn) {
+			if (ctdb_same_ip(&ctdb->single_ip_vnn->public_address, addr)) {
+				vnn = ctdb->single_ip_vnn;
+			}
+		}
+	}
+	if (vnn == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Could not get public ip info, "
+				 "'%s'not a public address\n",
+				 ctdb_addr_to_str(addr)));
+		return -1;
+	}
+
+	/* count how many public ip structures we have */
+	num = 0;
+	for (;vnn->ifaces[num];) {
+		num++;
+	}
+
+	len = offsetof(struct ctdb_control_public_ip_info, ifaces) +
+		num*sizeof(struct ctdb_control_iface_info);
+	info = talloc_zero_size(outdata, len);
+	CTDB_NO_MEMORY(ctdb, info);
+
+	info->ip.addr = vnn->public_address;
+	info->ip.pnn = vnn->pnn;
+	info->active_idx = 0xFFFFFFFF;
+
+	for (i=0; vnn->ifaces[i]; i++) {
+		struct ctdb_iface *cur;
+
+		cur = ctdb_find_iface(ctdb, vnn->ifaces[i]);
+		if (cur == NULL) {
+			DEBUG(DEBUG_CRIT, (__location__ " internal error iface[%s] unknown\n",
+					   vnn->ifaces[i]));
+			return -1;
+		}
+		if (vnn->iface == cur) {
+			info->active_idx = i;
+		}
+		strcpy(info->ifaces[i].name, cur->name);
+		info->ifaces[i].link_state = cur->link_up;
+		info->ifaces[i].references = cur->references;
+	}
+	info->num = i;
+	len = offsetof(struct ctdb_control_public_ip_info, ifaces) +
+		i*sizeof(struct ctdb_control_iface_info);
+
+	outdata->dsize = len;
+	outdata->dptr  = (uint8_t *)info;
+
+	return 0;
+}
+
+int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
+				struct ctdb_req_control *c,
+				TDB_DATA *outdata)
+{
+	int i, num, len;
+	struct ctdb_control_get_ifaces *ifaces;
+	struct ctdb_iface *cur;
+
+	/* count how many public ip structures we have */
+	num = 0;
+	for (cur=ctdb->ifaces;cur;cur=cur->next) {
+		num++;
+	}
+
+	len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
+		num*sizeof(struct ctdb_control_iface_info);
+	ifaces = talloc_zero_size(outdata, len);
+	CTDB_NO_MEMORY(ctdb, ifaces);
+
+	i = 0;
+	for (cur=ctdb->ifaces;cur;cur=cur->next) {
+		strcpy(ifaces->ifaces[i].name, cur->name);
+		ifaces->ifaces[i].link_state = cur->link_up;
+		ifaces->ifaces[i].references = cur->references;
+		i++;
+	}
+	ifaces->num = i;
+	len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
+		i*sizeof(struct ctdb_control_iface_info);
+
+	outdata->dsize = len;
+	outdata->dptr  = (uint8_t *)ifaces;
+
+	return 0;
+}
+
+int32_t ctdb_control_set_iface_link(struct ctdb_context *ctdb,
+				    struct ctdb_req_control *c,
+				    TDB_DATA indata)
+{
+	struct ctdb_control_iface_info *info;
+	struct ctdb_iface *iface;
+	bool link_up = false;
+
+	info = (struct ctdb_control_iface_info *)indata.dptr;
+
+	if (info->name[CTDB_IFACE_SIZE] != '\0') {
+		int len = strnlen(info->name, CTDB_IFACE_SIZE);
+		DEBUG(DEBUG_ERR, (__location__ " name[%*.*s] not terminated\n",
+				  len, len, info->name));
+		return -1;
+	}
+
+	switch (info->link_state) {
+	case 0:
+		link_up = false;
+		break;
+	case 1:
+		link_up = true;
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " link_state[%u] invalid\n",
+				  (unsigned int)info->link_state));
+		return -1;
+	}
+
+	if (info->references != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " references[%u] should be 0\n",
+				  (unsigned int)info->references));
+		return -1;
+	}
+
+	iface = ctdb_find_iface(ctdb, info->name);
+	if (iface == NULL) {
+		return -1;
+	}
+
+	if (link_up == iface->link_up) {
+		return 0;
+	}
+
+	DEBUG(iface->link_up?DEBUG_ERR:DEBUG_NOTICE,
+	      ("iface[%s] has changed it's link status %s => %s\n",
+	       iface->name,
+	       iface->link_up?"up":"down",
+	       link_up?"up":"down"));
+
+	iface->link_up = link_up;
+	return 0;
+}
+
+
+/* 
+   structure containing the listening socket and the list of tcp connections
+   that the ctdb daemon is to kill
+*/
+struct ctdb_kill_tcp {
+	struct ctdb_vnn *vnn;
+	struct ctdb_context *ctdb;
+	int capture_fd;
+	struct fd_event *fde;
+	trbt_tree_t *connections;
+	void *private_data;
+};
+
+/*
+  a tcp connection that is to be killed
+ */
+struct ctdb_killtcp_con {
+	ctdb_sock_addr src_addr;
+	ctdb_sock_addr dst_addr;
+	int count;
+	struct ctdb_kill_tcp *killtcp;
+};
+
+/* this function is used to create a key to represent this socketpair
+   in the killtcp tree.
+   this key is used to insert and lookup matching socketpairs that are
+   to be tickled and RST
+*/
+#define KILLTCP_KEYLEN	10
+static uint32_t *killtcp_key(ctdb_sock_addr *src, ctdb_sock_addr *dst)
+{
+	static uint32_t key[KILLTCP_KEYLEN];
+
+	bzero(key, sizeof(key));
+
+	if (src->sa.sa_family != dst->sa.sa_family) {
+		DEBUG(DEBUG_ERR, (__location__ " ERROR, different families passed :%u vs %u\n", src->sa.sa_family, dst->sa.sa_family));
+		return key;
+	}
+	
+	switch (src->sa.sa_family) {
+	case AF_INET:
+		key[0]	= dst->ip.sin_addr.s_addr;
+		key[1]	= src->ip.sin_addr.s_addr;
+		key[2]	= dst->ip.sin_port;
+		key[3]	= src->ip.sin_port;
+		break;
+	case AF_INET6:
+		key[0]	= dst->ip6.sin6_addr.s6_addr32[3];
+		key[1]	= src->ip6.sin6_addr.s6_addr32[3];
+		key[2]	= dst->ip6.sin6_addr.s6_addr32[2];
+		key[3]	= src->ip6.sin6_addr.s6_addr32[2];
+		key[4]	= dst->ip6.sin6_addr.s6_addr32[1];
+		key[5]	= src->ip6.sin6_addr.s6_addr32[1];
+		key[6]	= dst->ip6.sin6_addr.s6_addr32[0];
+		key[7]	= src->ip6.sin6_addr.s6_addr32[0];
+		key[8]	= dst->ip6.sin6_port;
+		key[9]	= src->ip6.sin6_port;
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", src->sa.sa_family));
+		return key;
+	}
+
+	return key;
+}
+
+/*
+  called when we get a read event on the raw socket
+ */
+static void capture_tcp_handler(struct event_context *ev, struct fd_event *fde, 
+				uint16_t flags, void *private_data)
+{
+	struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
+	struct ctdb_killtcp_con *con;
+	ctdb_sock_addr src, dst;
+	uint32_t ack_seq, seq;
+
+	if (!(flags & EVENT_FD_READ)) {
+		return;
+	}
+
+	if (ctdb_sys_read_tcp_packet(killtcp->capture_fd,
+				killtcp->private_data,
+				&src, &dst,
+				&ack_seq, &seq) != 0) {
+		/* probably a non-tcp ACK packet */
+		return;
+	}
+
+	/* check if we have this guy in our list of connections
+	   to kill
+	*/
+	con = trbt_lookuparray32(killtcp->connections, 
+			KILLTCP_KEYLEN, killtcp_key(&src, &dst));
+	if (con == NULL) {
+		/* no this was some other packet we can just ignore */
+		return;
+	}
+
+	/* This one has been tickled !
+	   now reset him and remove him from the list.
+	 */
+	DEBUG(DEBUG_INFO, ("sending a tcp reset to kill connection :%d -> %s:%d\n",
+		ntohs(con->dst_addr.ip.sin_port),
+		ctdb_addr_to_str(&con->src_addr),
+		ntohs(con->src_addr.ip.sin_port)));
+
+	ctdb_sys_send_tcp(&con->dst_addr, &con->src_addr, ack_seq, seq, 1);
+	talloc_free(con);
+}
+
+
+/* when traversing the list of all tcp connections to send tickle acks to
+   (so that we can capture the ack coming back and kill the connection
+    by a RST)
+   this callback is called for each connection we are currently trying to kill
+*/
+static void tickle_connection_traverse(void *param, void *data)
+{
+	struct ctdb_killtcp_con *con = talloc_get_type(data, struct ctdb_killtcp_con);
+
+	/* have tried too many times, just give up */
+	if (con->count >= 5) {
+		/* can't delete in traverse: reparent to delete_cons */
+		talloc_steal(param, con);
+		return;
+	}
+
+	/* othervise, try tickling it again */
+	con->count++;
+	ctdb_sys_send_tcp(
+		(ctdb_sock_addr *)&con->dst_addr,
+		(ctdb_sock_addr *)&con->src_addr,
+		0, 0, 0);
+}
+
+
+/* 
+   called every second until all sentenced connections have been reset
+ */
+static void ctdb_tickle_sentenced_connections(struct event_context *ev, struct timed_event *te, 
+					      struct timeval t, void *private_data)
+{
+	struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
+	void *delete_cons = talloc_new(NULL);
+
+	/* loop over all connections sending tickle ACKs */
+	trbt_traversearray32(killtcp->connections, KILLTCP_KEYLEN, tickle_connection_traverse, delete_cons);
+
+	/* now we've finished traverse, it's safe to do deletion. */
+	talloc_free(delete_cons);
+
+	/* If there are no more connections to kill we can remove the
+	   entire killtcp structure
+	 */
+	if ( (killtcp->connections == NULL) || 
+	     (killtcp->connections->root == NULL) ) {
+		talloc_free(killtcp);
+		return;
+	}
+
+	/* try tickling them again in a seconds time
+	 */
+	event_add_timed(killtcp->ctdb->ev, killtcp, timeval_current_ofs(1, 0), 
+			ctdb_tickle_sentenced_connections, killtcp);
+}
+
+/*
+  destroy the killtcp structure
+ */
+static int ctdb_killtcp_destructor(struct ctdb_kill_tcp *killtcp)
+{
+	if (killtcp->vnn) {
+		killtcp->vnn->killtcp = NULL;
+	}
+	return 0;
+}
+
+
+/* nothing fancy here, just unconditionally replace any existing
+   connection structure with the new one.
+
+   dont even free the old one if it did exist, that one is talloc_stolen
+   by the same node in the tree anyway and will be deleted when the new data 
+   is deleted
+*/
+static void *add_killtcp_callback(void *parm, void *data)
+{
+	return parm;
+}
+
+/*
+  add a tcp socket to the list of connections we want to RST
+ */
+static int ctdb_killtcp_add_connection(struct ctdb_context *ctdb, 
+				       ctdb_sock_addr *s,
+				       ctdb_sock_addr *d)
+{
+	ctdb_sock_addr src, dst;
+	struct ctdb_kill_tcp *killtcp;
+	struct ctdb_killtcp_con *con;
+	struct ctdb_vnn *vnn;
+
+	ctdb_canonicalize_ip(s, &src);
+	ctdb_canonicalize_ip(d, &dst);
+
+	vnn = find_public_ip_vnn(ctdb, &dst);
+	if (vnn == NULL) {
+		vnn = find_public_ip_vnn(ctdb, &src);
+	}
+	if (vnn == NULL) {
+		/* if it is not a public ip   it could be our 'single ip' */
+		if (ctdb->single_ip_vnn) {
+			if (ctdb_same_ip(&ctdb->single_ip_vnn->public_address, &dst)) {
+				vnn = ctdb->single_ip_vnn;
+			}
+		}
+	}
+	if (vnn == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Could not killtcp, not a public address\n")); 
+		return -1;
+	}
+
+	killtcp = vnn->killtcp;
+	
+	/* If this is the first connection to kill we must allocate
+	   a new structure
+	 */
+	if (killtcp == NULL) {
+		killtcp = talloc_zero(ctdb, struct ctdb_kill_tcp);
+		CTDB_NO_MEMORY(ctdb, killtcp);
+
+		killtcp->vnn         = vnn;
+		killtcp->ctdb        = ctdb;
+		killtcp->capture_fd  = -1;
+		killtcp->connections = trbt_create(killtcp, 0);
+
+		vnn->killtcp         = killtcp;
+		talloc_set_destructor(killtcp, ctdb_killtcp_destructor);
+	}
+
+
+
+	/* create a structure that describes this connection we want to
+	   RST and store it in killtcp->connections
+	*/
+	con = talloc(killtcp, struct ctdb_killtcp_con);
+	CTDB_NO_MEMORY(ctdb, con);
+	con->src_addr = src;
+	con->dst_addr = dst;
+	con->count    = 0;
+	con->killtcp  = killtcp;
+
+
+	trbt_insertarray32_callback(killtcp->connections,
+			KILLTCP_KEYLEN, killtcp_key(&con->dst_addr, &con->src_addr),
+			add_killtcp_callback, con);
+
+	/* 
+	   If we dont have a socket to listen on yet we must create it
+	 */
+	if (killtcp->capture_fd == -1) {
+		const char *iface = ctdb_vnn_iface_string(vnn);
+		killtcp->capture_fd = ctdb_sys_open_capture_socket(iface, &killtcp->private_data);
+		if (killtcp->capture_fd == -1) {
+			DEBUG(DEBUG_CRIT,(__location__ " Failed to open capturing "
+					  "socket on iface '%s' for killtcp (%s)\n",
+					  iface, strerror(errno)));
+			goto failed;
+		}
+	}
+
+
+	if (killtcp->fde == NULL) {
+		killtcp->fde = event_add_fd(ctdb->ev, killtcp, killtcp->capture_fd, 
+					    EVENT_FD_READ,
+					    capture_tcp_handler, killtcp);
+		tevent_fd_set_auto_close(killtcp->fde);
+
+		/* We also need to set up some events to tickle all these connections
+		   until they are all reset
+		*/
+		event_add_timed(ctdb->ev, killtcp, timeval_current_ofs(1, 0), 
+				ctdb_tickle_sentenced_connections, killtcp);
+	}
+
+	/* tickle him once now */
+	ctdb_sys_send_tcp(
+		&con->dst_addr,
+		&con->src_addr,
+		0, 0, 0);
+
+	return 0;
+
+failed:
+	talloc_free(vnn->killtcp);
+	vnn->killtcp = NULL;
+	return -1;
+}
+
+/*
+  kill a TCP connection.
+ */
+int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_control_killtcp *killtcp = (struct ctdb_control_killtcp *)indata.dptr;
+
+	return ctdb_killtcp_add_connection(ctdb, &killtcp->src_addr, &killtcp->dst_addr);
+}
+
+/*
+  called by a daemon to inform us of the entire list of TCP tickles for
+  a particular public address.
+  this control should only be sent by the node that is currently serving
+  that public address.
+ */
+int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_control_tcp_tickle_list *list = (struct ctdb_control_tcp_tickle_list *)indata.dptr;
+	struct ctdb_tcp_array *tcparray;
+	struct ctdb_vnn *vnn;
+
+	/* We must at least have tickles.num or else we cant verify the size
+	   of the received data blob
+	 */
+	if (indata.dsize < offsetof(struct ctdb_control_tcp_tickle_list, 
+					tickles.connections)) {
+		DEBUG(DEBUG_ERR,("Bad indata in ctdb_control_set_tcp_tickle_list. Not enough data for the tickle.num field\n"));
+		return -1;
+	}
+
+	/* verify that the size of data matches what we expect */
+	if (indata.dsize < offsetof(struct ctdb_control_tcp_tickle_list, 
+				tickles.connections)
+			 + sizeof(struct ctdb_tcp_connection)
+				 * list->tickles.num) {
+		DEBUG(DEBUG_ERR,("Bad indata in ctdb_control_set_tcp_tickle_list\n"));
+		return -1;
+	}	
+
+	vnn = find_public_ip_vnn(ctdb, &list->addr);
+	if (vnn == NULL) {
+		DEBUG(DEBUG_INFO,(__location__ " Could not set tcp tickle list, '%s' is not a public address\n", 
+			ctdb_addr_to_str(&list->addr)));
+
+		return 1;
+	}
+
+	/* remove any old ticklelist we might have */
+	talloc_free(vnn->tcp_array);
+	vnn->tcp_array = NULL;
+
+	tcparray = talloc(ctdb->nodes, struct ctdb_tcp_array);
+	CTDB_NO_MEMORY(ctdb, tcparray);
+
+	tcparray->num = list->tickles.num;
+
+	tcparray->connections = talloc_array(tcparray, struct ctdb_tcp_connection, tcparray->num);
+	CTDB_NO_MEMORY(ctdb, tcparray->connections);
+
+	memcpy(tcparray->connections, &list->tickles.connections[0], 
+	       sizeof(struct ctdb_tcp_connection)*tcparray->num);
+
+	/* We now have a new fresh tickle list array for this vnn */
+	vnn->tcp_array = talloc_steal(vnn, tcparray);
+	
+	return 0;
+}
+
+/*
+  called to return the full list of tickles for the puclic address associated 
+  with the provided vnn
+ */
+int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata)
+{
+	ctdb_sock_addr *addr = (ctdb_sock_addr *)indata.dptr;
+	struct ctdb_control_tcp_tickle_list *list;
+	struct ctdb_tcp_array *tcparray;
+	int num;
+	struct ctdb_vnn *vnn;
+
+	vnn = find_public_ip_vnn(ctdb, addr);
+	if (vnn == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Could not get tcp tickle list, '%s' is not a public address\n", 
+			ctdb_addr_to_str(addr)));
+
+		return 1;
+	}
+
+	tcparray = vnn->tcp_array;
+	if (tcparray) {
+		num = tcparray->num;
+	} else {
+		num = 0;
+	}
+
+	outdata->dsize = offsetof(struct ctdb_control_tcp_tickle_list, 
+				tickles.connections)
+			+ sizeof(struct ctdb_tcp_connection) * num;
+
+	outdata->dptr  = talloc_size(outdata, outdata->dsize);
+	CTDB_NO_MEMORY(ctdb, outdata->dptr);
+	list = (struct ctdb_control_tcp_tickle_list *)outdata->dptr;
+
+	list->addr = *addr;
+	list->tickles.num = num;
+	if (num) {
+		memcpy(&list->tickles.connections[0], tcparray->connections, 
+			sizeof(struct ctdb_tcp_connection) * num);
+	}
+
+	return 0;
+}
+
+
+/*
+  set the list of all tcp tickles for a public address
+ */
+static int ctdb_ctrl_set_tcp_tickles(struct ctdb_context *ctdb, 
+			      struct timeval timeout, uint32_t destnode, 
+			      ctdb_sock_addr *addr,
+			      struct ctdb_tcp_array *tcparray)
+{
+	int ret, num;
+	TDB_DATA data;
+	struct ctdb_control_tcp_tickle_list *list;
+
+	if (tcparray) {
+		num = tcparray->num;
+	} else {
+		num = 0;
+	}
+
+	data.dsize = offsetof(struct ctdb_control_tcp_tickle_list, 
+				tickles.connections) +
+			sizeof(struct ctdb_tcp_connection) * num;
+	data.dptr = talloc_size(ctdb, data.dsize);
+	CTDB_NO_MEMORY(ctdb, data.dptr);
+
+	list = (struct ctdb_control_tcp_tickle_list *)data.dptr;
+	list->addr = *addr;
+	list->tickles.num = num;
+	if (tcparray) {
+		memcpy(&list->tickles.connections[0], tcparray->connections, sizeof(struct ctdb_tcp_connection) * num);
+	}
+
+	ret = ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_CONNECTED, 0, 
+				       CTDB_CONTROL_SET_TCP_TICKLE_LIST,
+				       0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set tcp tickles failed\n"));
+		return -1;
+	}
+
+	talloc_free(data.dptr);
+
+	return ret;
+}
+
+
+/*
+  perform tickle updates if required
+ */
+static void ctdb_update_tcp_tickles(struct event_context *ev, 
+				struct timed_event *te, 
+				struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	int ret;
+	struct ctdb_vnn *vnn;
+
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		/* we only send out updates for public addresses that 
+		   we have taken over
+		 */
+		if (ctdb->pnn != vnn->pnn) {
+			continue;
+		}
+		/* We only send out the updates if we need to */
+		if (!vnn->tcp_update_needed) {
+			continue;
+		}
+		ret = ctdb_ctrl_set_tcp_tickles(ctdb, 
+				TAKEOVER_TIMEOUT(),
+				CTDB_BROADCAST_CONNECTED,
+				&vnn->public_address,
+				vnn->tcp_array);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to send the tickle update for public address %s\n",
+				ctdb_addr_to_str(&vnn->public_address)));
+		}
+	}
+
+	event_add_timed(ctdb->ev, ctdb->tickle_update_context,
+			     timeval_current_ofs(ctdb->tunable.tickle_update_interval, 0), 
+			     ctdb_update_tcp_tickles, ctdb);
+}		
+	
+
+/*
+  start periodic update of tcp tickles
+ */
+void ctdb_start_tcp_tickle_update(struct ctdb_context *ctdb)
+{
+	ctdb->tickle_update_context = talloc_new(ctdb);
+
+	event_add_timed(ctdb->ev, ctdb->tickle_update_context,
+			     timeval_current_ofs(ctdb->tunable.tickle_update_interval, 0), 
+			     ctdb_update_tcp_tickles, ctdb);
+}
+
+
+
+
+struct control_gratious_arp {
+	struct ctdb_context *ctdb;
+	ctdb_sock_addr addr;
+	const char *iface;
+	int count;
+};
+
+/*
+  send a control_gratuitous arp
+ */
+static void send_gratious_arp(struct event_context *ev, struct timed_event *te, 
+				  struct timeval t, void *private_data)
+{
+	int ret;
+	struct control_gratious_arp *arp = talloc_get_type(private_data, 
+							struct control_gratious_arp);
+
+	ret = ctdb_sys_send_arp(&arp->addr, arp->iface);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " sending of gratious arp on iface '%s' failed (%s)\n",
+				 arp->iface, strerror(errno)));
+	}
+
+
+	arp->count++;
+	if (arp->count == CTDB_ARP_REPEAT) {
+		talloc_free(arp);
+		return;
+	}
+
+	event_add_timed(arp->ctdb->ev, arp, 
+			timeval_current_ofs(CTDB_ARP_INTERVAL, 0), 
+			send_gratious_arp, arp);
+}
+
+
+/*
+  send a gratious arp 
+ */
+int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_control_gratious_arp *gratious_arp = (struct ctdb_control_gratious_arp *)indata.dptr;
+	struct control_gratious_arp *arp;
+
+	/* verify the size of indata */
+	if (indata.dsize < offsetof(struct ctdb_control_gratious_arp, iface)) {
+		DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_gratious_arp structure. Got %u require %u bytes\n", 
+				 (unsigned)indata.dsize, 
+				 (unsigned)offsetof(struct ctdb_control_gratious_arp, iface)));
+		return -1;
+	}
+	if (indata.dsize != 
+		( offsetof(struct ctdb_control_gratious_arp, iface)
+		+ gratious_arp->len ) ){
+
+		DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
+			"but should be %u bytes\n", 
+			 (unsigned)indata.dsize, 
+			 (unsigned)(offsetof(struct ctdb_control_gratious_arp, iface)+gratious_arp->len)));
+		return -1;
+	}
+
+
+	arp = talloc(ctdb, struct control_gratious_arp);
+	CTDB_NO_MEMORY(ctdb, arp);
+
+	arp->ctdb  = ctdb;
+	arp->addr   = gratious_arp->addr;
+	arp->iface = talloc_strdup(arp, gratious_arp->iface);
+	CTDB_NO_MEMORY(ctdb, arp->iface);
+	arp->count = 0;
+	
+	event_add_timed(arp->ctdb->ev, arp, 
+			timeval_zero(), send_gratious_arp, arp);
+
+	return 0;
+}
+
+int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_control_ip_iface *pub = (struct ctdb_control_ip_iface *)indata.dptr;
+	int ret;
+
+	/* verify the size of indata */
+	if (indata.dsize < offsetof(struct ctdb_control_ip_iface, iface)) {
+		DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_ip_iface structure\n"));
+		return -1;
+	}
+	if (indata.dsize != 
+		( offsetof(struct ctdb_control_ip_iface, iface)
+		+ pub->len ) ){
+
+		DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
+			"but should be %u bytes\n", 
+			 (unsigned)indata.dsize, 
+			 (unsigned)(offsetof(struct ctdb_control_ip_iface, iface)+pub->len)));
+		return -1;
+	}
+
+	ret = ctdb_add_public_address(ctdb, &pub->addr, pub->mask, &pub->iface[0]);
+
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to add public address\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  called when releaseip event finishes for del_public_address
+ */
+static void delete_ip_callback(struct ctdb_context *ctdb, int status, 
+				void *private_data)
+{
+	talloc_free(private_data);
+}
+
+int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_control_ip_iface *pub = (struct ctdb_control_ip_iface *)indata.dptr;
+	struct ctdb_vnn *vnn;
+	int ret;
+
+	/* verify the size of indata */
+	if (indata.dsize < offsetof(struct ctdb_control_ip_iface, iface)) {
+		DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_ip_iface structure\n"));
+		return -1;
+	}
+	if (indata.dsize != 
+		( offsetof(struct ctdb_control_ip_iface, iface)
+		+ pub->len ) ){
+
+		DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
+			"but should be %u bytes\n", 
+			 (unsigned)indata.dsize, 
+			 (unsigned)(offsetof(struct ctdb_control_ip_iface, iface)+pub->len)));
+		return -1;
+	}
+
+	/* walk over all public addresses until we find a match */
+	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
+		if (ctdb_same_ip(&vnn->public_address, &pub->addr)) {
+			TALLOC_CTX *mem_ctx;
+
+			DLIST_REMOVE(ctdb->vnn, vnn);
+			if (vnn->pnn != ctdb->pnn) {
+				if (vnn->iface != NULL) {
+					ctdb_vnn_unassign_iface(ctdb, vnn);
+				}
+				talloc_free(vnn);
+				return 0;
+			}
+			vnn->pnn = -1;
+
+			mem_ctx = talloc_new(ctdb);
+			talloc_steal(mem_ctx, vnn);
+			ret = ctdb_event_script_callback(ctdb, 
+					 mem_ctx, delete_ip_callback, mem_ctx,
+					 false,
+					 CTDB_EVENT_RELEASE_IP,
+					 "%s %s %u",
+					 ctdb_vnn_iface_string(vnn),
+					 ctdb_addr_to_str(&vnn->public_address),
+					 vnn->public_netmask_bits);
+			if (vnn->iface != NULL) {
+				ctdb_vnn_unassign_iface(ctdb, vnn);
+			}
+			if (ret != 0) {
+				return -1;
+			}
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+/* This function is called from the recovery daemon to verify that a remote
+   node has the expected ip allocation.
+   This is verified against ctdb->ip_tree
+*/
+int verify_remote_ip_allocation(struct ctdb_context *ctdb, struct ctdb_all_public_ips *ips)
+{
+	struct ctdb_public_ip_list *tmp_ip; 
+	int i;
+
+	if (ctdb->ip_tree == NULL) {
+		/* dont know the expected allocation yet, assume remote node
+		   is correct. */
+		return 0;
+	}
+
+	if (ips == NULL) {
+		return 0;
+	}
+
+	for (i=0; i<ips->num; i++) {
+		tmp_ip = trbt_lookuparray32(ctdb->ip_tree, IP_KEYLEN, ip_key(&ips->ips[i].addr));
+		if (tmp_ip == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Could not find host for address %s, reassign ips\n", ctdb_addr_to_str(&ips->ips[i].addr)));
+			return -1;
+		}
+
+		if (tmp_ip->pnn == -1 || ips->ips[i].pnn == -1) {
+			continue;
+		}
+
+		if (tmp_ip->pnn != ips->ips[i].pnn) {
+			DEBUG(DEBUG_ERR,("Inconsistent ip allocation. Trigger reallocation. Thinks %s is held by node %u while it is held by node %u\n", ctdb_addr_to_str(&ips->ips[i].addr), ips->ips[i].pnn, tmp_ip->pnn));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int update_ip_assignment_tree(struct ctdb_context *ctdb, struct ctdb_public_ip *ip)
+{
+	struct ctdb_public_ip_list *tmp_ip; 
+
+	if (ctdb->ip_tree == NULL) {
+		DEBUG(DEBUG_ERR,("No ctdb->ip_tree yet. Failed to update ip assignment\n"));
+		return -1;
+	}
+
+	tmp_ip = trbt_lookuparray32(ctdb->ip_tree, IP_KEYLEN, ip_key(&ip->addr));
+	if (tmp_ip == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Could not find record for address %s, update ip\n", ctdb_addr_to_str(&ip->addr)));
+		return -1;
+	}
+
+	DEBUG(DEBUG_NOTICE,("Updated ip assignment tree for ip : %s from node %u to node %u\n", ctdb_addr_to_str(&ip->addr), tmp_ip->pnn, ip->pnn));
+	tmp_ip->pnn = ip->pnn;
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_traverse.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_traverse.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_traverse.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,607 @@
+/* 
+   efficient async ctdb traverse
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "db_wrap.h"
+#include "lib/tdb/include/tdb.h"
+#include "../include/ctdb_private.h"
+#include "lib/util/dlinklist.h"
+
+typedef void (*ctdb_traverse_fn_t)(void *private_data, TDB_DATA key, TDB_DATA data);
+
+/*
+  handle returned to caller - freeing this handler will kill the child and 
+  terminate the traverse
+ */
+struct ctdb_traverse_local_handle {
+	struct ctdb_traverse_local_handle *next, *prev;
+	struct ctdb_db_context *ctdb_db;
+	int fd[2];
+	pid_t child;
+	uint64_t srvid;
+	uint32_t client_reqid;
+	void *private_data;
+	ctdb_traverse_fn_t callback;
+	struct timeval start_time;
+	struct ctdb_queue *queue;
+};
+
+/*
+  called when data is available from the child
+ */
+static void ctdb_traverse_local_handler(uint8_t *rawdata, size_t length, void *private_data)
+{
+	struct ctdb_traverse_local_handle *h = talloc_get_type(private_data, 
+							       struct ctdb_traverse_local_handle);
+	TDB_DATA key, data;
+	ctdb_traverse_fn_t callback = h->callback;
+	void *p = h->private_data;
+	struct ctdb_rec_data *tdata = (struct ctdb_rec_data *)rawdata;
+
+	if (rawdata == NULL || length < 4 || length != tdata->length) {
+		/* end of traverse */
+		talloc_free(h);
+		callback(p, tdb_null, tdb_null);
+		return;
+	}
+
+	key.dsize = tdata->keylen;
+	key.dptr  = &tdata->data[0];
+	data.dsize = tdata->datalen;
+	data.dptr = &tdata->data[tdata->keylen];
+
+	callback(p, key, data);	
+}
+
+/*
+  destroy a in-flight traverse operation
+ */
+static int traverse_local_destructor(struct ctdb_traverse_local_handle *h)
+{
+	DLIST_REMOVE(h->ctdb_db->traverse, h);
+	kill(h->child, SIGKILL);
+	return 0;
+}
+
+/*
+  callback from tdb_traverse_read()
+ */
+static int ctdb_traverse_local_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *p)
+{
+	struct ctdb_traverse_local_handle *h = talloc_get_type(p, 
+							       struct ctdb_traverse_local_handle);
+	struct ctdb_rec_data *d;
+	struct ctdb_ltdb_header *hdr;
+
+	hdr = (struct ctdb_ltdb_header *)data.dptr;
+
+	if (h->ctdb_db->persistent == 0) {
+		/* filter out zero-length records */
+		if (data.dsize <= sizeof(struct ctdb_ltdb_header)) {
+			return 0;
+		}
+
+		/* filter out non-authoritative records */
+		if (hdr->dmaster != h->ctdb_db->ctdb->pnn) {
+			return 0;
+		}
+	}
+
+	d = ctdb_marshall_record(h, 0, key, NULL, data);
+	if (d == NULL) {
+		/* error handling is tricky in this child code .... */
+		return -1;
+	}
+
+	if (write(h->fd[1], (uint8_t *)d, d->length) != d->length) {
+		return -1;
+	}
+	return 0;
+}
+
+struct traverse_all_state {
+	struct ctdb_context *ctdb;
+	struct ctdb_traverse_local_handle *h;
+	uint32_t reqid;
+	uint32_t srcnode;
+	uint32_t client_reqid;
+	uint64_t srvid;
+};
+
+/*
+  setup a non-blocking traverse of a local ltdb. The callback function
+  will be called on every record in the local ltdb. To stop the
+  traverse, talloc_free() the traverse_handle.
+
+  The traverse is finished when the callback is called with tdb_null for key and data
+ */
+static struct ctdb_traverse_local_handle *ctdb_traverse_local(struct ctdb_db_context *ctdb_db,
+							      ctdb_traverse_fn_t callback,
+							      struct traverse_all_state *all_state)
+{
+	struct ctdb_traverse_local_handle *h;
+	int ret;
+
+	h = talloc_zero(all_state, struct ctdb_traverse_local_handle);
+	if (h == NULL) {
+		return NULL;
+	}
+
+	ret = pipe(h->fd);
+
+	if (ret != 0) {
+		talloc_free(h);
+		return NULL;
+	}
+
+	h->child = ctdb_fork(ctdb_db->ctdb);
+
+	if (h->child == (pid_t)-1) {
+		close(h->fd[0]);
+		close(h->fd[1]);
+		talloc_free(h);
+		return NULL;
+	}
+
+	h->callback = callback;
+	h->private_data = all_state;
+	h->ctdb_db = ctdb_db;
+	h->client_reqid = all_state->client_reqid;
+	h->srvid = all_state->srvid;
+
+	if (h->child == 0) {
+		/* start the traverse in the child */
+		close(h->fd[0]);
+		debug_extra = talloc_asprintf(NULL, "traverse_local-%s:",
+					      ctdb_db->db_name);
+		tdb_traverse_read(ctdb_db->ltdb->tdb, ctdb_traverse_local_fn, h);
+		_exit(0);
+	}
+
+	close(h->fd[1]);
+	set_close_on_exec(h->fd[0]);
+
+	talloc_set_destructor(h, traverse_local_destructor);
+
+	DLIST_ADD(ctdb_db->traverse, h);
+
+	/*
+	  setup a packet queue between the child and the parent. This
+	  copes with all the async and packet boundary issues
+	 */
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to child traverse\n", h->fd[0]));
+
+	h->queue = ctdb_queue_setup(ctdb_db->ctdb, h, h->fd[0], 0, ctdb_traverse_local_handler, h,
+				    "to-ctdbd");
+	if (h->queue == NULL) {
+		talloc_free(h);
+		return NULL;
+	}
+
+	h->start_time = timeval_current();
+
+	return h;
+}
+
+
+struct ctdb_traverse_all_handle {
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	uint32_t reqid;
+	ctdb_traverse_fn_t callback;
+	void *private_data;
+	uint32_t null_count;
+};
+
+/*
+  destroy a traverse_all op
+ */
+static int ctdb_traverse_all_destructor(struct ctdb_traverse_all_handle *state)
+{
+	ctdb_reqid_remove(state->ctdb, state->reqid);
+	return 0;
+}
+
+struct ctdb_traverse_all {
+	uint32_t db_id;
+	uint32_t reqid;
+	uint32_t pnn;
+	uint32_t client_reqid;
+	uint64_t srvid;
+};
+
+/* called when a traverse times out */
+static void ctdb_traverse_all_timeout(struct event_context *ev, struct timed_event *te, 
+				      struct timeval t, void *private_data)
+{
+	struct ctdb_traverse_all_handle *state = talloc_get_type(private_data, struct ctdb_traverse_all_handle);
+
+	DEBUG(DEBUG_ERR,(__location__ " Traverse all timeout on database:%s\n", state->ctdb_db->db_name));
+	CTDB_INCREMENT_STAT(state->ctdb, timeouts.traverse);
+
+	state->callback(state->private_data, tdb_null, tdb_null);
+}
+
+
+struct traverse_start_state {
+	struct ctdb_context *ctdb;
+	struct ctdb_traverse_all_handle *h;
+	uint32_t srcnode;
+	uint32_t reqid;
+	uint32_t db_id;
+	uint64_t srvid;
+};
+
+
+/*
+  setup a cluster-wide non-blocking traverse of a ctdb. The
+  callback function will be called on every record in the local
+  ltdb. To stop the travserse, talloc_free() the traverse_handle.
+
+  The traverse is finished when the callback is called with tdb_null
+  for key and data
+ */
+static struct ctdb_traverse_all_handle *ctdb_daemon_traverse_all(struct ctdb_db_context *ctdb_db,
+								 ctdb_traverse_fn_t callback,
+								 struct traverse_start_state *start_state)
+{
+	struct ctdb_traverse_all_handle *state;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	int ret;
+	TDB_DATA data;
+	struct ctdb_traverse_all r;
+	uint32_t destination;
+
+	state = talloc(start_state, struct ctdb_traverse_all_handle);
+	if (state == NULL) {
+		return NULL;
+	}
+
+	state->ctdb         = ctdb;
+	state->ctdb_db      = ctdb_db;
+	state->reqid        = ctdb_reqid_new(ctdb_db->ctdb, state);
+	state->callback     = callback;
+	state->private_data = start_state;
+	state->null_count   = 0;
+	
+	talloc_set_destructor(state, ctdb_traverse_all_destructor);
+
+	r.db_id = ctdb_db->db_id;
+	r.reqid = state->reqid;
+	r.pnn   = ctdb->pnn;
+	r.client_reqid = start_state->reqid;
+	r.srvid = start_state->srvid;
+
+	data.dptr = (uint8_t *)&r;
+	data.dsize = sizeof(r);
+
+	if (ctdb_db->persistent == 0) {
+		/* normal database, traverse all nodes */	  
+		destination = CTDB_BROADCAST_VNNMAP;
+	} else {
+		int i;
+		/* persistent database, traverse one node, preferably
+		 * the local one
+		 */
+		destination = ctdb->pnn;
+		/* check we are in the vnnmap */
+		for (i=0; i < ctdb->vnn_map->size; i++) {
+			if (ctdb->vnn_map->map[i] == ctdb->pnn) {
+				break;
+			}
+		}
+		/* if we are not in the vnn map we just pick the first
+		 * node instead
+		 */
+		if (i == ctdb->vnn_map->size) {
+			destination = ctdb->vnn_map->map[0];
+		}
+	}
+
+	/* tell all the nodes in the cluster to start sending records to this
+	 * node, or if it is a persistent database, just tell the local
+	 * node
+	 */
+	ret = ctdb_daemon_send_control(ctdb, destination, 0, 
+			       CTDB_CONTROL_TRAVERSE_ALL,
+			       0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
+
+	if (ret != 0) {
+		talloc_free(state);
+		return NULL;
+	}
+
+	/* timeout the traverse */
+	event_add_timed(ctdb->ev, state, 
+			timeval_current_ofs(ctdb->tunable.traverse_timeout, 0), 
+			ctdb_traverse_all_timeout, state);
+
+	return state;
+}
+
+/*
+  called for each record during a traverse all 
+ */
+static void traverse_all_callback(void *p, TDB_DATA key, TDB_DATA data)
+{
+	struct traverse_all_state *state = talloc_get_type(p, struct traverse_all_state);
+	int ret;
+	struct ctdb_rec_data *d;
+	TDB_DATA cdata;
+
+	d = ctdb_marshall_record(state, state->reqid, key, NULL, data);
+	if (d == NULL) {
+		/* darn .... */
+		DEBUG(DEBUG_ERR,("Out of memory in traverse_all_callback\n"));
+		return;
+	}
+
+	cdata.dptr = (uint8_t *)d;
+	cdata.dsize = d->length;
+
+	ret = ctdb_daemon_send_control(state->ctdb, state->srcnode, 0, CTDB_CONTROL_TRAVERSE_DATA,
+				       0, CTDB_CTRL_FLAG_NOREPLY, cdata, NULL, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send traverse data\n"));
+	}
+
+	if (key.dsize == 0 && data.dsize == 0) {
+		/* we're done */
+		talloc_free(state);
+	}
+}
+
+/*
+  called when a CTDB_CONTROL_TRAVERSE_ALL control comes in. We then
+  setup a traverse of our local ltdb, sending the records as
+  CTDB_CONTROL_TRAVERSE_DATA records back to the originator
+ */
+int32_t ctdb_control_traverse_all(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata)
+{
+	struct ctdb_traverse_all *c = (struct ctdb_traverse_all *)data.dptr;
+	struct traverse_all_state *state;
+	struct ctdb_db_context *ctdb_db;
+
+	if (data.dsize != sizeof(struct ctdb_traverse_all)) {
+		DEBUG(DEBUG_ERR,(__location__ " Invalid size in ctdb_control_traverse_all\n"));
+		return -1;
+	}
+
+	ctdb_db = find_ctdb_db(ctdb, c->db_id);
+	if (ctdb_db == NULL) {
+		return -1;
+	}
+
+	if (ctdb_db->unhealthy_reason) {
+		if (ctdb->tunable.allow_unhealthy_db_read == 0) {
+			DEBUG(DEBUG_ERR,("db(%s) unhealty in ctdb_control_traverse_all: %s\n",
+					ctdb_db->db_name, ctdb_db->unhealthy_reason));
+			return -1;
+		}
+		DEBUG(DEBUG_WARNING,("warn: db(%s) unhealty in ctdb_control_traverse_all: %s\n",
+				     ctdb_db->db_name, ctdb_db->unhealthy_reason));
+	}
+
+	state = talloc(ctdb_db, struct traverse_all_state);
+	if (state == NULL) {
+		return -1;
+	}
+
+	state->reqid = c->reqid;
+	state->srcnode = c->pnn;
+	state->ctdb = ctdb;
+	state->client_reqid = c->client_reqid;
+	state->srvid = c->srvid;
+
+	state->h = ctdb_traverse_local(ctdb_db, traverse_all_callback, state);
+	if (state->h == NULL) {
+		talloc_free(state);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+  called when a CTDB_CONTROL_TRAVERSE_DATA control comes in. We then
+  call the traverse_all callback with the record
+ */
+int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata)
+{
+	struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr;
+	struct ctdb_traverse_all_handle *state;
+	TDB_DATA key;
+	ctdb_traverse_fn_t callback;
+	void *private_data;
+
+	if (data.dsize < sizeof(uint32_t) || data.dsize != d->length) {
+		DEBUG(DEBUG_ERR,("Bad record size in ctdb_control_traverse_data\n"));
+		return -1;
+	}
+
+	state = ctdb_reqid_find(ctdb, d->reqid, struct ctdb_traverse_all_handle);
+	if (state == NULL || d->reqid != state->reqid) {
+		/* traverse might have been terminated already */
+		return -1;
+	}
+
+	key.dsize = d->keylen;
+	key.dptr  = &d->data[0];
+	data.dsize = d->datalen;
+	data.dptr = &d->data[d->keylen];
+
+	if (key.dsize == 0 && data.dsize == 0) {
+		state->null_count++;
+		/* Persistent databases are only scanned on one node (the local
+		 * node)
+		 */
+		if (state->ctdb_db->persistent == 0) {
+			if (state->null_count != ctdb_get_num_active_nodes(ctdb)) {
+				return 0;
+			}
+		}
+	}
+
+	callback = state->callback;
+	private_data = state->private_data;
+
+	callback(private_data, key, data);
+	return 0;
+}	
+
+/*
+  kill a in-progress traverse, used when a client disconnects
+ */
+int32_t ctdb_control_traverse_kill(struct ctdb_context *ctdb, TDB_DATA data, 
+				   TDB_DATA *outdata, uint32_t srcnode)
+{
+	struct ctdb_traverse_start *d = (struct ctdb_traverse_start *)data.dptr;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_traverse_local_handle *t;
+
+	ctdb_db = find_ctdb_db(ctdb, d->db_id);
+	if (ctdb_db == NULL) {
+		return -1;
+	}
+
+	for (t=ctdb_db->traverse; t; t=t->next) {
+		if (t->client_reqid == d->reqid &&
+		    t->srvid == d->srvid) {
+			talloc_free(t);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+  this is called when a client disconnects during a traverse
+  we need to notify all the nodes taking part in the search that they
+  should kill their traverse children
+ */
+static int ctdb_traverse_start_destructor(struct traverse_start_state *state)
+{
+	struct ctdb_traverse_start r;
+	TDB_DATA data;
+
+	DEBUG(DEBUG_ERR,(__location__ " Traverse cancelled by client disconnect for database:0x%08x\n", state->db_id));
+	r.db_id = state->db_id;
+	r.reqid = state->reqid;
+	r.srvid = state->srvid;
+
+	data.dptr = (uint8_t *)&r;
+	data.dsize = sizeof(r);
+
+	ctdb_daemon_send_control(state->ctdb, CTDB_BROADCAST_CONNECTED, 0, 
+				 CTDB_CONTROL_TRAVERSE_KILL, 
+				 0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
+	return 0;
+}
+
+/*
+  callback which sends records as messages to the client
+ */
+static void traverse_start_callback(void *p, TDB_DATA key, TDB_DATA data)
+{
+	struct traverse_start_state *state;
+	struct ctdb_rec_data *d;
+	TDB_DATA cdata;
+
+	state = talloc_get_type(p, struct traverse_start_state);
+
+	d = ctdb_marshall_record(state, state->reqid, key, NULL, data);
+	if (d == NULL) {
+		return;
+	}
+
+	cdata.dptr = (uint8_t *)d;
+	cdata.dsize = d->length;
+
+	ctdb_dispatch_message(state->ctdb, state->srvid, cdata);
+	if (key.dsize == 0 && data.dsize == 0) {
+		/* end of traverse */
+		talloc_set_destructor(state, NULL);
+		talloc_free(state);
+	}
+}
+
+
+/*
+  start a traverse_all - called as a control from a client
+ */
+int32_t ctdb_control_traverse_start(struct ctdb_context *ctdb, TDB_DATA data, 
+				    TDB_DATA *outdata, uint32_t srcnode, uint32_t client_id)
+{
+	struct ctdb_traverse_start *d = (struct ctdb_traverse_start *)data.dptr;
+	struct traverse_start_state *state;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+
+	if (client == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " No client found\n"));
+		return -1;		
+	}
+
+	if (data.dsize != sizeof(*d)) {
+		DEBUG(DEBUG_ERR,("Bad record size in ctdb_control_traverse_start\n"));
+		return -1;
+	}
+
+	ctdb_db = find_ctdb_db(ctdb, d->db_id);
+	if (ctdb_db == NULL) {
+		return -1;
+	}
+
+	if (ctdb_db->unhealthy_reason) {
+		if (ctdb->tunable.allow_unhealthy_db_read == 0) {
+			DEBUG(DEBUG_ERR,("db(%s) unhealty in ctdb_control_traverse_start: %s\n",
+					ctdb_db->db_name, ctdb_db->unhealthy_reason));
+			return -1;
+		}
+		DEBUG(DEBUG_WARNING,("warn: db(%s) unhealty in ctdb_control_traverse_start: %s\n",
+				     ctdb_db->db_name, ctdb_db->unhealthy_reason));
+	}
+
+	state = talloc(client, struct traverse_start_state);
+	if (state == NULL) {
+		return -1;
+	}
+	
+	state->srcnode = srcnode;
+	state->reqid = d->reqid;
+	state->srvid = d->srvid;
+	state->db_id = d->db_id;
+	state->ctdb = ctdb;
+
+	state->h = ctdb_daemon_traverse_all(ctdb_db, traverse_start_callback, state);
+	if (state->h == NULL) {
+		talloc_free(state);
+		return -1;
+	}
+
+	talloc_set_destructor(state, ctdb_traverse_start_destructor);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_tunables.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_tunables.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_tunables.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,199 @@
+/* 
+   ctdb tunables code
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "../include/ctdb_private.h"
+
+static const struct {
+	const char *name;
+	uint32_t default_v;
+	size_t offset;	
+} tunable_map[] = {
+	{ "MaxRedirectCount",     3,  offsetof(struct ctdb_tunable, max_redirect_count) },
+	{ "SeqnumInterval",      1000,  offsetof(struct ctdb_tunable, seqnum_interval) },
+	{ "ControlTimeout",      60, offsetof(struct ctdb_tunable, control_timeout) },
+	{ "TraverseTimeout",     20, offsetof(struct ctdb_tunable, traverse_timeout) },
+	{ "KeepaliveInterval",    5,  offsetof(struct ctdb_tunable, keepalive_interval) },
+	{ "KeepaliveLimit",       5,  offsetof(struct ctdb_tunable, keepalive_limit) },
+	{ "RecoverTimeout",      20,  offsetof(struct ctdb_tunable, recover_timeout) },
+	{ "RecoverInterval",      1,  offsetof(struct ctdb_tunable, recover_interval) },
+	{ "ElectionTimeout",      3,  offsetof(struct ctdb_tunable, election_timeout) },
+	{ "TakeoverTimeout",      9,  offsetof(struct ctdb_tunable, takeover_timeout) },
+	{ "MonitorInterval",     15,  offsetof(struct ctdb_tunable, monitor_interval) },
+	{ "TickleUpdateInterval",20,  offsetof(struct ctdb_tunable, tickle_update_interval) },
+	{ "EventScriptTimeout",  30,  offsetof(struct ctdb_tunable, script_timeout) },
+	{ "EventScriptTimeoutCount", 1,  offsetof(struct ctdb_tunable, script_timeout_count) },
+	{ "EventScriptUnhealthyOnTimeout", 0, offsetof(struct ctdb_tunable, script_unhealthy_on_timeout) },/* OBSOLETE */
+	{ "RecoveryGracePeriod", 120,  offsetof(struct ctdb_tunable, recovery_grace_period) },
+	{ "RecoveryBanPeriod",  300,  offsetof(struct ctdb_tunable, recovery_ban_period) },
+	{ "DatabaseHashSize", 100001, offsetof(struct ctdb_tunable, database_hash_size) },
+	{ "DatabaseMaxDead",      5,  offsetof(struct ctdb_tunable, database_max_dead) },
+	{ "RerecoveryTimeout",   10,  offsetof(struct ctdb_tunable, rerecovery_timeout) },
+	{ "EnableBans",           1,  offsetof(struct ctdb_tunable, enable_bans) },
+	{ "DeterministicIPs",     0,  offsetof(struct ctdb_tunable, deterministic_public_ips) },
+	{ "LCP2PublicIPs",        1,  offsetof(struct ctdb_tunable, lcp2_public_ip_assignment) },
+	{ "ReclockPingPeriod",   60,  offsetof(struct ctdb_tunable,  reclock_ping_period) },
+	{ "NoIPFailback",         0,  offsetof(struct ctdb_tunable, no_ip_failback) },
+	{ "DisableIPFailover",    0,  offsetof(struct ctdb_tunable, disable_ip_failover) },
+	{ "VerboseMemoryNames",   0,  offsetof(struct ctdb_tunable, verbose_memory_names) },
+	{ "RecdPingTimeout",	 60,  offsetof(struct ctdb_tunable, recd_ping_timeout) },
+	{ "RecdFailCount",	 10,  offsetof(struct ctdb_tunable, recd_ping_failcount) },
+	{ "LogLatencyMs",         0,  offsetof(struct ctdb_tunable, log_latency_ms) },
+	{ "RecLockLatencyMs",  1000,  offsetof(struct ctdb_tunable, reclock_latency_ms) },
+	{ "RecoveryDropAllIPs", 120,  offsetof(struct ctdb_tunable, recovery_drop_all_ips) },
+	{ "VerifyRecoveryLock",   1,  offsetof(struct ctdb_tunable, verify_recovery_lock) },
+	{ "VacuumDefaultInterval", 10,  offsetof(struct ctdb_tunable, vacuum_default_interval) },
+	{ "VacuumMaxRunTime",     30,  offsetof(struct ctdb_tunable, vacuum_max_run_time) },
+	{ "RepackLimit",      10000,  offsetof(struct ctdb_tunable, repack_limit) },
+	{ "VacuumLimit",       5000,  offsetof(struct ctdb_tunable, vacuum_limit) },
+	{ "VacuumMinInterval",   10,  offsetof(struct ctdb_tunable, vacuum_min_interval) },
+	{ "VacuumMaxInterval",   10,  offsetof(struct ctdb_tunable, vacuum_max_interval) },
+	{ "VacuumFastPathCount", 60, offsetof(struct ctdb_tunable, vacuum_fast_path_count) },
+	{ "MaxQueueDropMsg",  1000000, offsetof(struct ctdb_tunable, max_queue_depth_drop_msg) },
+	{ "UseStatusEvents",     0,  offsetof(struct ctdb_tunable, use_status_events_for_monitoring) },
+	{ "AllowUnhealthyDBRead", 0,  offsetof(struct ctdb_tunable, allow_unhealthy_db_read) },
+	{ "StatHistoryInterval",  1,  offsetof(struct ctdb_tunable, stat_history_interval) },
+	{ "DeferredAttachTO",  120,  offsetof(struct ctdb_tunable, deferred_attach_timeout) },
+	{ "AllowClientDBAttach", 1, offsetof(struct ctdb_tunable, allow_client_db_attach) }
+};
+
+/*
+  set all tunables to defaults
+ */
+void ctdb_tunables_set_defaults(struct ctdb_context *ctdb)
+{
+	int i;
+	for (i=0;i<ARRAY_SIZE(tunable_map);i++) {
+		*(uint32_t *)(tunable_map[i].offset + (uint8_t*)&ctdb->tunable) = tunable_map[i].default_v;
+	}
+}
+
+
+/*
+  get a tunable
+ */
+int32_t ctdb_control_get_tunable(struct ctdb_context *ctdb, TDB_DATA indata, 
+				 TDB_DATA *outdata)
+{
+	struct ctdb_control_get_tunable *t = 
+		(struct ctdb_control_get_tunable *)indata.dptr;
+	char *name;
+	uint32_t val;
+	int i;
+
+	if (indata.dsize < sizeof(*t) ||
+	    t->length > indata.dsize - offsetof(struct ctdb_control_get_tunable, name)) {
+		DEBUG(DEBUG_ERR,("Bad indata in ctdb_control_get_tunable\n"));
+		return -1;
+	}
+
+	name = talloc_strndup(ctdb, (char*)t->name, t->length);
+	CTDB_NO_MEMORY(ctdb, name);
+
+	for (i=0;i<ARRAY_SIZE(tunable_map);i++) {
+		if (strcasecmp(name, tunable_map[i].name) == 0) break;
+	}
+	talloc_free(name);
+	
+	if (i == ARRAY_SIZE(tunable_map)) {
+		return -1;
+	}
+
+	val = *(uint32_t *)(tunable_map[i].offset + (uint8_t*)&ctdb->tunable);
+
+	outdata->dptr = (uint8_t *)talloc(outdata, uint32_t);
+	CTDB_NO_MEMORY(ctdb, outdata->dptr);
+
+	*(uint32_t *)outdata->dptr = val;
+	outdata->dsize = sizeof(uint32_t);
+
+	return 0;
+}
+
+
+/*
+  set a tunable
+ */
+int32_t ctdb_control_set_tunable(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	struct ctdb_control_set_tunable *t = 
+		(struct ctdb_control_set_tunable *)indata.dptr;
+	char *name;
+	int i;
+
+	if (indata.dsize < sizeof(*t) ||
+	    t->length > indata.dsize - offsetof(struct ctdb_control_set_tunable, name)) {
+		DEBUG(DEBUG_ERR,("Bad indata in ctdb_control_set_tunable\n"));
+		return -1;
+	}
+
+	name = talloc_strndup(ctdb, (char *)t->name, t->length);
+	CTDB_NO_MEMORY(ctdb, name);
+
+	for (i=0;i<ARRAY_SIZE(tunable_map);i++) {
+		if (strcasecmp(name, tunable_map[i].name) == 0) break;
+	}
+
+	if (!strcmp(name, "VerifyRecoveryLock") && t->value != 0
+	&& ctdb->recovery_lock_file == NULL) {
+		DEBUG(DEBUG_ERR,("Can not activate tunable \"VerifyRecoveryLock\" since there is no recovery lock file set.\n"));
+		talloc_free(name);
+		return -1;
+	}
+
+	talloc_free(name);
+	
+	if (i == ARRAY_SIZE(tunable_map)) {
+		return -1;
+	}
+
+	*(uint32_t *)(tunable_map[i].offset + (uint8_t*)&ctdb->tunable) = t->value;
+
+	return 0;
+}
+
+/*
+  list tunables
+ */
+int32_t ctdb_control_list_tunables(struct ctdb_context *ctdb, TDB_DATA *outdata)
+{
+	char *list = NULL;
+	int i;
+	struct ctdb_control_list_tunable *t;
+
+	list = talloc_strdup(outdata, tunable_map[0].name);
+	CTDB_NO_MEMORY(ctdb, list);
+
+	for (i=1;i<ARRAY_SIZE(tunable_map);i++) {
+		list = talloc_asprintf_append(list, ":%s", tunable_map[i].name);
+		CTDB_NO_MEMORY(ctdb, list);		
+	}
+
+	outdata->dsize = offsetof(struct ctdb_control_list_tunable, data) + 
+		strlen(list) + 1;
+	outdata->dptr = talloc_size(outdata, outdata->dsize);
+	CTDB_NO_MEMORY(ctdb, outdata->dptr);
+
+	t = (struct ctdb_control_list_tunable *)outdata->dptr;
+	t->length = strlen(list)+1;
+
+	memcpy(t->data, list, t->length);
+	talloc_free(list);
+
+	return 0;	
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_uptime.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_uptime.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_uptime.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,46 @@
+/* 
+   ctdb uptime code
+
+   Copyright (C) Ronnie Sahlberg 2008
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "../include/ctdb_private.h"
+#include "system/syslog.h"
+#include "system/time.h"
+#include "system/filesys.h"
+
+/* 
+   returns the ctdb uptime
+*/
+int32_t ctdb_control_uptime(struct ctdb_context *ctdb, TDB_DATA *outdata)
+{
+	struct ctdb_uptime *uptime;
+
+	uptime = talloc_zero(outdata, struct ctdb_uptime);
+	CTDB_NO_MEMORY(ctdb, uptime);
+
+	gettimeofday(&uptime->current_time, NULL);
+	uptime->ctdbd_start_time       = ctdb->ctdbd_start_time;
+	uptime->last_recovery_started  = ctdb->last_recovery_started;
+	uptime->last_recovery_finished = ctdb->last_recovery_finished;
+
+	outdata->dsize = sizeof(struct ctdb_uptime);
+	outdata->dptr  = (uint8_t *)uptime;
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/server/ctdb_vacuum.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdb_vacuum.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdb_vacuum.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1407 @@
+/*
+   ctdb vacuuming events
+
+   Copyright (C) Ronnie Sahlberg  2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include "../include/ctdb_private.h"
+#include "db_wrap.h"
+#include "lib/util/dlinklist.h"
+#include "lib/tevent/tevent.h"
+#include "../include/ctdb_private.h"
+#include "../common/rb_tree.h"
+
+#define TIMELIMIT() timeval_current_ofs(10, 0)
+#define TUNINGDBNAME "vactune.tdb"
+
+enum vacuum_child_status { VACUUM_RUNNING, VACUUM_OK, VACUUM_ERROR, VACUUM_TIMEOUT};
+
+struct ctdb_vacuum_child_context {
+	struct ctdb_vacuum_child_context *next, *prev;
+	struct ctdb_vacuum_handle *vacuum_handle;
+	/* fd child writes status to */
+	int fd[2];
+	pid_t child_pid;
+	enum vacuum_child_status status;
+	struct timeval start_time;
+};
+
+struct ctdb_vacuum_handle {
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_vacuum_child_context *child_ctx;
+	uint32_t fast_path_count;
+};
+
+
+/*  a list of records to possibly delete */
+struct vacuum_data {
+	uint32_t vacuum_limit;
+	uint32_t repack_limit;
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	struct tdb_context *dest_db;
+	trbt_tree_t *delete_tree;
+	uint32_t delete_count;
+	struct ctdb_marshall_buffer **list;
+	struct timeval start;
+	bool traverse_error;
+	bool vacuum;
+	uint32_t total;
+	uint32_t vacuumed;
+	uint32_t copied;
+	uint32_t fast_added_to_vacuum_fetch_list;
+	uint32_t fast_added_to_delete_tree;
+	uint32_t fast_deleted;
+	uint32_t fast_skipped;
+	uint32_t fast_error;
+	uint32_t fast_total;
+	uint32_t full_added_to_vacuum_fetch_list;
+	uint32_t full_added_to_delete_tree;
+	uint32_t full_skipped;
+	uint32_t full_error;
+	uint32_t full_total;
+};
+
+/* tuning information stored for every db */
+struct vacuum_tuning_data {
+	uint32_t last_num_repack;
+	uint32_t last_num_empty;
+	uint32_t last_interval;
+	uint32_t new_interval;
+	struct timeval last_start;
+	double   last_duration;
+};
+
+/* this structure contains the information for one record to be deleted */
+struct delete_record_data {
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_ltdb_header hdr;
+	TDB_DATA key;
+};
+
+struct delete_records_list {
+	struct ctdb_marshall_buffer *records;
+};
+
+/**
+ * Store key and header in a tree, indexed by the key hash.
+ */
+static int insert_delete_record_data_into_tree(struct ctdb_context *ctdb,
+					       struct ctdb_db_context *ctdb_db,
+					       trbt_tree_t *tree,
+					       const struct ctdb_ltdb_header *hdr,
+					       TDB_DATA key)
+{
+	struct delete_record_data *dd;
+	uint32_t hash;
+
+	dd = talloc_zero(tree, struct delete_record_data);
+	if (dd == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		return -1;
+	}
+
+	dd->ctdb      = ctdb;
+	dd->ctdb_db   = ctdb_db;
+	dd->key.dsize = key.dsize;
+	dd->key.dptr  = talloc_memdup(dd, key.dptr, key.dsize);
+	if (dd->key.dptr == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		return -1;
+	}
+
+	dd->hdr = *hdr;
+
+	hash = ctdb_hash(&key);
+
+	trbt_insert32(tree, hash, dd);
+
+	return 0;
+}
+
+static int add_record_to_delete_tree(struct vacuum_data *vdata, TDB_DATA key,
+				     struct ctdb_ltdb_header *hdr)
+{
+	struct ctdb_context *ctdb = vdata->ctdb;
+	struct ctdb_db_context *ctdb_db = vdata->ctdb_db;
+	uint32_t hash;
+	int ret;
+
+	hash = ctdb_hash(&key);
+
+	if (trbt_lookup32(vdata->delete_tree, hash)) {
+		DEBUG(DEBUG_INFO, (__location__ " Hash collission when vacuuming, skipping this record.\n"));
+		return 0;
+	}
+
+	ret = insert_delete_record_data_into_tree(ctdb, ctdb_db,
+						  vdata->delete_tree,
+						  hdr, key);
+	if (ret != 0) {
+		return -1;
+	}
+
+	vdata->delete_count++;
+
+	return 0;
+}
+
+/**
+ * Add a record to the list of records to be sent
+ * to their lmaster with VACUUM_FETCH.
+ */
+static int add_record_to_vacuum_fetch_list(struct vacuum_data *vdata,
+					   TDB_DATA key)
+{
+	struct ctdb_context *ctdb = vdata->ctdb;
+	struct ctdb_rec_data *rec;
+	uint32_t lmaster;
+	size_t old_size;
+
+	lmaster = ctdb_lmaster(ctdb, &key);
+
+	rec = ctdb_marshall_record(vdata->list[lmaster], ctdb->pnn, key, NULL, tdb_null);
+	if (rec == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		vdata->traverse_error = true;
+		return -1;
+	}
+
+	old_size = talloc_get_size(vdata->list[lmaster]);
+	vdata->list[lmaster] = talloc_realloc_size(NULL, vdata->list[lmaster],
+						   old_size + rec->length);
+	if (vdata->list[lmaster] == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to expand\n"));
+		vdata->traverse_error = true;
+		return -1;
+	}
+
+	vdata->list[lmaster]->count++;
+	memcpy(old_size+(uint8_t *)vdata->list[lmaster], rec, rec->length);
+	talloc_free(rec);
+
+	vdata->total++;
+
+	return 0;
+}
+
+
+static void ctdb_vacuum_event(struct event_context *ev, struct timed_event *te, 
+							  struct timeval t, void *private_data);
+
+
+/*
+ * traverse function for gathering the records that can be deleted
+ */
+static int vacuum_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
+{
+	struct vacuum_data *vdata = talloc_get_type(private, struct vacuum_data);
+	struct ctdb_context *ctdb = vdata->ctdb;
+	uint32_t lmaster;
+	struct ctdb_ltdb_header *hdr;
+	int res = 0;
+
+	vdata->full_total++;
+
+	lmaster = ctdb_lmaster(ctdb, &key);
+	if (lmaster >= ctdb->num_nodes) {
+		vdata->full_error++;
+		DEBUG(DEBUG_CRIT, (__location__
+				   " lmaster[%u] >= ctdb->num_nodes[%u] for key"
+				   " with hash[%u]!\n",
+				   (unsigned)lmaster,
+				   (unsigned)ctdb->num_nodes,
+				   (unsigned)ctdb_hash(&key)));
+		return -1;
+	}
+
+	if (data.dsize != sizeof(struct ctdb_ltdb_header)) {
+		/* its not a deleted record */
+		vdata->full_skipped++;
+		return 0;
+	}
+
+	hdr = (struct ctdb_ltdb_header *)data.dptr;
+
+	if (hdr->dmaster != ctdb->pnn) {
+		vdata->full_skipped++;
+		return 0;
+	}
+
+	if (lmaster == ctdb->pnn) {
+		/*
+		 * We are both lmaster and dmaster, and the record * is empty.
+		 * So we should be able to delete it.
+		 */
+		res = add_record_to_delete_tree(vdata, key, hdr);
+		if (res != 0) {
+			vdata->full_error++;
+		} else {
+			vdata->full_added_to_delete_tree++;
+		}
+	} else {
+		/*
+		 * We are not lmaster.
+		 * Add the record to the blob ready to send to the nodes.
+		 */
+		res = add_record_to_vacuum_fetch_list(vdata, key);
+		if (res != 0) {
+			vdata->full_error++;
+		} else {
+			vdata->full_added_to_vacuum_fetch_list++;
+		}
+	}
+
+	return res;
+}
+
+/*
+ * traverse the tree of records to delete and marshall them into
+ * a blob
+ */
+static void delete_traverse(void *param, void *data)
+{
+	struct delete_record_data *dd = talloc_get_type(data, struct delete_record_data);
+	struct delete_records_list *recs = talloc_get_type(param, struct delete_records_list);
+	struct ctdb_rec_data *rec;
+	size_t old_size;
+
+	rec = ctdb_marshall_record(dd, recs->records->db_id, dd->key, &dd->hdr, tdb_null);
+	if (rec == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to marshall record\n"));
+		return;
+	}
+
+	old_size = talloc_get_size(recs->records);
+	recs->records = talloc_realloc_size(NULL, recs->records, old_size + rec->length);
+	if (recs->records == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to expand\n"));
+		return;
+	}
+	recs->records->count++;
+	memcpy(old_size+(uint8_t *)(recs->records), rec, rec->length);
+}
+
+/**
+ * traverse function for the traversal of the delete_queue,
+ * the fast-path vacuuming list.
+ *
+ *  - If the record has been migrated off the node
+ *    or has been revived (filled with data) on the node,
+ *    then skip the record.
+ *
+ *  - If the current node is the record's lmaster and it is
+ *    a record that has never been migrated with data, then
+ *    delete the record from the local tdb.
+ *
+ *  - If the current node is the record's lmaster and it has
+ *    been migrated with data, then schedule it for the normal
+ *    vacuuming procedure (i.e. add it to the delete_list).
+ *
+ *  - If the current node is NOT the record's lmaster then
+ *    add it to the list of records that are to be sent to
+ *    the lmaster with the VACUUM_FETCH message.
+ */
+static void delete_queue_traverse(void *param, void *data)
+{
+	struct delete_record_data *dd =
+		talloc_get_type(data, struct delete_record_data);
+	struct vacuum_data *vdata = talloc_get_type(param, struct vacuum_data);
+	struct ctdb_db_context *ctdb_db = dd->ctdb_db;
+	struct ctdb_context *ctdb = ctdb_db->ctdb; /* or dd->ctdb ??? */
+	int res;
+	struct ctdb_ltdb_header *header;
+	TDB_DATA tdb_data;
+	uint32_t lmaster;
+
+	vdata->fast_total++;
+
+	res = tdb_chainlock(ctdb_db->ltdb->tdb, dd->key);
+	if (res != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Error getting chainlock.\n"));
+		vdata->fast_error++;
+		return;
+	}
+
+	tdb_data = tdb_fetch(ctdb_db->ltdb->tdb, dd->key);
+	if (tdb_data.dsize < sizeof(struct ctdb_ltdb_header)) {
+		/* Does not exist or not a ctdb record. Skip. */
+		goto skipped;
+	}
+
+	if (tdb_data.dsize > sizeof(struct ctdb_ltdb_header)) {
+		/* The record has been recycled (filled with data). Skip. */
+		goto skipped;
+	}
+
+	header = (struct ctdb_ltdb_header *)tdb_data.dptr;
+
+	if (header->dmaster != ctdb->pnn) {
+		/* The record has been migrated off the node. Skip. */
+		goto skipped;
+	}
+
+
+	if (header->rsn != dd->hdr.rsn) {
+		/*
+		 * The record has been migrated off the node and back again.
+		 * But not requeued for deletion. Skip it.
+		 */
+		goto skipped;
+	}
+
+	/*
+	 * We are dmaster, and the record has no data, and it has
+	 * not been migrated after it has been queued for deletion.
+	 *
+	 * At this stage, the record could still have been revived locally
+	 * and last been written with empty data. This can only be
+	 * fixed with the addition of an active or delete flag. (TODO)
+	 */
+
+	lmaster = ctdb_lmaster(ctdb_db->ctdb, &dd->key);
+
+	if (lmaster != ctdb->pnn) {
+		res = add_record_to_vacuum_fetch_list(vdata, dd->key);
+
+		if (res != 0) {
+			DEBUG(DEBUG_ERR,
+			      (__location__ " Error adding record to list "
+			       "of records to send to lmaster.\n"));
+			vdata->fast_error++;
+		} else {
+			vdata->fast_added_to_vacuum_fetch_list++;
+		}
+		goto done;
+	}
+
+	/* use header->flags or dd->hdr.flags ?? */
+	if (dd->hdr.flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
+		res = add_record_to_delete_tree(vdata, dd->key, &dd->hdr);
+
+		if (res != 0) {
+			DEBUG(DEBUG_ERR,
+			      (__location__ " Error adding record to list "
+			       "of records for deletion on lmaster.\n"));
+			vdata->fast_error++;
+		} else {
+			vdata->fast_added_to_delete_tree++;
+		}
+	} else {
+		res = tdb_delete(ctdb_db->ltdb->tdb, dd->key);
+
+		if (res != 0) {
+			DEBUG(DEBUG_ERR,
+			      (__location__ " Error deleting record from local "
+			       "data base.\n"));
+			vdata->fast_error++;
+		} else {
+			vdata->fast_deleted++;
+		}
+	}
+
+	goto done;
+
+skipped:
+	vdata->fast_skipped++;
+
+done:
+	if (tdb_data.dptr != NULL) {
+		free(tdb_data.dptr);
+	}
+	tdb_chainunlock(ctdb_db->ltdb->tdb, dd->key);
+
+	return;
+}
+
+/* 
+ * read-only traverse the database in order to find
+ * records that can be deleted and try to delete these
+ * records on the other nodes
+ * this executes in the child context
+ */
+static int ctdb_vacuum_db(struct ctdb_db_context *ctdb_db,
+			  struct vacuum_data *vdata,
+			  bool full_vacuum_run)
+{
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	const char *name = ctdb_db->db_name;
+	int ret, i, pnn;
+
+	DEBUG(DEBUG_INFO, (__location__ " Entering %s vacuum run for db "
+			   "%s db_id[0x%08x]\n",
+			   full_vacuum_run ? "full" : "fast",
+			   ctdb_db->db_name, ctdb_db->db_id));
+
+	ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &ctdb->vnn_map);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get vnnmap from local node\n"));
+		return ret;
+	}
+
+	pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+	if (pnn == -1) {
+		DEBUG(DEBUG_ERR, ("Unable to get pnn from local node\n"));
+		return -1;
+	}
+
+	ctdb->pnn = pnn;
+
+	vdata->fast_added_to_delete_tree = 0;
+	vdata->fast_added_to_vacuum_fetch_list = 0;
+	vdata->fast_deleted = 0;
+	vdata->fast_skipped = 0;
+	vdata->fast_error = 0;
+	vdata->fast_total = 0;
+	vdata->full_added_to_delete_tree = 0;
+	vdata->full_added_to_vacuum_fetch_list = 0;
+	vdata->full_skipped = 0;
+	vdata->full_error = 0;
+	vdata->full_total = 0;
+
+	/* the list needs to be of length num_nodes */
+	vdata->list = talloc_array(vdata, struct ctdb_marshall_buffer *, ctdb->num_nodes);
+	if (vdata->list == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		return -1;
+	}
+	for (i = 0; i < ctdb->num_nodes; i++) {
+		vdata->list[i] = (struct ctdb_marshall_buffer *)
+			talloc_zero_size(vdata->list, 
+							 offsetof(struct ctdb_marshall_buffer, data));
+		if (vdata->list[i] == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+			return -1;
+		}
+		vdata->list[i]->db_id = ctdb_db->db_id;
+	}
+
+	/*
+	 * Traverse the delete_queue.
+	 * This builds the same lists as the db traverse.
+	 */
+	trbt_traversearray32(ctdb_db->delete_queue, 1, delete_queue_traverse, vdata);
+
+	if (vdata->fast_total > 0) {
+		DEBUG(DEBUG_INFO,
+		      (__location__
+		       " fast vacuuming delete_queue traverse statistics: "
+		       "db[%s] "
+		       "total[%u] "
+		       "del[%u] "
+		       "skp[%u] "
+		       "err[%u] "
+		       "adt[%u] "
+		       "avf[%u]\n",
+		       ctdb_db->db_name,
+		       (unsigned)vdata->fast_total,
+		       (unsigned)vdata->fast_deleted,
+		       (unsigned)vdata->fast_skipped,
+		       (unsigned)vdata->fast_error,
+		       (unsigned)vdata->fast_added_to_delete_tree,
+		       (unsigned)vdata->fast_added_to_vacuum_fetch_list));
+	}
+
+	/*
+	 * read-only traverse of the database, looking for records that
+	 * might be able to be vacuumed.
+	 *
+	 * This is not done each time but only every tunable
+	 * VacuumFastPathCount times.
+	 */
+	if (full_vacuum_run) {
+		ret = tdb_traverse_read(ctdb_db->ltdb->tdb, vacuum_traverse, vdata);
+		if (ret == -1 || vdata->traverse_error) {
+			DEBUG(DEBUG_ERR,(__location__ " Traverse error in vacuuming '%s'\n", name));
+			return -1;
+		}
+		if (vdata->full_total > 0) {
+			DEBUG(DEBUG_INFO,
+			      (__location__
+			       " full vacuuming db traverse statistics: "
+			       "db[%s] "
+			       "total[%u] "
+			       "skp[%u] "
+			       "err[%u] "
+			       "adt[%u] "
+			       "avf[%u]\n",
+			       ctdb_db->db_name,
+			       (unsigned)vdata->full_total,
+			       (unsigned)vdata->full_skipped,
+			       (unsigned)vdata->full_error,
+			       (unsigned)vdata->full_added_to_delete_tree,
+			       (unsigned)vdata->full_added_to_vacuum_fetch_list));
+		}
+	}
+
+	/*
+	 * For records where we are not the lmaster,
+	 * tell the lmaster to fetch the record.
+	 */
+	for (i = 0; i < ctdb->num_nodes; i++) {
+		TDB_DATA data;
+
+		if (ctdb->nodes[i]->pnn == ctdb->pnn) {
+			continue;
+		}
+
+		if (vdata->list[i]->count == 0) {
+			continue;
+		}
+
+		DEBUG(DEBUG_INFO, ("Found %u records for lmaster %u in '%s'\n",
+				   vdata->list[i]->count, ctdb->nodes[i]->pnn,
+				   name));
+
+		data.dsize = talloc_get_size(vdata->list[i]);
+		data.dptr  = (void *)vdata->list[i];
+		if (ctdb_client_send_message(ctdb, ctdb->nodes[i]->pnn, CTDB_SRVID_VACUUM_FETCH, data) != 0) {
+			DEBUG(DEBUG_ERR, (__location__ " Failed to send vacuum "
+					  "fetch message to %u\n",
+					  ctdb->nodes[i]->pnn));
+			return -1;
+		}
+	}	
+
+	/* Process all records we can delete (if any) */
+	if (vdata->delete_count > 0) {
+		struct delete_records_list *recs;
+		TDB_DATA indata, outdata;
+		int32_t res;
+		struct ctdb_node_map *nodemap;
+		uint32_t *active_nodes;
+		int num_active_nodes;
+
+		recs = talloc_zero(vdata, struct delete_records_list);
+		if (recs == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+			return -1;
+		}
+		recs->records = (struct ctdb_marshall_buffer *)
+			talloc_zero_size(vdata, 
+				    offsetof(struct ctdb_marshall_buffer, data));
+		if (recs->records == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+			return -1;
+		}
+		recs->records->db_id = ctdb_db->db_id;
+
+		/* 
+		 * traverse the tree of all records we want to delete and
+		 * create a blob we can send to the other nodes.
+		 */
+		trbt_traversearray32(vdata->delete_tree, 1, delete_traverse, recs);
+
+		indata.dsize = talloc_get_size(recs->records);
+		indata.dptr  = (void *)recs->records;
+
+		/* 
+		 * now tell all the active nodes to delete all these records
+		 * (if possible)
+		 */
+
+		ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(),
+					   CTDB_CURRENT_NODE,
+					   recs, /* talloc context */
+					   &nodemap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " unable to get node map\n"));
+			return -1;
+		}
+
+		active_nodes = list_of_active_nodes(ctdb, nodemap,
+						    nodemap, /* talloc context */
+						    false /* include self */);
+		/* yuck! ;-) */
+		num_active_nodes = talloc_get_size(active_nodes)/sizeof(*active_nodes);
+
+		for (i = 0; i < num_active_nodes; i++) {
+			struct ctdb_marshall_buffer *records;
+			struct ctdb_rec_data *rec;
+
+			ret = ctdb_control(ctdb, active_nodes[i], 0,
+					CTDB_CONTROL_TRY_DELETE_RECORDS, 0,
+					indata, recs, &outdata, &res,
+					NULL, NULL);
+			if (ret != 0 || res != 0) {
+				DEBUG(DEBUG_ERR, ("Failed to delete records on "
+						  "node %u: ret[%d] res[%d]\n",
+						  active_nodes[i], ret, res));
+				return -1;
+			}
+
+			/* 
+			 * outdata countains the list of records coming back
+			 * from the node which the node could not delete
+			 */
+			records = (struct ctdb_marshall_buffer *)outdata.dptr;
+			rec = (struct ctdb_rec_data *)&records->data[0];
+			while (records->count-- > 1) {
+				TDB_DATA reckey, recdata;
+				struct ctdb_ltdb_header *rechdr;
+
+				reckey.dptr = &rec->data[0];
+				reckey.dsize = rec->keylen;
+				recdata.dptr = &rec->data[reckey.dsize];
+				recdata.dsize = rec->datalen;
+
+				if (recdata.dsize < sizeof(struct ctdb_ltdb_header)) {
+					DEBUG(DEBUG_CRIT,(__location__ " bad ltdb record\n"));
+					return -1;
+				}
+				rechdr = (struct ctdb_ltdb_header *)recdata.dptr;
+				recdata.dptr += sizeof(*rechdr);
+				recdata.dsize -= sizeof(*rechdr);
+
+				/* 
+				 * that other node couldnt delete the record
+				 * so we should delete it and thereby remove it from the tree
+				 */
+				talloc_free(trbt_lookup32(vdata->delete_tree, ctdb_hash(&reckey)));
+
+				rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+			}	    
+		}
+
+		/* free nodemap and active_nodes */
+		talloc_free(nodemap);
+
+		/* 
+		 * The only records remaining in the tree would be those
+		 * records where all other nodes could successfully
+		 * delete them, so we can safely delete them on the
+		 * lmaster as well. Deletion implictely happens while
+		 * we repack the database. The repack algorithm revisits 
+		 * the tree in order to find the records that don't need
+		 * to be copied / repacked.
+		 */
+	}
+
+	/* this ensures we run our event queue */
+	ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+
+	return 0;
+}
+
+
+/*
+ * traverse function for repacking
+ */
+static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
+{
+	struct vacuum_data *vdata = (struct vacuum_data *)private;
+
+	if (vdata->vacuum) {
+		uint32_t hash = ctdb_hash(&key);
+		struct delete_record_data *kd;
+		/*
+		 * check if we can ignore this record because it's in the delete_tree
+		 */
+		kd = (struct delete_record_data *)trbt_lookup32(vdata->delete_tree, hash);
+		/*
+		 * there might be hash collisions so we have to compare the keys here to be sure
+		 */
+		if (kd && kd->key.dsize == key.dsize && memcmp(kd->key.dptr, key.dptr, key.dsize) == 0) {
+			struct ctdb_ltdb_header *hdr = (struct ctdb_ltdb_header *)data.dptr;
+			/*
+			 * we have to check if the record hasn't changed in the meantime in order to
+			 * savely remove it from the database
+			 */
+			if (data.dsize == sizeof(struct ctdb_ltdb_header) &&
+				hdr->dmaster == kd->ctdb->pnn &&
+				ctdb_lmaster(kd->ctdb, &(kd->key)) == kd->ctdb->pnn &&
+				kd->hdr.rsn == hdr->rsn) {
+				vdata->vacuumed++;
+				return 0;
+			}
+		}
+	}
+	if (tdb_store(vdata->dest_db, key, data, TDB_INSERT) != 0) {
+		vdata->traverse_error = true;
+		return -1;
+	}
+	vdata->copied++;
+	return 0;
+}
+
+/*
+ * repack a tdb
+ */
+static int ctdb_repack_tdb(struct tdb_context *tdb, TALLOC_CTX *mem_ctx, struct vacuum_data *vdata)
+{
+	struct tdb_context *tmp_db;
+
+	if (tdb_transaction_start(tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n"));
+		return -1;
+	}
+
+	tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb),
+			  TDB_INTERNAL|TDB_DISALLOW_NESTING,
+			  O_RDWR|O_CREAT, 0);
+	if (tmp_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to create tmp_db\n"));
+		tdb_transaction_cancel(tdb);
+		return -1;
+	}
+
+	vdata->traverse_error = false;
+	vdata->dest_db = tmp_db;
+	vdata->vacuum = true;
+	vdata->vacuumed = 0;
+	vdata->copied = 0;
+
+	/*
+	 * repack and vacuum on-the-fly by not writing the records that are
+	 * no longer needed
+	 */
+	if (tdb_traverse_read(tdb, repack_traverse, vdata) == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying out\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;		
+	}
+
+	DEBUG(DEBUG_INFO,(__location__ " %u records vacuumed\n", vdata->vacuumed));
+	
+	if (vdata->traverse_error) {
+		DEBUG(DEBUG_ERR,(__location__ " Error during traversal\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	if (tdb_wipe_all(tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	vdata->traverse_error = false;
+	vdata->dest_db = tdb;
+	vdata->vacuum = false;
+	vdata->copied = 0;
+
+	if (tdb_traverse_read(tmp_db, repack_traverse, vdata) == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying back\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;		
+	}
+
+	if (vdata->traverse_error) {
+		DEBUG(DEBUG_ERR,(__location__ " Error during second traversal\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	tdb_close(tmp_db);
+
+
+	if (tdb_transaction_commit(tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to commit\n"));
+		return -1;
+	}
+	DEBUG(DEBUG_INFO,(__location__ " %u records copied\n", vdata->copied));
+
+	return 0;
+}
+
+static int update_tuning_db(struct ctdb_db_context *ctdb_db, struct vacuum_data *vdata, uint32_t freelist)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	TDB_CONTEXT *tune_tdb;
+	TDB_DATA key, value;
+	struct vacuum_tuning_data tdata;
+	struct vacuum_tuning_data *tptr;
+	char *vac_dbname;
+	int flags;
+
+	vac_dbname = talloc_asprintf(tmp_ctx, "%s/%s.%u",
+				     ctdb_db->ctdb->db_directory_state,
+				     TUNINGDBNAME, ctdb_db->ctdb->pnn);
+	if (vac_dbname == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Out of memory error while allocating '%s'\n", vac_dbname));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	flags  = ctdb_db->ctdb->valgrinding ? TDB_NOMMAP : 0;
+	flags |= TDB_DISALLOW_NESTING;
+	tune_tdb = tdb_open(vac_dbname, 0,
+			    flags,
+			    O_RDWR|O_CREAT, 0600);
+	if (tune_tdb == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to create/open %s\n", TUNINGDBNAME));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	
+	if (tdb_transaction_start(tune_tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n"));
+		tdb_close(tune_tdb);
+		return -1;
+	}
+	key.dptr = discard_const(ctdb_db->db_name);
+	key.dsize = strlen(ctdb_db->db_name);
+	value = tdb_fetch(tune_tdb, key);
+
+	if (value.dptr != NULL && value.dsize == sizeof(struct vacuum_tuning_data)) {
+		tptr = (struct vacuum_tuning_data *)value.dptr;
+		tdata = *tptr;
+
+		/*
+		 * re-calc new vacuum interval:
+		 * in case no limit was reached we continuously increase the interval
+		 * until vacuum_max_interval is reached
+		 * in case a limit was reached we divide the current interval by 2
+		 * unless vacuum_min_interval is reached
+		 */
+		if (freelist < vdata->repack_limit &&
+		    vdata->delete_count < vdata->vacuum_limit) {
+			if (tdata.last_interval < ctdb_db->ctdb->tunable.vacuum_max_interval) {
+				tdata.new_interval = tdata.last_interval * 110 / 100;
+				DEBUG(DEBUG_INFO,("Increasing vacuum interval %u -> %u for %s\n", 
+					tdata.last_interval, tdata.new_interval, ctdb_db->db_name));
+			}
+		} else {
+			tdata.new_interval = tdata.last_interval / 2;
+			if (tdata.new_interval < ctdb_db->ctdb->tunable.vacuum_min_interval ||
+				tdata.new_interval > ctdb_db->ctdb->tunable.vacuum_max_interval) {
+				tdata.new_interval = ctdb_db->ctdb->tunable.vacuum_min_interval;
+			}		
+			DEBUG(DEBUG_INFO,("Decreasing vacuum interval %u -> %u for %s\n", 
+					 tdata.last_interval, tdata.new_interval, ctdb_db->db_name));
+		}
+		tdata.last_interval = tdata.new_interval;
+	} else {
+		DEBUG(DEBUG_DEBUG,(__location__ " Cannot find tunedb record for %s. Using default interval\n", ctdb_db->db_name));
+		tdata.last_num_repack = freelist;
+		tdata.last_num_empty = vdata->delete_count;
+		tdata.last_interval = ctdb_db->ctdb->tunable.vacuum_default_interval;
+	}
+
+	if (value.dptr != NULL) {
+		free(value.dptr);
+	}
+
+	tdata.last_start = vdata->start;
+	tdata.last_duration = timeval_elapsed(&vdata->start);
+
+	value.dptr = (unsigned char *)&tdata;
+	value.dsize = sizeof(tdata);
+
+	if (tdb_store(tune_tdb, key, value, 0) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Unable to store tundb record for %s\n", ctdb_db->db_name));
+		tdb_transaction_cancel(tune_tdb);
+		tdb_close(tune_tdb);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	tdb_transaction_commit(tune_tdb);
+	tdb_close(tune_tdb);
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+/*
+ * repack and vaccum a db
+ * called from the child context
+ */
+static int ctdb_vacuum_and_repack_db(struct ctdb_db_context *ctdb_db,
+				     TALLOC_CTX *mem_ctx,
+				     bool full_vacuum_run)
+{
+	uint32_t repack_limit = ctdb_db->ctdb->tunable.repack_limit;
+	uint32_t vacuum_limit = ctdb_db->ctdb->tunable.vacuum_limit;
+	const char *name = ctdb_db->db_name;
+	int size;
+	struct vacuum_data *vdata;
+
+	size = tdb_freelist_size(ctdb_db->ltdb->tdb);
+	if (size == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get freelist size for '%s'\n", name));
+		return -1;
+	}
+
+	vdata = talloc_zero(mem_ctx, struct vacuum_data);
+	if (vdata == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		return -1;
+	}
+
+	vdata->ctdb = ctdb_db->ctdb;
+	vdata->vacuum_limit = vacuum_limit;
+	vdata->repack_limit = repack_limit;
+	vdata->delete_tree = trbt_create(vdata, 0);
+	vdata->ctdb_db = ctdb_db;
+	if (vdata->delete_tree == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		talloc_free(vdata);
+		return -1;
+	}
+
+	vdata->start = timeval_current();
+ 
+	/*
+	 * gather all records that can be deleted in vdata
+	 */
+	if (ctdb_vacuum_db(ctdb_db, vdata, full_vacuum_run) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to vacuum '%s'\n", name));
+	}
+
+	/*
+	 * decide if a repack is necessary
+	 */
+	if (size < repack_limit && vdata->delete_count < vacuum_limit) {
+		update_tuning_db(ctdb_db, vdata, size);
+		talloc_free(vdata);
+		return 0;
+	}
+
+	DEBUG(DEBUG_INFO,("Repacking %s with %u freelist entries and %u records to delete\n", 
+			name, size, vdata->delete_count));
+
+	/*
+	 * repack and implicitely get rid of the records we can delete
+	 */
+	if (ctdb_repack_tdb(ctdb_db->ltdb->tdb, mem_ctx, vdata) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to repack '%s'\n", name));
+		update_tuning_db(ctdb_db, vdata, size);
+		talloc_free(vdata);
+		return -1;
+	}
+	update_tuning_db(ctdb_db, vdata, size);
+	talloc_free(vdata);
+
+	return 0;
+}
+
+static int get_vacuum_interval(struct ctdb_db_context *ctdb_db)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	TDB_CONTEXT *tdb;
+	TDB_DATA key, value;
+	char *vac_dbname;
+	uint interval = ctdb_db->ctdb->tunable.vacuum_default_interval;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	int flags;
+
+	vac_dbname = talloc_asprintf(tmp_ctx, "%s/%s.%u", ctdb->db_directory, TUNINGDBNAME, ctdb->pnn);
+	if (vac_dbname == NULL) {
+		DEBUG(DEBUG_CRIT,(__location__ " Out of memory error while allocating '%s'\n", vac_dbname));
+		talloc_free(tmp_ctx);
+		return interval;
+	}
+
+	flags  = ctdb_db->ctdb->valgrinding ? TDB_NOMMAP : 0;
+	flags |= TDB_DISALLOW_NESTING;
+	tdb = tdb_open(vac_dbname, 0,
+		       flags,
+		       O_RDWR|O_CREAT, 0600);
+	if (!tdb) {
+		DEBUG(DEBUG_ERR,("Unable to open/create database %s using default interval. Errno : %s (%d)\n", vac_dbname, strerror(errno), errno));
+		talloc_free(tmp_ctx);
+		return interval;
+	}
+
+	key.dptr = discard_const(ctdb_db->db_name);
+	key.dsize = strlen(ctdb_db->db_name);
+
+	value = tdb_fetch(tdb, key);
+
+	if (value.dptr != NULL) {
+		if (value.dsize == sizeof(struct vacuum_tuning_data)) {
+			struct vacuum_tuning_data *tptr = (struct vacuum_tuning_data *)value.dptr;
+
+			interval = tptr->new_interval;
+
+			if (interval < ctdb->tunable.vacuum_min_interval) {
+				interval = ctdb->tunable.vacuum_min_interval;
+			} 
+			if (interval > ctdb->tunable.vacuum_max_interval) {
+				interval = ctdb->tunable.vacuum_max_interval;
+			}
+		}
+		free(value.dptr);
+	}
+	tdb_close(tdb);
+
+	talloc_free(tmp_ctx);
+
+	return interval;
+}
+
+static int vacuum_child_destructor(struct ctdb_vacuum_child_context *child_ctx)
+{
+	double l = timeval_elapsed(&child_ctx->start_time);
+	struct ctdb_db_context *ctdb_db = child_ctx->vacuum_handle->ctdb_db;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+
+	DEBUG(DEBUG_INFO,("Vacuuming took %.3f seconds for database %s\n", l, ctdb_db->db_name));
+
+	if (child_ctx->child_pid != -1) {
+		kill(child_ctx->child_pid, SIGKILL);
+	} else {
+		/* Bump the number of successful fast-path runs. */
+		child_ctx->vacuum_handle->fast_path_count++;
+	}
+
+	DLIST_REMOVE(ctdb->vacuumers, child_ctx);
+
+	event_add_timed(ctdb->ev, child_ctx->vacuum_handle,
+			timeval_current_ofs(get_vacuum_interval(ctdb_db), 0), 
+			ctdb_vacuum_event, child_ctx->vacuum_handle);
+
+	return 0;
+}
+
+/*
+ * this event is generated when a vacuum child process times out
+ */
+static void vacuum_child_timeout(struct event_context *ev, struct timed_event *te,
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_vacuum_child_context *child_ctx = talloc_get_type(private_data, struct ctdb_vacuum_child_context);
+
+	DEBUG(DEBUG_ERR,("Vacuuming child process timed out for db %s\n", child_ctx->vacuum_handle->ctdb_db->db_name));
+
+	child_ctx->status = VACUUM_TIMEOUT;
+
+	talloc_free(child_ctx);
+}
+
+
+/*
+ * this event is generated when a vacuum child process has completed
+ */
+static void vacuum_child_handler(struct event_context *ev, struct fd_event *fde,
+			     uint16_t flags, void *private_data)
+{
+	struct ctdb_vacuum_child_context *child_ctx = talloc_get_type(private_data, struct ctdb_vacuum_child_context);
+	char c = 0;
+	int ret;
+
+	DEBUG(DEBUG_INFO,("Vacuuming child process %d finished for db %s\n", child_ctx->child_pid, child_ctx->vacuum_handle->ctdb_db->db_name));
+	child_ctx->child_pid = -1;
+
+	ret = read(child_ctx->fd[0], &c, 1);
+	if (ret != 1 || c != 0) {
+		child_ctx->status = VACUUM_ERROR;
+		DEBUG(DEBUG_ERR, ("A vacuum child process failed with an error for database %s. ret=%d c=%d\n", child_ctx->vacuum_handle->ctdb_db->db_name, ret, c));
+	} else {
+		child_ctx->status = VACUUM_OK;
+	}
+
+	talloc_free(child_ctx);
+}
+
+/*
+ * this event is called every time we need to start a new vacuum process
+ */
+static void
+ctdb_vacuum_event(struct event_context *ev, struct timed_event *te,
+			       struct timeval t, void *private_data)
+{
+	struct ctdb_vacuum_handle *vacuum_handle = talloc_get_type(private_data, struct ctdb_vacuum_handle);
+	struct ctdb_db_context *ctdb_db = vacuum_handle->ctdb_db;
+	struct ctdb_context *ctdb = ctdb_db->ctdb;
+	struct ctdb_vacuum_child_context *child_ctx;
+	struct tevent_fd *fde;
+	int ret;
+
+	/* we dont vacuum if we are in recovery mode, or db frozen */
+	if (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE ||
+	    ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_NONE) {
+		DEBUG(DEBUG_INFO, ("Not vacuuming %s (%s)\n", ctdb_db->db_name,
+				   ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE ? "in recovery"
+				   : ctdb->freeze_mode[ctdb_db->priority] == CTDB_FREEZE_PENDING
+				   ? "freeze pending"
+				   : "frozen"));
+		event_add_timed(ctdb->ev, vacuum_handle, timeval_current_ofs(ctdb->tunable.vacuum_default_interval, 0), ctdb_vacuum_event, vacuum_handle);
+		return;
+	}
+
+	child_ctx = talloc(vacuum_handle, struct ctdb_vacuum_child_context);
+	if (child_ctx == NULL) {
+		DEBUG(DEBUG_CRIT, (__location__ " Failed to allocate child context for vacuuming of %s\n", ctdb_db->db_name));
+		ctdb_fatal(ctdb, "Out of memory when crating vacuum child context. Shutting down\n");
+	}
+
+
+	ret = pipe(child_ctx->fd);
+	if (ret != 0) {
+		talloc_free(child_ctx);
+		DEBUG(DEBUG_ERR, ("Failed to create pipe for vacuum child process.\n"));
+		event_add_timed(ctdb->ev, vacuum_handle, timeval_current_ofs(ctdb->tunable.vacuum_default_interval, 0), ctdb_vacuum_event, vacuum_handle);
+		return;
+	}
+
+	if (vacuum_handle->fast_path_count > ctdb->tunable.vacuum_fast_path_count) {
+		vacuum_handle->fast_path_count = 0;
+	}
+
+	child_ctx->child_pid = ctdb_fork(ctdb);
+	if (child_ctx->child_pid == (pid_t)-1) {
+		close(child_ctx->fd[0]);
+		close(child_ctx->fd[1]);
+		talloc_free(child_ctx);
+		DEBUG(DEBUG_ERR, ("Failed to fork vacuum child process.\n"));
+		event_add_timed(ctdb->ev, vacuum_handle, timeval_current_ofs(ctdb->tunable.vacuum_default_interval, 0), ctdb_vacuum_event, vacuum_handle);
+		return;
+	}
+
+
+	if (child_ctx->child_pid == 0) {
+		char cc = 0;
+		bool full_vacuum_run = false;
+		close(child_ctx->fd[0]);
+
+		DEBUG(DEBUG_INFO,("Vacuuming child process %d for db %s started\n", getpid(), ctdb_db->db_name));
+	
+		if (switch_from_server_to_client(ctdb, "vacuum-%s", ctdb_db->db_name) != 0) {
+			DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch vacuum daemon into client mode. Shutting down.\n"));
+			_exit(1);
+		}
+
+		/* 
+		 * repack the db
+		 */
+		if ((ctdb->tunable.vacuum_fast_path_count > 0) &&
+		    (vacuum_handle->fast_path_count == 0))
+		{
+			full_vacuum_run = true;
+		}
+		cc = ctdb_vacuum_and_repack_db(ctdb_db, child_ctx,
+					       full_vacuum_run);
+
+		write(child_ctx->fd[1], &cc, 1);
+		_exit(0);
+	}
+
+	set_close_on_exec(child_ctx->fd[0]);
+	close(child_ctx->fd[1]);
+
+	child_ctx->status = VACUUM_RUNNING;
+	child_ctx->start_time = timeval_current();
+
+	DLIST_ADD(ctdb->vacuumers, child_ctx);
+	talloc_set_destructor(child_ctx, vacuum_child_destructor);
+
+	/*
+	 * Clear the fastpath vacuuming list in the parent.
+	 */
+	talloc_free(ctdb_db->delete_queue);
+	ctdb_db->delete_queue = trbt_create(ctdb_db, 0);
+	if (ctdb_db->delete_queue == NULL) {
+		/* fatal here? ... */
+		ctdb_fatal(ctdb, "Out of memory when re-creating vacuum tree "
+				 "in parent context. Shutting down\n");
+	}
+
+	event_add_timed(ctdb->ev, child_ctx,
+		timeval_current_ofs(ctdb->tunable.vacuum_max_run_time, 0),
+		vacuum_child_timeout, child_ctx);
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to child vacuum process\n", child_ctx->fd[0]));
+
+	fde = event_add_fd(ctdb->ev, child_ctx, child_ctx->fd[0],
+			   EVENT_FD_READ, vacuum_child_handler, child_ctx);
+	tevent_fd_set_auto_close(fde);
+
+	vacuum_handle->child_ctx = child_ctx;
+	child_ctx->vacuum_handle = vacuum_handle;
+}
+
+void ctdb_stop_vacuuming(struct ctdb_context *ctdb)
+{
+	/* Simply free them all. */
+	while (ctdb->vacuumers) {
+		DEBUG(DEBUG_INFO, ("Aborting vacuuming for %s (%i)\n",
+			   ctdb->vacuumers->vacuum_handle->ctdb_db->db_name,
+			   (int)ctdb->vacuumers->child_pid));
+		/* vacuum_child_destructor kills it, removes from list */
+		talloc_free(ctdb->vacuumers);
+	}
+}
+
+/* this function initializes the vacuuming context for a database
+ * starts the vacuuming events
+ */
+int ctdb_vacuum_init(struct ctdb_db_context *ctdb_db)
+{
+	if (ctdb_db->persistent != 0) {
+		DEBUG(DEBUG_ERR,("Vacuuming is disabled for persistent database %s\n", ctdb_db->db_name));
+		return 0;
+	}
+
+	ctdb_db->vacuum_handle = talloc(ctdb_db, struct ctdb_vacuum_handle);
+	CTDB_NO_MEMORY(ctdb_db->ctdb, ctdb_db->vacuum_handle);
+
+	ctdb_db->vacuum_handle->ctdb_db         = ctdb_db;
+	ctdb_db->vacuum_handle->fast_path_count = 0;
+
+	event_add_timed(ctdb_db->ctdb->ev, ctdb_db->vacuum_handle, 
+			timeval_current_ofs(get_vacuum_interval(ctdb_db), 0), 
+			ctdb_vacuum_event, ctdb_db->vacuum_handle);
+
+	return 0;
+}
+
+/**
+ * Insert a record into the ctdb_db context's delete queue,
+ * handling hash collisions.
+ */
+static int insert_record_into_delete_queue(struct ctdb_db_context *ctdb_db,
+					   const struct ctdb_ltdb_header *hdr,
+					   TDB_DATA key)
+{
+	struct delete_record_data *kd;
+	uint32_t hash;
+	int ret;
+
+	hash = (uint32_t)ctdb_hash(&key);
+
+	DEBUG(DEBUG_INFO, (__location__ " Schedule for deletion: db[%s] "
+			   "db_id[0x%08x] "
+			   "key_hash[0x%08x] "
+			   "lmaster[%u] "
+			   "migrated_with_data[%s]\n",
+			    ctdb_db->db_name, ctdb_db->db_id,
+			    hash,
+			    ctdb_lmaster(ctdb_db->ctdb, &key),
+			    hdr->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA ? "yes" : "no"));
+
+	kd = (struct delete_record_data *)trbt_lookup32(ctdb_db->delete_queue, hash);
+	if (kd != NULL) {
+		if ((kd->key.dsize != key.dsize) ||
+		    (memcmp(kd->key.dptr, key.dptr, key.dsize) != 0))
+		{
+			DEBUG(DEBUG_INFO,
+			      ("schedule for deletion: Hash collision (0x%08x)."
+			       " Skipping the record.\n", hash));
+			return 0;
+		} else {
+			DEBUG(DEBUG_DEBUG,
+			      ("schedule for deletion: Overwriting entry for "
+			       "key with hash 0x%08x.\n", hash));
+		}
+	}
+
+	ret = insert_delete_record_data_into_tree(ctdb_db->ctdb, ctdb_db,
+						  ctdb_db->delete_queue,
+						  hdr, key);
+	if (ret != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Schedule a record for deletetion.
+ * Called from the parent context.
+ */
+int32_t ctdb_control_schedule_for_deletion(struct ctdb_context *ctdb,
+					   TDB_DATA indata)
+{
+	struct ctdb_control_schedule_for_deletion *dd;
+	struct ctdb_db_context *ctdb_db;
+	int ret;
+	TDB_DATA key;
+
+	dd = (struct ctdb_control_schedule_for_deletion *)indata.dptr;
+
+	ctdb_db = find_ctdb_db(ctdb, dd->db_id);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Unknown db id 0x%08x\n",
+				  dd->db_id));
+		return -1;
+	}
+
+	key.dsize = dd->keylen;
+	key.dptr = dd->key;
+
+	ret = insert_record_into_delete_queue(ctdb_db, &dd->hdr, key);
+
+	return ret;
+}
+
+int32_t ctdb_local_schedule_for_deletion(struct ctdb_db_context *ctdb_db,
+					 const struct ctdb_ltdb_header *hdr,
+					 TDB_DATA key)
+{
+	int ret;
+	struct ctdb_control_schedule_for_deletion *dd;
+	TDB_DATA indata;
+	int32_t status;
+
+	if (ctdb_db->ctdb->ctdbd_pid == getpid()) {
+		/* main daemon - directly queue */
+		ret = insert_record_into_delete_queue(ctdb_db, hdr, key);
+
+		return ret;
+	}
+
+	/* child process: send the main daemon a control */
+
+	indata.dsize = offsetof(struct ctdb_control_schedule_for_deletion, key) + key.dsize;
+	indata.dptr = talloc_zero_array(ctdb_db, uint8_t, indata.dsize);
+	if (indata.dptr == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+		return -1;
+	}
+	dd = (struct ctdb_control_schedule_for_deletion *)(void *)indata.dptr;
+	dd->db_id = ctdb_db->db_id;
+	dd->hdr = *hdr;
+	dd->keylen = key.dsize;
+	memcpy(dd->key, key.dptr, key.dsize);
+
+	ret = ctdb_control(ctdb_db->ctdb,
+			   CTDB_CURRENT_NODE,
+			   ctdb_db->db_id,
+			   CTDB_CONTROL_SCHEDULE_FOR_DELETION,
+			   CTDB_CTRL_FLAG_NOREPLY, /* flags */
+			   indata,
+			   NULL, /* mem_ctx */
+			   NULL, /* outdata */
+			   &status,
+			   NULL, /* timeout : NULL == wait forever */
+			   NULL); /* error message */
+
+	talloc_free(indata.dptr);
+
+	if (ret != 0 || status != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Error sending "
+				  "SCHEDULE_FOR_DELETION "
+				  "control.\n"));
+		if (status != 0) {
+			ret = -1;
+		}
+	}
+
+	return ret;
+}

Added: branches/ctdb/squeeze-backports/server/ctdbd.c
===================================================================
--- branches/ctdb/squeeze-backports/server/ctdbd.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/ctdbd.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,340 @@
+/* 
+   standalone ctdb daemon
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/network.h"
+#include "cmdline.h"
+#include "../include/ctdb_private.h"
+
+static struct {
+	const char *nlist;
+	const char *transport;
+	const char *myaddress;
+	const char *public_address_list;
+	const char *event_script_dir;
+	const char *notification_script;
+	const char *logfile;
+	const char *recovery_lock_file;
+	const char *db_dir;
+	const char *db_dir_persistent;
+	const char *db_dir_state;
+	const char *public_interface;
+	const char *single_public_ip;
+	const char *node_ip;
+	int         valgrinding;
+	int         nosetsched;
+	int         use_syslog;
+	int         start_as_disabled;
+	int         start_as_stopped;
+	int         no_lmaster;
+	int         no_recmaster;
+	int         lvs;
+	int	    script_log_level;
+	int         no_publicipcheck;
+	int         max_persistent_check_errors;
+} options = {
+	.nlist = ETCDIR "/ctdb/nodes",
+	.transport = "tcp",
+	.event_script_dir = ETCDIR "/ctdb/events.d",
+	.logfile = LOGDIR "/log.ctdb",
+	.db_dir = VARDIR "/ctdb",
+	.db_dir_persistent = VARDIR "/ctdb/persistent",
+	.db_dir_state = VARDIR "/ctdb/state",
+	.script_log_level = DEBUG_ERR,
+};
+
+int script_log_level;
+bool fast_start;
+
+/*
+  called by the transport layer when a packet comes in
+*/
+static void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length)
+{
+	struct ctdb_req_header *hdr = (struct ctdb_req_header *)data;
+
+	CTDB_INCREMENT_STAT(ctdb, node_packets_recv);
+
+	/* up the counter for this source node, so we know its alive */
+	if (ctdb_validate_pnn(ctdb, hdr->srcnode)) {
+		/* as a special case, redirected calls don't increment the rx_cnt */
+		if (hdr->operation != CTDB_REQ_CALL ||
+		    ((struct ctdb_req_call *)hdr)->hopcount == 0) {
+			ctdb->nodes[hdr->srcnode]->rx_cnt++;
+		}
+	}
+
+	ctdb_input_pkt(ctdb, hdr);
+}
+
+void ctdb_load_nodes_file(struct ctdb_context *ctdb)
+{
+	int ret;
+
+	ret = ctdb_set_nlist(ctdb, options.nlist);
+	if (ret == -1) {
+		DEBUG(DEBUG_ALERT,("ctdb_set_nlist failed - %s\n", ctdb_errstr(ctdb)));
+		exit(1);
+	}
+}
+
+static const struct ctdb_upcalls ctdb_upcalls = {
+	.recv_pkt       = ctdb_recv_pkt,
+	.node_dead      = ctdb_node_dead,
+	.node_connected = ctdb_node_connected
+};
+
+
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	int interactive = 0;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "interactive", 'i', POPT_ARG_NONE, &interactive, 0, "don't fork", NULL },
+		{ "public-addresses", 0, POPT_ARG_STRING, &options.public_address_list, 0, "public address list file", "filename" },
+		{ "public-interface", 0, POPT_ARG_STRING, &options.public_interface, 0, "public interface", "interface"},
+		{ "single-public-ip", 0, POPT_ARG_STRING, &options.single_public_ip, 0, "single public ip", "ip-address"},
+		{ "event-script-dir", 0, POPT_ARG_STRING, &options.event_script_dir, 0, "event script directory", "dirname" },
+		{ "logfile", 0, POPT_ARG_STRING, &options.logfile, 0, "log file location", "filename" },
+		{ "nlist", 0, POPT_ARG_STRING, &options.nlist, 0, "node list file", "filename" },
+		{ "node-ip", 0, POPT_ARG_STRING, &options.node_ip, 0, "node ip", "ip-address"},
+		{ "notification-script", 0, POPT_ARG_STRING, &options.notification_script, 0, "notification script", "filename" },
+		{ "listen", 0, POPT_ARG_STRING, &options.myaddress, 0, "address to listen on", "address" },
+		{ "transport", 0, POPT_ARG_STRING, &options.transport, 0, "protocol transport", NULL },
+		{ "dbdir", 0, POPT_ARG_STRING, &options.db_dir, 0, "directory for the tdb files", NULL },
+		{ "dbdir-persistent", 0, POPT_ARG_STRING, &options.db_dir_persistent, 0, "directory for persistent tdb files", NULL },
+		{ "dbdir-state", 0, POPT_ARG_STRING, &options.db_dir_state, 0, "directory for internal state tdb files", NULL },
+		{ "reclock", 0, POPT_ARG_STRING, &options.recovery_lock_file, 0, "location of recovery lock file", "filename" },
+		{ "valgrinding", 0, POPT_ARG_NONE, &options.valgrinding, 0, "disable setscheduler SCHED_FIFO call, use mmap for tdbs", NULL },
+		{ "nosetsched", 0, POPT_ARG_NONE, &options.nosetsched, 0, "disable setscheduler SCHED_FIFO call, use mmap for tdbs", NULL },
+		{ "syslog", 0, POPT_ARG_NONE, &options.use_syslog, 0, "log messages to syslog", NULL },
+		{ "start-as-disabled", 0, POPT_ARG_NONE, &options.start_as_disabled, 0, "Node starts in disabled state", NULL },
+		{ "start-as-stopped", 0, POPT_ARG_NONE, &options.start_as_stopped, 0, "Node starts in stopped state", NULL },
+		{ "no-lmaster", 0, POPT_ARG_NONE, &options.no_lmaster, 0, "disable lmaster role on this node", NULL },
+		{ "no-recmaster", 0, POPT_ARG_NONE, &options.no_recmaster, 0, "disable recmaster role on this node", NULL },
+		{ "lvs", 0, POPT_ARG_NONE, &options.lvs, 0, "lvs is enabled on this node", NULL },
+		{ "script-log-level", 0, POPT_ARG_INT, &options.script_log_level, DEBUG_ERR, "log level of event script output", NULL },
+		{ "nopublicipcheck", 0, POPT_ARG_NONE, &options.no_publicipcheck, 0, "don't check we have/don't have the correct public ip addresses", NULL },
+		{ "max-persistent-check-errors", 0, POPT_ARG_INT,
+		  &options.max_persistent_check_errors, 0,
+		  "max allowed persistent check errors (default 0)", NULL },
+		{ "log-ringbuf-size", 0, POPT_ARG_INT, &log_ringbuf_size, DEBUG_ERR, "Number of log messages we can store in the memory ringbuffer", NULL },
+		{ "sloppy-start", 0, POPT_ARG_NONE, &fast_start, 0, "Do not perform full recovery on start", NULL },
+		POPT_TABLEEND
+	};
+	int opt, ret;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	talloc_enable_null_tracking();
+
+	ctdb_block_signal(SIGPIPE);
+	fault_setup("ctdbd");
+
+	ev = event_context_init(NULL);
+	tevent_loop_allow_nesting(ev);
+
+	ctdb = ctdb_cmdline_init(ev);
+
+	ctdb->start_as_disabled = options.start_as_disabled;
+	ctdb->start_as_stopped  = options.start_as_stopped;
+
+	script_log_level = options.script_log_level;
+
+	ret = ctdb_set_logfile(ctdb, options.logfile, options.use_syslog);
+	if (ret == -1) {
+		printf("ctdb_set_logfile to %s failed - %s\n", 
+		       options.use_syslog?"syslog":options.logfile, ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	DEBUG(DEBUG_NOTICE,("CTDB starting on node\n"));
+
+	gettimeofday(&ctdb->ctdbd_start_time, NULL);
+	gettimeofday(&ctdb->last_recovery_started, NULL);
+	gettimeofday(&ctdb->last_recovery_finished, NULL);
+	ctdb->recovery_mode    = CTDB_RECOVERY_NORMAL;
+	ctdb->recovery_master  = (uint32_t)-1;
+	ctdb->upcalls          = &ctdb_upcalls;
+	ctdb->idr              = idr_init(ctdb);
+	ctdb->recovery_lock_fd = -1;
+
+	ctdb_tunables_set_defaults(ctdb);
+
+	ctdb->tunable.disable_ip_failover = options.no_publicipcheck;
+
+	ret = ctdb_set_recovery_lock_file(ctdb, options.recovery_lock_file);
+	if (ret == -1) {
+		DEBUG(DEBUG_ALERT,("ctdb_set_recovery_lock_file failed - %s\n", ctdb_errstr(ctdb)));
+		exit(1);
+	}
+
+	ret = ctdb_set_transport(ctdb, options.transport);
+	if (ret == -1) {
+		DEBUG(DEBUG_ALERT,("ctdb_set_transport failed - %s\n", ctdb_errstr(ctdb)));
+		exit(1);
+	}
+
+	/* tell ctdb what address to listen on */
+	if (options.myaddress) {
+		ret = ctdb_set_address(ctdb, options.myaddress);
+		if (ret == -1) {
+			DEBUG(DEBUG_ALERT,("ctdb_set_address failed - %s\n", ctdb_errstr(ctdb)));
+			exit(1);
+		}
+	}
+
+	/* set ctdbd capabilities */
+	ctdb->capabilities = 0;
+	if (options.no_lmaster == 0) {
+		ctdb->capabilities |= CTDB_CAP_LMASTER;
+	}
+	if (options.no_recmaster == 0) {
+		ctdb->capabilities |= CTDB_CAP_RECMASTER;
+	}
+	if (options.lvs != 0) {
+		ctdb->capabilities |= CTDB_CAP_LVS;
+	}
+
+	/* tell ctdb what nodes are available */
+	ctdb_load_nodes_file(ctdb);
+
+	/* if a node-ip was specified, verify that it exists in the
+	   nodes file
+	*/
+	if (options.node_ip != NULL) {
+		DEBUG(DEBUG_NOTICE,("IP for this node is %s\n", options.node_ip));
+		ret = ctdb_ip_to_nodeid(ctdb, options.node_ip);
+		if (ret == -1) {
+			DEBUG(DEBUG_ALERT,("The specified node-ip:%s is not a valid node address. Exiting.\n", options.node_ip));
+			exit(1);
+		}
+		ctdb->node_ip = options.node_ip;
+		DEBUG(DEBUG_NOTICE,("This is node %d\n", ret));
+	}
+
+	if (options.db_dir) {
+		ret = ctdb_set_tdb_dir(ctdb, options.db_dir);
+		if (ret == -1) {
+			DEBUG(DEBUG_ALERT,("ctdb_set_tdb_dir failed - %s\n", ctdb_errstr(ctdb)));
+			exit(1);
+		}
+	}
+	if (options.db_dir_persistent) {
+		ret = ctdb_set_tdb_dir_persistent(ctdb, options.db_dir_persistent);
+		if (ret == -1) {
+			DEBUG(DEBUG_ALERT,("ctdb_set_tdb_dir_persistent failed - %s\n", ctdb_errstr(ctdb)));
+			exit(1);
+		}
+	}
+	if (options.db_dir_state) {
+		ret = ctdb_set_tdb_dir_state(ctdb, options.db_dir_state);
+		if (ret == -1) {
+			DEBUG(DEBUG_ALERT,("ctdb_set_tdb_dir_state failed - %s\n", ctdb_errstr(ctdb)));
+			exit(1);
+		}
+	}
+
+	if (options.public_interface) {
+		ctdb->default_public_interface = talloc_strdup(ctdb, options.public_interface);
+		CTDB_NO_MEMORY(ctdb, ctdb->default_public_interface);
+	}
+
+	if (options.single_public_ip) {
+		if (options.public_interface == NULL) {
+			DEBUG(DEBUG_ALERT,("--single_public_ip used but --public_interface is not specified. You must specify the public interface when using single public ip. Exiting\n"));
+			exit(10);
+		}
+
+		ret = ctdb_set_single_public_ip(ctdb, options.public_interface,
+						options.single_public_ip);
+		if (ret != 0) {
+			DEBUG(DEBUG_ALERT,("Invalid --single-public-ip argument : %s . This is not a valid ip address. Exiting.\n", options.single_public_ip));
+			exit(10);
+		}
+	}
+
+	ret = ctdb_set_event_script_dir(ctdb, options.event_script_dir);
+	if (ret == -1) {
+		DEBUG(DEBUG_ALERT,("Unable to setup event script directory\n"));
+		exit(1);
+	}
+
+	if (options.notification_script != NULL) {
+		ret = ctdb_set_notification_script(ctdb, options.notification_script);
+		if (ret == -1) {
+			DEBUG(DEBUG_ALERT,("Unable to setup notification script\n"));
+			exit(1);
+		}
+	}
+
+	ctdb->valgrinding = options.valgrinding;
+	if (options.valgrinding || options.nosetsched) {
+		ctdb->do_setsched = 0;
+	} else {
+		ctdb->do_setsched = 1;
+	}
+
+	if (options.max_persistent_check_errors < 0) {
+		ctdb->max_persistent_check_errors = 0xFFFFFFFFFFFFFFFFLL;
+	} else {
+		ctdb->max_persistent_check_errors = (uint64_t)options.max_persistent_check_errors;
+	}
+
+	if (getenv("CTDB_BASE") == NULL) {
+		/* setup a environment variable for the event scripts to use
+		   to find the installation directory */
+		setenv("CTDB_BASE", ETCDIR "/ctdb", 1);
+	}
+
+	/* start the protocol running (as a child) */
+	return ctdb_start_daemon(ctdb, interactive?False:True, options.use_syslog, options.public_address_list);
+}

Added: branches/ctdb/squeeze-backports/server/eventscript.c
===================================================================
--- branches/ctdb/squeeze-backports/server/eventscript.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/server/eventscript.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1084 @@
+/* 
+   event script handling
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <time.h>
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "system/dir.h"
+#include "system/locale.h"
+#include "../include/ctdb_private.h"
+#include "lib/tevent/tevent.h"
+#include "../common/rb_tree.h"
+
+static void ctdb_event_script_timeout(struct event_context *ev, struct timed_event *te, struct timeval t, void *p);
+
+/*
+  ctdbd sends us a SIGTERM when we should die.
+ */
+static void sigterm(int sig)
+{
+	/* all the child processes will be running in the same process group */
+	kill(-getpgrp(), SIGKILL);
+	_exit(1);
+}
+
+/* This is attached to the event script state. */
+struct event_script_callback {
+	struct ctdb_event_script_state *state;
+
+	/* Warning: this can free us! */
+	void (*fn)(struct ctdb_context *, int, void *);
+	void *private_data;
+};
+	
+
+struct ctdb_event_script_state {
+	struct ctdb_context *ctdb;
+	struct event_script_callback *callback;
+	pid_t child;
+	int fd[2];
+	bool from_user;
+	enum ctdb_eventscript_call call;
+	const char *options;
+	struct timeval timeout;
+
+	unsigned int current;
+	struct ctdb_scripts_wire *scripts;
+};
+
+static struct ctdb_script_wire *get_current_script(struct ctdb_event_script_state *state)
+{
+	return &state->scripts->scripts[state->current];
+}
+
+/* called from ctdb_logging when we have received output on STDERR from
+ * one of the eventscripts
+ */
+static void log_event_script_output(const char *str, uint16_t len, void *p)
+{
+	struct ctdb_event_script_state *state
+		= talloc_get_type(p, struct ctdb_event_script_state);
+	struct ctdb_script_wire *current;
+	unsigned int slen, min;
+
+	/* We may have been aborted to run something else.  Discard */
+	if (state->scripts == NULL) {
+		return;
+	}
+
+	current = get_current_script(state);
+
+	/* Append, but don't overfill buffer.  It starts zero-filled. */
+	slen = strlen(current->output);
+	min = MIN(len, sizeof(current->output) - slen - 1);
+
+	memcpy(current->output + slen, str, min);
+}
+
+int32_t ctdb_control_get_event_script_status(struct ctdb_context *ctdb,
+					     uint32_t call_type,
+					     TDB_DATA *outdata)
+{
+	if (call_type >= CTDB_EVENT_MAX) {
+		return -1;
+	}
+
+	if (ctdb->last_status[call_type] == NULL) {
+		/* If it's never been run, return nothing so they can tell. */
+		outdata->dsize = 0;
+	} else {
+		outdata->dsize = talloc_get_size(ctdb->last_status[call_type]);
+		outdata->dptr  = (uint8_t *)ctdb->last_status[call_type];
+	}
+	return 0;
+}
+
+struct ctdb_script_tree_item {
+	const char *name;
+	int error;
+};
+
+/* Return true if OK, otherwise set errno. */
+static bool check_executable(const char *dir, const char *name)
+{
+	char *full;
+	struct stat st;
+
+	full = talloc_asprintf(NULL, "%s/%s", dir, name);
+	if (!full)
+		return false;
+
+	if (stat(full, &st) != 0) {
+		DEBUG(DEBUG_ERR,("Could not stat event script %s: %s\n",
+				 full, strerror(errno)));
+		talloc_free(full);
+		return false;
+	}
+
+	if (!(st.st_mode & S_IXUSR)) {
+		DEBUG(DEBUG_DEBUG,("Event script %s is not executable. Ignoring this event script\n", full));
+		errno = ENOEXEC;
+		talloc_free(full);
+		return false;
+	}
+
+	talloc_free(full);
+	return true;
+}
+
+static struct ctdb_scripts_wire *ctdb_get_script_list(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx)
+{
+	DIR *dir;
+	struct dirent *de;
+	struct stat st;
+	trbt_tree_t *tree;
+	struct ctdb_scripts_wire *scripts;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_script_tree_item *tree_item;
+	int count;
+
+	/*
+	  the service specific event scripts 
+	*/
+	if (stat(ctdb->event_script_dir, &st) != 0 && 
+	    errno == ENOENT) {
+		DEBUG(DEBUG_CRIT,("No event script directory found at '%s'\n", ctdb->event_script_dir));
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	/* create a tree to store all the script names in */
+	tree = trbt_create(tmp_ctx, 0);
+
+	/* scan all directory entries and insert all valid scripts into the 
+	   tree
+	*/
+	dir = opendir(ctdb->event_script_dir);
+	if (dir == NULL) {
+		DEBUG(DEBUG_CRIT,("Failed to open event script directory '%s'\n", ctdb->event_script_dir));
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	count = 0;
+	while ((de=readdir(dir)) != NULL) {
+		int namlen;
+		unsigned num;
+
+		namlen = strlen(de->d_name);
+
+		if (namlen < 3) {
+			continue;
+		}
+
+		if (de->d_name[namlen-1] == '~') {
+			/* skip files emacs left behind */
+			continue;
+		}
+
+		if (de->d_name[2] != '.') {
+			continue;
+		}
+
+		if (sscanf(de->d_name, "%02u.", &num) != 1) {
+			continue;
+		}
+
+		if (strlen(de->d_name) > MAX_SCRIPT_NAME) {
+			DEBUG(DEBUG_ERR,("Script name %s too long! %u chars max",
+					 de->d_name, MAX_SCRIPT_NAME));
+			continue;
+		}
+
+		tree_item = talloc(tree, struct ctdb_script_tree_item);
+		if (tree_item == NULL) {
+			DEBUG(DEBUG_ERR, (__location__ " Failed to allocate new tree item\n"));
+			talloc_free(tmp_ctx);
+			return NULL;
+		}
+	
+		tree_item->error = 0;
+		if (!check_executable(ctdb->event_script_dir, de->d_name)) {
+			tree_item->error = errno;
+		}
+
+		tree_item->name = talloc_strdup(tree_item, de->d_name);
+		if (tree_item->name == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to allocate script name.\n"));
+			talloc_free(tmp_ctx);
+			return NULL;
+		}
+
+		/* store the event script in the tree */
+		trbt_insert32(tree, (num<<16)|count++, tree_item);
+	}
+	closedir(dir);
+
+	/* Overallocates by one, but that's OK */
+	scripts = talloc_zero_size(tmp_ctx,
+				   sizeof(*scripts)
+				   + sizeof(scripts->scripts[0]) * count);
+	if (scripts == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to allocate scripts\n"));
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+	scripts->num_scripts = count;
+
+	for (count = 0; count < scripts->num_scripts; count++) {
+		tree_item = trbt_findfirstarray32(tree, 1);
+
+		strcpy(scripts->scripts[count].name, tree_item->name);
+		scripts->scripts[count].status = -tree_item->error;
+
+		/* remove this script from the tree */
+		talloc_free(tree_item);
+	}
+
+	talloc_steal(mem_ctx, scripts);
+	talloc_free(tmp_ctx);
+	return scripts;
+}
+
+static int child_setup(struct ctdb_context *ctdb)
+{
+	if (setpgid(0,0) != 0) {
+		int ret = -errno;
+		DEBUG(DEBUG_ERR,("Failed to create process group for event scripts - %s\n",
+			 strerror(errno)));
+		return ret;
+	}
+
+	signal(SIGTERM, sigterm);
+	return 0;
+}
+
+static char *child_command_string(struct ctdb_context *ctdb,
+				       TALLOC_CTX *ctx,
+				       bool from_user,
+				       const char *scriptname,
+				       enum ctdb_eventscript_call call,
+				       const char *options)
+{
+	const char *str = from_user ? "CTDB_CALLED_BY_USER=1 " : "";
+
+	/* Allow a setting where we run the actual monitor event
+	   from an external source and replace it with
+	   a "status" event that just picks up the actual
+	   status of the event asynchronously.
+	*/
+	if ((ctdb->tunable.use_status_events_for_monitoring != 0)
+	    &&  (call == CTDB_EVENT_MONITOR)
+	    &&  !from_user) {
+		return talloc_asprintf(ctx, "%s%s/%s %s",
+				       str,
+				       ctdb->event_script_dir,
+				       scriptname, "status");
+	} else {
+		return talloc_asprintf(ctx, "%s%s/%s %s %s",
+				       str,
+				       ctdb->event_script_dir,
+				       scriptname,
+				       ctdb_eventscript_call_names[call],
+				       options);
+	}
+}
+
+static int child_run_one(struct ctdb_context *ctdb,
+			 const char *scriptname, const char *cmdstr)
+{
+	int ret;
+
+	ret = system(cmdstr);
+	/* if the system() call was successful, translate ret into the
+	   return code from the command
+	*/
+	if (ret != -1) {
+		ret = WEXITSTATUS(ret);
+	} else {
+		ret = -errno;
+	}
+
+	/* 127 could mean it does not exist, 126 non-executable. */
+	if (ret == 127 || ret == 126) {
+		/* Re-check it... */
+		if (!check_executable(ctdb->event_script_dir, scriptname)) {
+			DEBUG(DEBUG_ERR,("Script %s returned status %u. Someone just deleted it?\n",
+					 cmdstr, ret));
+			ret = -errno;
+		}
+	}
+	return ret;
+}
+
+/*
+  Actually run one event script
+  this function is called and run in the context of a forked child
+  which allows it to do blocking calls such as system()
+ */
+static int child_run_script(struct ctdb_context *ctdb,
+			    bool from_user,
+			    enum ctdb_eventscript_call call,
+			    const char *options,
+			    struct ctdb_script_wire *current)
+{
+	char *cmdstr;
+	int ret;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+	ret = child_setup(ctdb);
+	if (ret != 0)
+		goto out;
+
+	cmdstr = child_command_string(ctdb, tmp_ctx, from_user,
+				      current->name, call, options);
+	CTDB_NO_MEMORY(ctdb, cmdstr);
+
+	DEBUG(DEBUG_DEBUG,("Executing event script %s\n",cmdstr));
+
+	if (current->status) {
+		ret = current->status;
+		goto out;
+	}
+
+	ret = child_run_one(ctdb, current->name, cmdstr);
+out:
+	talloc_free(tmp_ctx);
+	return ret;
+}
+
+static void ctdb_event_script_handler(struct event_context *ev, struct fd_event *fde,
+				      uint16_t flags, void *p);
+
+static int fork_child_for_script(struct ctdb_context *ctdb,
+				 struct ctdb_event_script_state *state)
+{
+	int r;
+	struct tevent_fd *fde;
+	struct ctdb_script_wire *current = get_current_script(state);
+
+	current->start = timeval_current();
+
+	r = pipe(state->fd);
+	if (r != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " pipe failed for child eventscript process\n"));
+		return -errno;
+	}
+
+ 	if (!ctdb_fork_with_logging(state, ctdb, current->name, log_event_script_output,
+				    state, &state->child)) {
+		r = -errno;
+		close(state->fd[0]);
+		close(state->fd[1]);
+		return r;
+	}
+
+	/* If we are the child, do the work. */
+	if (state->child == 0) {
+		int rt;
+
+		debug_extra = talloc_asprintf(NULL, "eventscript-%s-%s:",
+					      current->name,
+					      ctdb_eventscript_call_names[state->call]);
+		close(state->fd[0]);
+		set_close_on_exec(state->fd[1]);
+
+		rt = child_run_script(ctdb, state->from_user, state->call, state->options, current);
+		/* We must be able to write PIPEBUF bytes at least; if this
+		   somehow fails, the read above will be short. */
+		write(state->fd[1], &rt, sizeof(rt));
+		close(state->fd[1]);
+		_exit(rt);
+	}
+
+	close(state->fd[1]);
+	set_close_on_exec(state->fd[0]);
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created PIPE FD:%d to child eventscript process\n", state->fd[0]));
+
+	/* Set ourselves up to be called when that's done. */
+	fde = event_add_fd(ctdb->ev, state, state->fd[0], EVENT_FD_READ,
+			   ctdb_event_script_handler, state);
+	tevent_fd_set_auto_close(fde);
+
+	return 0;
+}
+
+/*
+ Summarize status of this run of scripts.
+ */
+static int script_status(struct ctdb_scripts_wire *scripts)
+{
+	unsigned int i;
+
+	for (i = 0; i < scripts->num_scripts; i++) {
+		switch (scripts->scripts[i].status) {
+		case -ENOENT:
+		case -ENOEXEC:
+			/* Disabled or missing; that's OK. */
+			break;
+		case 0:
+			/* No problem. */
+			break;
+		default:
+			return scripts->scripts[i].status;
+		}
+	}
+
+	/* All OK! */
+	return 0;
+}
+
+/* called when child is finished */
+static void ctdb_event_script_handler(struct event_context *ev, struct fd_event *fde, 
+				      uint16_t flags, void *p)
+{
+	struct ctdb_event_script_state *state = 
+		talloc_get_type(p, struct ctdb_event_script_state);
+	struct ctdb_script_wire *current = get_current_script(state);
+	struct ctdb_context *ctdb = state->ctdb;
+	int r, status;
+
+	if (ctdb == NULL) {
+		DEBUG(DEBUG_ERR,("Eventscript finished but ctdb is NULL\n"));
+		return;
+	}
+
+	r = read(state->fd[0], &current->status, sizeof(current->status));
+	if (r < 0) {
+		current->status = -errno;
+	} else if (r != sizeof(current->status)) {
+		current->status = -EIO;
+	}
+
+	current->finished = timeval_current();
+	/* valgrind gets overloaded if we run next script as it's still doing
+	 * post-execution analysis, so kill finished child here. */
+	if (ctdb->valgrinding) {
+		kill(state->child, SIGKILL);
+	}
+
+	state->child = 0;
+
+	status = script_status(state->scripts);
+
+	/* Aborted or finished all scripts?  We're done. */
+	if (status != 0 || state->current+1 == state->scripts->num_scripts) {
+		DEBUG(DEBUG_INFO,(__location__ " Eventscript %s %s finished with state %d\n",
+				  ctdb_eventscript_call_names[state->call], state->options, status));
+
+		ctdb->event_script_timeouts = 0;
+		talloc_free(state);
+		return;
+	}
+
+	/* Forget about that old fd. */
+	talloc_free(fde);
+
+	/* Next script! */
+	state->current++;
+	current++;
+	current->status = fork_child_for_script(ctdb, state);
+	if (current->status != 0) {
+		/* This calls the callback. */
+		talloc_free(state);
+	}
+}
+
+static void debug_timeout(struct ctdb_event_script_state *state)
+{
+	struct ctdb_script_wire *current = get_current_script(state);
+	char *cmd;
+	pid_t pid;
+	time_t t;
+	char tbuf[100], buf[200];
+
+	cmd = child_command_string(state->ctdb, state,
+				   state->from_user, current->name,
+				   state->call, state->options);
+	CTDB_NO_MEMORY_VOID(state->ctdb, cmd);
+
+	DEBUG(DEBUG_ERR,("Timed out running script '%s' after %.1f seconds pid :%d\n",
+			 cmd, timeval_elapsed(&current->start), state->child));
+	talloc_free(cmd);
+
+	t = time(NULL);
+	strftime(tbuf, sizeof(tbuf)-1, "%Y%m%d%H%M%S", 	localtime(&t));
+	sprintf(buf, "{ pstree -p; cat /proc/locks; ls -li /var/ctdb/ /var/ctdb/persistent; }"
+			" >/tmp/ctdb.event.%s.%d", tbuf, getpid());
+
+	pid = ctdb_fork(state->ctdb);
+	if (pid == 0) {
+		system(buf);
+		/* Now we can kill the child */
+		kill(state->child, SIGTERM);
+		exit(0);
+	}
+	if (pid == -1) {
+		DEBUG(DEBUG_ERR,("Fork for debug script failed : %s\n",
+				 strerror(errno)));
+	} else {
+		DEBUG(DEBUG_ERR,("Logged timedout eventscript : %s\n", buf));
+		/* Don't kill child until timeout done. */
+		state->child = 0;
+	}
+}
+
+/* called when child times out */
+static void ctdb_event_script_timeout(struct event_context *ev, struct timed_event *te, 
+				      struct timeval t, void *p)
+{
+	struct ctdb_event_script_state *state = talloc_get_type(p, struct ctdb_event_script_state);
+	struct ctdb_context *ctdb = state->ctdb;
+	struct ctdb_script_wire *current = get_current_script(state);
+
+	DEBUG(DEBUG_ERR,("Event script timed out : %s %s %s count : %u  pid : %d\n",
+			 current->name, ctdb_eventscript_call_names[state->call], state->options, ctdb->event_script_timeouts, state->child));
+
+	/* ignore timeouts for these events */
+	switch (state->call) {
+	case CTDB_EVENT_START_RECOVERY:
+	case CTDB_EVENT_RECOVERED:
+	case CTDB_EVENT_TAKE_IP:
+	case CTDB_EVENT_RELEASE_IP:
+	case CTDB_EVENT_STOPPED:
+	case CTDB_EVENT_MONITOR:
+	case CTDB_EVENT_STATUS:
+		state->scripts->scripts[state->current].status = 0;
+		DEBUG(DEBUG_ERR,("Ignoring hung script for %s call %d\n", state->options, state->call));
+		break;
+        default:
+		state->scripts->scripts[state->current].status = -ETIME;
+		debug_timeout(state);
+	}
+
+	talloc_free(state);
+}
+
+/*
+  destroy an event script: kill it if ->child != 0.
+ */
+static int event_script_destructor(struct ctdb_event_script_state *state)
+{
+	int status;
+	struct event_script_callback *callback;
+
+	if (state->child) {
+		DEBUG(DEBUG_ERR,(__location__ " Sending SIGTERM to child pid:%d\n", state->child));
+
+		if (kill(state->child, SIGTERM) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to kill child process for eventscript, errno %s(%d)\n", strerror(errno), errno));
+		}
+	}
+
+	/* If we were the current monitor, we no longer are. */
+	if (state->ctdb->current_monitor == state) {
+		state->ctdb->current_monitor = NULL;
+	}
+
+	/* Save our scripts as the last executed status, if we have them.
+	 * See ctdb_event_script_callback_v where we abort monitor event. */
+	if (state->scripts) {
+		talloc_free(state->ctdb->last_status[state->call]);
+		state->ctdb->last_status[state->call] = state->scripts;
+		if (state->current < state->ctdb->last_status[state->call]->num_scripts) {
+			state->ctdb->last_status[state->call]->num_scripts = state->current+1;
+		}
+	}
+
+	/* Use last status as result, or "OK" if none. */
+	if (state->ctdb->last_status[state->call]) {
+		status = script_status(state->ctdb->last_status[state->call]);
+	} else {
+		status = 0;
+	}
+
+	/* This is allowed to free us; talloc will prevent double free anyway,
+	 * but beware if you call this outside the destructor! */
+	callback = state->callback;
+
+	if (callback) {
+		/* Make sure destructor doesn't free itself! */
+		talloc_steal(NULL, callback);
+		callback->fn(state->ctdb, status, callback->private_data);
+		talloc_free(callback);
+	}
+
+	return 0;
+}
+
+static unsigned int count_words(const char *options)
+{
+	unsigned int words = 0;
+
+	options += strspn(options, " \t");
+	while (*options) {
+		words++;
+		options += strcspn(options, " \t");
+		options += strspn(options, " \t");
+	}
+	return words;
+}
+
+static bool check_options(enum ctdb_eventscript_call call, const char *options)
+{
+	switch (call) {
+	/* These all take no arguments. */
+	case CTDB_EVENT_INIT:
+	case CTDB_EVENT_SETUP:
+	case CTDB_EVENT_STARTUP:
+	case CTDB_EVENT_START_RECOVERY:
+	case CTDB_EVENT_RECOVERED:
+	case CTDB_EVENT_STOPPED:
+	case CTDB_EVENT_MONITOR:
+	case CTDB_EVENT_STATUS:
+	case CTDB_EVENT_SHUTDOWN:
+	case CTDB_EVENT_RELOAD:
+	case CTDB_EVENT_IPREALLOCATED:
+		return count_words(options) == 0;
+
+	case CTDB_EVENT_TAKE_IP: /* interface, IP address, netmask bits. */
+	case CTDB_EVENT_RELEASE_IP:
+		return count_words(options) == 3;
+
+	case CTDB_EVENT_UPDATE_IP: /* old interface, new interface, IP address, netmask bits. */
+		return count_words(options) == 4;
+
+	default:
+		DEBUG(DEBUG_ERR,(__location__ "Unknown ctdb_eventscript_call %u\n", call));
+		return false;
+	}
+}
+
+static int remove_callback(struct event_script_callback *callback)
+{
+	/* Detach ourselves from the running script state */
+	callback->state->callback = NULL;
+	return 0;
+}
+
+/*
+  run the event script in the background, calling the callback when 
+  finished
+ */
+static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
+					const void *mem_ctx,
+					void (*callback)(struct ctdb_context *, int, void *),
+					void *private_data,
+					bool from_user,
+					enum ctdb_eventscript_call call,
+					const char *fmt, va_list ap)
+{
+	struct ctdb_event_script_state *state;
+
+	state = talloc(ctdb->event_script_ctx, struct ctdb_event_script_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	/* The callback isn't done if the context is freed. */
+	state->callback = talloc(mem_ctx, struct event_script_callback);
+	CTDB_NO_MEMORY(ctdb, state->callback);
+	talloc_set_destructor(state->callback, remove_callback);
+	state->callback->state = state;
+	state->callback->fn = callback;
+	state->callback->private_data = private_data;
+
+	state->ctdb = ctdb;
+	state->from_user = from_user;
+	state->call = call;
+	state->options = talloc_vasprintf(state, fmt, ap);
+	state->timeout = timeval_set(ctdb->tunable.script_timeout, 0);
+	state->scripts = NULL;
+	if (state->options == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " could not allocate state->options\n"));
+		talloc_free(state);
+		return -1;
+	}
+	if (!check_options(state->call, state->options)) {
+		DEBUG(DEBUG_ERR, ("Bad eventscript options '%s' for %s\n",
+				  ctdb_eventscript_call_names[state->call], state->options));
+		talloc_free(state);
+		return -1;
+	}
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		/* we guarantee that only some specifically allowed event scripts are run
+		   while in recovery */
+		const enum ctdb_eventscript_call allowed_calls[] = {
+			CTDB_EVENT_INIT,
+			CTDB_EVENT_SETUP,
+			CTDB_EVENT_START_RECOVERY,
+			CTDB_EVENT_SHUTDOWN,
+			CTDB_EVENT_RELEASE_IP,
+			CTDB_EVENT_STOPPED
+		};
+		int i;
+		for (i=0;i<ARRAY_SIZE(allowed_calls);i++) {
+			if (call == allowed_calls[i]) break;
+		}
+		if (i == ARRAY_SIZE(allowed_calls)) {
+			DEBUG(DEBUG_ERR,("Refusing to run event scripts call '%s' while in recovery\n",
+				 ctdb_eventscript_call_names[call]));
+			talloc_free(state);
+			return -1;
+		}
+	}
+
+	/* Kill off any running monitor events to run this event. */
+	if (ctdb->current_monitor) {
+		/* Discard script status so we don't save to last_status */
+		talloc_free(ctdb->current_monitor->scripts);
+		ctdb->current_monitor->scripts = NULL;
+		talloc_free(ctdb->current_monitor);
+		ctdb->current_monitor = NULL;
+	}
+
+	DEBUG(DEBUG_INFO,(__location__ " Starting eventscript %s %s\n",
+			  ctdb_eventscript_call_names[state->call],
+			  state->options));
+
+	/* This is not a child of state, since we save it in destructor. */
+	state->scripts = ctdb_get_script_list(ctdb, ctdb);
+	if (state->scripts == NULL) {
+		talloc_free(state);
+		return -1;
+	}
+	state->current = 0;
+	state->child = 0;
+
+	if (!from_user && (call == CTDB_EVENT_MONITOR || call == CTDB_EVENT_STATUS)) {
+		ctdb->current_monitor = state;
+	}
+
+	talloc_set_destructor(state, event_script_destructor);
+
+	/* Nothing to do? */
+	if (state->scripts->num_scripts == 0) {
+		talloc_free(state);
+		return 0;
+	}
+
+ 	state->scripts->scripts[0].status = fork_child_for_script(ctdb, state);
+ 	if (state->scripts->scripts[0].status != 0) {
+ 		/* Callback is called from destructor, with fail result. */
+ 		talloc_free(state);
+ 		return 0;
+ 	}
+
+	if (!timeval_is_zero(&state->timeout)) {
+		event_add_timed(ctdb->ev, state, timeval_current_ofs(state->timeout.tv_sec, state->timeout.tv_usec), ctdb_event_script_timeout, state);
+	} else {
+		DEBUG(DEBUG_ERR, (__location__ " eventscript %s %s called with no timeout\n",
+				  ctdb_eventscript_call_names[state->call],
+				  state->options));
+	}
+
+	return 0;
+}
+
+
+/*
+  run the event script in the background, calling the callback when 
+  finished.  If mem_ctx is freed, callback will never be called.
+ */
+int ctdb_event_script_callback(struct ctdb_context *ctdb, 
+			       TALLOC_CTX *mem_ctx,
+			       void (*callback)(struct ctdb_context *, int, void *),
+			       void *private_data,
+			       bool from_user,
+			       enum ctdb_eventscript_call call,
+			       const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, fmt);
+	ret = ctdb_event_script_callback_v(ctdb, mem_ctx, callback, private_data, from_user, call, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+
+struct callback_status {
+	bool done;
+	int status;
+};
+
+/*
+  called when ctdb_event_script() finishes
+ */
+static void event_script_callback(struct ctdb_context *ctdb, int status, void *private_data)
+{
+	struct callback_status *s = (struct callback_status *)private_data;
+	s->done = true;
+	s->status = status;
+}
+
+/*
+  run the event script, waiting for it to complete. Used when the caller
+  doesn't want to continue till the event script has finished.
+ */
+int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_eventscript_call call,
+			   const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+	struct callback_status status;
+
+	va_start(ap, fmt);
+	ret = ctdb_event_script_callback_v(ctdb, ctdb,
+			event_script_callback, &status, false, call, fmt, ap);
+	if (ret != 0) {
+		return ret;
+	}
+	va_end(ap);
+
+	status.status = -1;
+	status.done = false;
+
+	while (status.done == false && event_loop_once(ctdb->ev) == 0) /* noop */;
+
+	if (status.status == -ETIME) {
+		DEBUG(DEBUG_ERR, (__location__ " eventscript for '%s' timedout."
+				  " Immediately banning ourself for %d seconds\n",
+				  ctdb_eventscript_call_names[call],
+				  ctdb->tunable.recovery_ban_period));
+		ctdb_ban_self(ctdb);
+	}
+
+	return status.status;
+}
+
+int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_eventscript_call call)
+{
+	/* GCC complains about empty format string, so use %s and "". */
+	return ctdb_event_script_args(ctdb, call, "%s", "");
+}
+
+struct eventscript_callback_state {
+	struct ctdb_req_control *c;
+};
+
+/*
+  called when a forced eventscript run has finished
+ */
+static void run_eventscripts_callback(struct ctdb_context *ctdb, int status, 
+				 void *private_data)
+{
+	struct eventscript_callback_state *state = 
+		talloc_get_type(private_data, struct eventscript_callback_state);
+
+	ctdb_enable_monitoring(ctdb);
+
+	if (status != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to forcibly run eventscripts\n"));
+	}
+
+	ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
+	/* This will free the struct ctdb_event_script_state we are in! */
+	talloc_free(state);
+	return;
+}
+
+
+/* Returns rest of string, or NULL if no match. */
+static const char *get_call(const char *p, enum ctdb_eventscript_call *call)
+{
+	unsigned int len;
+
+	/* Skip any initial whitespace. */
+	p += strspn(p, " \t");
+
+	/* See if we match any. */
+	for (*call = 0; *call < CTDB_EVENT_MAX; (*call)++) {
+		len = strlen(ctdb_eventscript_call_names[*call]);
+		if (strncmp(p, ctdb_eventscript_call_names[*call], len) == 0) {
+			/* If end of string or whitespace, we're done. */
+			if (strcspn(p + len, " \t") == 0) {
+				return p + len;
+			}
+		}
+	}
+	return NULL;
+}
+
+/*
+  A control to force running of the eventscripts from the ctdb client tool
+*/
+int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb,
+		struct ctdb_req_control *c,
+		TDB_DATA indata, bool *async_reply)
+{
+	int ret;
+	struct eventscript_callback_state *state;
+	const char *options;
+	enum ctdb_eventscript_call call;
+
+	/* Figure out what call they want. */
+	options = get_call((const char *)indata.dptr, &call);
+	if (!options) {
+		DEBUG(DEBUG_ERR, (__location__ " Invalid forced \"%s\"\n", (const char *)indata.dptr));
+		return -1;
+	}
+
+	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
+		DEBUG(DEBUG_ERR, (__location__ " Aborted running eventscript \"%s\" while in RECOVERY mode\n", indata.dptr));
+		return -1;
+	}
+
+	state = talloc(ctdb->event_script_ctx, struct eventscript_callback_state);
+	CTDB_NO_MEMORY(ctdb, state);
+
+	state->c = talloc_steal(state, c);
+
+	DEBUG(DEBUG_NOTICE,("Forced running of eventscripts with arguments %s\n", indata.dptr));
+
+	ctdb_disable_monitoring(ctdb);
+
+	ret = ctdb_event_script_callback(ctdb, 
+			 state, run_eventscripts_callback, state,
+			 true, call, "%s", options);
+
+	if (ret != 0) {
+		ctdb_enable_monitoring(ctdb);
+		DEBUG(DEBUG_ERR,(__location__ " Failed to run eventscripts with arguments %s\n", indata.dptr));
+		talloc_free(state);
+		return -1;
+	}
+
+	/* tell ctdb_control.c that we will be replying asynchronously */
+	*async_reply = true;
+
+	return 0;
+}
+
+
+
+int32_t ctdb_control_enable_script(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	const char *script;
+	struct stat st;
+	char *filename;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+	script = (char *)indata.dptr;
+	if (indata.dsize == 0) {
+		DEBUG(DEBUG_ERR,(__location__ " No script specified.\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	if (indata.dptr[indata.dsize - 1] != '\0') {
+		DEBUG(DEBUG_ERR,(__location__ " String is not null terminated.\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	if (index(script,'/') != NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Script name contains '/'. Failed to enable script %s\n", script));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	if (stat(ctdb->event_script_dir, &st) != 0 && 
+	    errno == ENOENT) {
+		DEBUG(DEBUG_CRIT,("No event script directory found at '%s'\n", ctdb->event_script_dir));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	filename = talloc_asprintf(tmp_ctx, "%s/%s", ctdb->event_script_dir, script);
+	if (filename == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to create script path\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (stat(filename, &st) != 0) {
+		DEBUG(DEBUG_ERR,("Could not stat event script %s. Failed to enable script.\n", filename));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (chmod(filename, st.st_mode | S_IXUSR) == -1) {
+		DEBUG(DEBUG_ERR,("Could not chmod %s. Failed to enable script.\n", filename));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+int32_t ctdb_control_disable_script(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+	const char *script;
+	struct stat st;
+	char *filename;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+	script = (char *)indata.dptr;
+	if (indata.dsize == 0) {
+		DEBUG(DEBUG_ERR,(__location__ " No script specified.\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	if (indata.dptr[indata.dsize - 1] != '\0') {
+		DEBUG(DEBUG_ERR,(__location__ " String is not null terminated.\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	if (index(script,'/') != NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Script name contains '/'. Failed to disable script %s\n", script));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	if (stat(ctdb->event_script_dir, &st) != 0 && 
+	    errno == ENOENT) {
+		DEBUG(DEBUG_CRIT,("No event script directory found at '%s'\n", ctdb->event_script_dir));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	filename = talloc_asprintf(tmp_ctx, "%s/%s", ctdb->event_script_dir, script);
+	if (filename == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to create script path\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (stat(filename, &st) != 0) {
+		DEBUG(DEBUG_ERR,("Could not stat event script %s. Failed to disable script.\n", filename));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (chmod(filename, st.st_mode & ~(S_IXUSR|S_IXGRP|S_IXOTH)) == -1) {
+		DEBUG(DEBUG_ERR,("Could not chmod %s. Failed to disable script.\n", filename));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tcp/ctdb_tcp.h
===================================================================
--- branches/ctdb/squeeze-backports/tcp/ctdb_tcp.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tcp/ctdb_tcp.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,56 @@
+/* 
+   ctdb database library
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/* ctdb_tcp main state */
+struct ctdb_tcp {
+	struct ctdb_context *ctdb;
+	int listen_fd;
+};
+
+/*
+  state associated with an incoming connection
+*/
+struct ctdb_incoming {
+	struct ctdb_context *ctdb;
+	int fd;
+	struct ctdb_queue *queue;
+};
+
+/*
+  state associated with one tcp node
+*/
+struct ctdb_tcp_node {
+	int fd;
+	struct ctdb_queue *out_queue;
+	struct fd_event *connect_fde;
+	struct timed_event *connect_te;
+};
+
+
+/* prototypes internal to tcp transport */
+int ctdb_tcp_queue_pkt(struct ctdb_node *node, uint8_t *data, uint32_t length);
+int ctdb_tcp_listen(struct ctdb_context *ctdb);
+void ctdb_tcp_node_connect(struct event_context *ev, struct timed_event *te, 
+			   struct timeval t, void *private_data);
+void ctdb_tcp_read_cb(uint8_t *data, size_t cnt, void *args);
+void ctdb_tcp_tnode_cb(uint8_t *data, size_t cnt, void *private_data);
+void ctdb_tcp_stop_connection(struct ctdb_node *node);
+
+#define CTDB_TCP_ALIGNMENT 8

Added: branches/ctdb/squeeze-backports/tcp/tcp_connect.c
===================================================================
--- branches/ctdb/squeeze-backports/tcp/tcp_connect.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tcp/tcp_connect.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,488 @@
+/* 
+   ctdb over TCP
+
+   Copyright (C) Andrew Tridgell  2006
+   Copyright (C) Ronnie Sahlberg  2008
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "../include/ctdb_private.h"
+#include "ctdb_tcp.h"
+
+/*
+  stop any connecting (established or pending) to a node
+ */
+void ctdb_tcp_stop_connection(struct ctdb_node *node)
+{
+	struct ctdb_tcp_node *tnode = talloc_get_type(
+		node->private_data, struct ctdb_tcp_node);
+	
+	ctdb_queue_set_fd(tnode->out_queue, -1);
+	talloc_free(tnode->connect_te);
+	talloc_free(tnode->connect_fde);
+	tnode->connect_fde = NULL;
+	tnode->connect_te = NULL;
+	if (tnode->fd != -1) {
+		close(tnode->fd);
+		tnode->fd = -1;
+	}
+}
+
+
+/*
+  called when a complete packet has come in - should not happen on this socket
+  unless the other side closes the connection with RST or FIN
+ */
+void ctdb_tcp_tnode_cb(uint8_t *data, size_t cnt, void *private_data)
+{
+	struct ctdb_node *node = talloc_get_type(private_data, struct ctdb_node);
+	struct ctdb_tcp_node *tnode = talloc_get_type(
+		node->private_data, struct ctdb_tcp_node);
+
+	if (data == NULL) {
+		node->ctdb->upcalls->node_dead(node);
+	}
+
+	ctdb_tcp_stop_connection(node);
+	tnode->connect_te = event_add_timed(node->ctdb->ev, tnode,
+					    timeval_current_ofs(3, 0),
+					    ctdb_tcp_node_connect, node);
+}
+
+/*
+  called when socket becomes writeable on connect
+*/
+static void ctdb_node_connect_write(struct event_context *ev, struct fd_event *fde, 
+				    uint16_t flags, void *private_data)
+{
+	struct ctdb_node *node = talloc_get_type(private_data,
+						 struct ctdb_node);
+	struct ctdb_tcp_node *tnode = talloc_get_type(node->private_data,
+						      struct ctdb_tcp_node);
+	struct ctdb_context *ctdb = node->ctdb;
+	int error = 0;
+	socklen_t len = sizeof(error);
+	int one = 1;
+
+	talloc_free(tnode->connect_te);
+	tnode->connect_te = NULL;
+
+	if (getsockopt(tnode->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0 ||
+	    error != 0) {
+		ctdb_tcp_stop_connection(node);
+		tnode->connect_te = event_add_timed(ctdb->ev, tnode, 
+						    timeval_current_ofs(1, 0),
+						    ctdb_tcp_node_connect, node);
+		return;
+	}
+
+	talloc_free(tnode->connect_fde);
+	tnode->connect_fde = NULL;
+
+        setsockopt(tnode->fd,IPPROTO_TCP,TCP_NODELAY,(char *)&one,sizeof(one));
+        setsockopt(tnode->fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(one));
+
+	ctdb_queue_set_fd(tnode->out_queue, tnode->fd);
+
+	/* the queue subsystem now owns this fd */
+	tnode->fd = -1;
+}
+
+
+static int ctdb_tcp_get_address(struct ctdb_context *ctdb,
+				const char *address, ctdb_sock_addr *addr)
+{
+	if (parse_ip(address, NULL, 0, addr) == 0) {
+		DEBUG(DEBUG_CRIT, (__location__ " Unparsable address : %s.\n", address));
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  called when we should try and establish a tcp connection to a node
+*/
+void ctdb_tcp_node_connect(struct event_context *ev, struct timed_event *te, 
+			   struct timeval t, void *private_data)
+{
+	struct ctdb_node *node = talloc_get_type(private_data,
+						 struct ctdb_node);
+	struct ctdb_tcp_node *tnode = talloc_get_type(node->private_data, 
+						      struct ctdb_tcp_node);
+	struct ctdb_context *ctdb = node->ctdb;
+        ctdb_sock_addr sock_in;
+	int sockin_size;
+	int sockout_size;
+        ctdb_sock_addr sock_out;
+
+	ctdb_tcp_stop_connection(node);
+
+	ZERO_STRUCT(sock_out);
+#ifdef HAVE_SOCK_SIN_LEN
+	sock_out.ip.sin_len = sizeof(sock_out);
+#endif
+	if (ctdb_tcp_get_address(ctdb, node->address.address, &sock_out) != 0) {
+		return;
+	}
+	switch (sock_out.sa.sa_family) {
+	case AF_INET:
+		sock_out.ip.sin_port = htons(node->address.port);
+		break;
+	case AF_INET6:
+		sock_out.ip6.sin6_port = htons(node->address.port);
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
+			sock_out.sa.sa_family));
+		return;
+	}
+
+	tnode->fd = socket(sock_out.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+	set_nonblocking(tnode->fd);
+	set_close_on_exec(tnode->fd);
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created TCP SOCKET FD:%d\n", tnode->fd));
+
+	/* Bind our side of the socketpair to the same address we use to listen
+	 * on incoming CTDB traffic.
+	 * We must specify this address to make sure that the address we expose to
+	 * the remote side is actually routable in case CTDB traffic will run on
+	 * a dedicated non-routeable network.
+	 */
+	ZERO_STRUCT(sock_in);
+	if (ctdb_tcp_get_address(ctdb, ctdb->address.address, &sock_in) != 0) {
+		DEBUG(DEBUG_ERR, (__location__ " Failed to find our address. Failing bind.\n"));
+		close(tnode->fd);
+		return;
+	}
+
+	/* AIX libs check to see if the socket address and length
+	   arguments are consistent with each other on calls like
+	   connect().   Can not get by with just sizeof(sock_in),
+	   need sizeof(sock_in.ip).
+	*/
+	switch (sock_in.sa.sa_family) {
+	case AF_INET:
+		sockin_size = sizeof(sock_in.ip);
+		sockout_size = sizeof(sock_out.ip);
+		break;
+	case AF_INET6:
+		sockin_size = sizeof(sock_in.ip6);
+		sockout_size = sizeof(sock_out.ip6);
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
+			sock_in.sa.sa_family));
+		close(tnode->fd);
+		return;
+	}
+#ifdef HAVE_SOCK_SIN_LEN
+	sock_in.ip.sin_len = sockin_size;
+	sock_out.ip.sin_len = sockout_size;
+#endif
+	bind(tnode->fd, (struct sockaddr *)&sock_in, sockin_size);
+
+	if (connect(tnode->fd, (struct sockaddr *)&sock_out, sockout_size) != 0 &&
+	    errno != EINPROGRESS) {
+		ctdb_tcp_stop_connection(node);
+		tnode->connect_te = event_add_timed(ctdb->ev, tnode, 
+						    timeval_current_ofs(1, 0),
+						    ctdb_tcp_node_connect, node);
+		return;
+	}
+
+	/* non-blocking connect - wait for write event */
+	tnode->connect_fde = event_add_fd(node->ctdb->ev, tnode, tnode->fd, 
+					  EVENT_FD_WRITE|EVENT_FD_READ, 
+					  ctdb_node_connect_write, node);
+
+	/* don't give it long to connect - retry in one second. This ensures
+	   that we find a node is up quickly (tcp normally backs off a syn reply
+	   delay by quite a lot) */
+	tnode->connect_te = event_add_timed(ctdb->ev, tnode, timeval_current_ofs(1, 0), 
+					    ctdb_tcp_node_connect, node);
+}
+
+/*
+  called when we get contacted by another node
+  currently makes no attempt to check if the connection is really from a ctdb
+  node in our cluster
+*/
+static void ctdb_listen_event(struct event_context *ev, struct fd_event *fde, 
+			      uint16_t flags, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	struct ctdb_tcp *ctcp = talloc_get_type(ctdb->private_data, struct ctdb_tcp);
+	ctdb_sock_addr addr;
+	socklen_t len;
+	int fd, nodeid;
+	struct ctdb_incoming *in;
+	int one = 1;
+	const char *incoming_node;
+
+	memset(&addr, 0, sizeof(addr));
+	len = sizeof(addr);
+	fd = accept(ctcp->listen_fd, (struct sockaddr *)&addr, &len);
+	if (fd == -1) return;
+
+	incoming_node = ctdb_addr_to_str(&addr);
+	nodeid = ctdb_ip_to_nodeid(ctdb, incoming_node);
+
+	if (nodeid == -1) {
+		DEBUG(DEBUG_ERR, ("Refused connection from unknown node %s\n", incoming_node));
+		close(fd);
+		return;
+	}
+
+	in = talloc_zero(ctcp, struct ctdb_incoming);
+	in->fd = fd;
+	in->ctdb = ctdb;
+
+	set_nonblocking(in->fd);
+	set_close_on_exec(in->fd);
+
+	DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d to incoming ctdb connection\n", fd));
+
+        setsockopt(in->fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(one));
+
+	in->queue = ctdb_queue_setup(ctdb, in, in->fd, CTDB_TCP_ALIGNMENT, 
+				     ctdb_tcp_read_cb, in, "ctdbd-%s", incoming_node);
+}
+
+
+/*
+  automatically find which address to listen on
+*/
+static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
+{
+	struct ctdb_tcp *ctcp = talloc_get_type(ctdb->private_data,
+						struct ctdb_tcp);
+        ctdb_sock_addr sock;
+	int lock_fd, i;
+	const char *lock_path = "/tmp/.ctdb_socket_lock";
+	struct flock lock;
+	int one = 1;
+	int sock_size;
+	struct tevent_fd *fde;
+
+	/* in order to ensure that we don't get two nodes with the
+	   same adddress, we must make the bind() and listen() calls
+	   atomic. The SO_REUSEADDR setsockopt only prevents double
+	   binds if the first socket is in LISTEN state  */
+	lock_fd = open(lock_path, O_RDWR|O_CREAT, 0666);
+	if (lock_fd == -1) {
+		DEBUG(DEBUG_CRIT,("Unable to open %s\n", lock_path));
+		return -1;
+	}
+
+	lock.l_type = F_WRLCK;
+	lock.l_whence = SEEK_SET;
+	lock.l_start = 0;
+	lock.l_len = 1;
+	lock.l_pid = 0;
+
+	if (fcntl(lock_fd, F_SETLKW, &lock) != 0) {
+		DEBUG(DEBUG_CRIT,("Unable to lock %s\n", lock_path));
+		close(lock_fd);
+		return -1;
+	}
+
+	for (i=0; i < ctdb->num_nodes; i++) {
+		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+
+		/* if node_ip is specified we will only try to bind to that
+		   ip.
+		*/
+		if (ctdb->node_ip != NULL) {
+			if (strcmp(ctdb->node_ip, ctdb->nodes[i]->address.address)) {
+				continue;
+			}
+		}
+
+		ZERO_STRUCT(sock);
+		if (ctdb_tcp_get_address(ctdb,
+				ctdb->nodes[i]->address.address, 
+				&sock) != 0) {
+			continue;
+		}
+	
+		switch (sock.sa.sa_family) {
+		case AF_INET:
+			sock.ip.sin_port = htons(ctdb->nodes[i]->address.port);
+			sock_size = sizeof(sock.ip);
+			break;
+		case AF_INET6:
+			sock.ip6.sin6_port = htons(ctdb->nodes[i]->address.port);
+			sock_size = sizeof(sock.ip6);
+			break;
+		default:
+			DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
+				sock.sa.sa_family));
+			continue;
+		}
+#ifdef HAVE_SOCK_SIN_LEN
+		sock.ip.sin_len = sock_size;
+#endif
+
+		ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+		if (ctcp->listen_fd == -1) {
+			ctdb_set_error(ctdb, "socket failed\n");
+			continue;
+		}
+
+		set_close_on_exec(ctcp->listen_fd);
+
+	        setsockopt(ctcp->listen_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
+
+		if (bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size) == 0) {
+			break;
+		}
+
+		if (errno == EADDRNOTAVAIL) {
+			DEBUG(DEBUG_DEBUG,(__location__ " Failed to bind() to socket. %s(%d)\n",
+					strerror(errno), errno));
+		} else {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n",
+					strerror(errno), errno));
+		}
+	}
+	
+	if (i == ctdb->num_nodes) {
+		DEBUG(DEBUG_CRIT,("Unable to bind to any of the node addresses - giving up\n"));
+		goto failed;
+	}
+	ctdb->address.address = talloc_strdup(ctdb, ctdb->nodes[i]->address.address);
+	ctdb->address.port    = ctdb->nodes[i]->address.port;
+	ctdb->name = talloc_asprintf(ctdb, "%s:%u", 
+				     ctdb->address.address, 
+				     ctdb->address.port);
+	ctdb->pnn = ctdb->nodes[i]->pnn;
+	ctdb->nodes[i]->flags &= ~NODE_FLAGS_DISCONNECTED;
+	DEBUG(DEBUG_INFO,("ctdb chose network address %s:%u pnn %u\n", 
+		 ctdb->address.address, 
+		 ctdb->address.port, 
+		 ctdb->pnn));
+	/* do we start out in DISABLED mode? */
+	if (ctdb->start_as_disabled != 0) {
+		DEBUG(DEBUG_INFO, ("This node is configured to start in DISABLED state\n"));
+		ctdb->nodes[i]->flags |= NODE_FLAGS_DISABLED;
+	}
+	/* do we start out in STOPPED mode? */
+	if (ctdb->start_as_stopped != 0) {
+		DEBUG(DEBUG_INFO, ("This node is configured to start in STOPPED state\n"));
+		ctdb->nodes[i]->flags |= NODE_FLAGS_STOPPED;
+	}
+	
+	if (listen(ctcp->listen_fd, 10) == -1) {
+		goto failed;
+	}
+
+	fde = event_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, EVENT_FD_READ,
+			   ctdb_listen_event, ctdb);
+	tevent_fd_set_auto_close(fde);
+
+	close(lock_fd);
+	return 0;
+	
+failed:
+	close(lock_fd);
+	close(ctcp->listen_fd);
+	ctcp->listen_fd = -1;
+	return -1;
+}
+
+
+/*
+  listen on our own address
+*/
+int ctdb_tcp_listen(struct ctdb_context *ctdb)
+{
+	struct ctdb_tcp *ctcp = talloc_get_type(ctdb->private_data,
+						struct ctdb_tcp);
+        ctdb_sock_addr sock;
+	int sock_size;
+	int one = 1;
+	struct tevent_fd *fde;
+
+	/* we can either auto-bind to the first available address, or we can
+	   use a specified address */
+	if (!ctdb->address.address) {
+		return ctdb_tcp_listen_automatic(ctdb);
+	}
+
+	ZERO_STRUCT(sock);
+	if (ctdb_tcp_get_address(ctdb, ctdb->address.address, 
+				 &sock) != 0) {
+		goto failed;
+	}
+	
+	switch (sock.sa.sa_family) {
+	case AF_INET:
+		sock.ip.sin_port = htons(ctdb->address.port);
+		sock_size = sizeof(sock.ip);
+		break;
+	case AF_INET6:
+		sock.ip6.sin6_port = htons(ctdb->address.port);
+		sock_size = sizeof(sock.ip6);
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
+			sock.sa.sa_family));
+		goto failed;
+	}
+#ifdef HAVE_SOCK_SIN_LEN
+	sock.ip.sin_len = sock_size;
+#endif
+
+	ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+	if (ctcp->listen_fd == -1) {
+		ctdb_set_error(ctdb, "socket failed\n");
+		return -1;
+	}
+
+	set_close_on_exec(ctcp->listen_fd);
+
+        setsockopt(ctcp->listen_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
+
+	if (bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n", strerror(errno), errno));
+		goto failed;
+	}
+
+	if (listen(ctcp->listen_fd, 10) == -1) {
+		goto failed;
+	}
+
+	fde = event_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, EVENT_FD_READ,
+		     ctdb_listen_event, ctdb);	
+	tevent_fd_set_auto_close(fde);
+
+	return 0;
+
+failed:
+	if (ctcp->listen_fd != -1) {
+		close(ctcp->listen_fd);
+	}
+	ctcp->listen_fd = -1;
+	return -1;
+}
+

Added: branches/ctdb/squeeze-backports/tcp/tcp_init.c
===================================================================
--- branches/ctdb/squeeze-backports/tcp/tcp_init.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tcp/tcp_init.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,202 @@
+/* 
+   ctdb over TCP
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/tevent/tevent.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "../include/ctdb_private.h"
+#include "ctdb_tcp.h"
+
+static int tnode_destructor(struct ctdb_tcp_node *tnode)
+{
+  //	struct ctdb_node *node = talloc_find_parent_bytype(tnode, struct ctdb_node);
+
+	if (tnode->fd != -1) {
+		close(tnode->fd);
+		tnode->fd = -1;
+	}
+
+	return 0;
+}
+
+/*
+  initialise tcp portion of a ctdb node 
+*/
+static int ctdb_tcp_add_node(struct ctdb_node *node)
+{
+	struct ctdb_tcp_node *tnode;
+	tnode = talloc_zero(node, struct ctdb_tcp_node);
+	CTDB_NO_MEMORY(node->ctdb, tnode);
+
+	tnode->fd = -1;
+	node->private_data = tnode;
+	talloc_set_destructor(tnode, tnode_destructor);
+
+	tnode->out_queue = ctdb_queue_setup(node->ctdb, node, tnode->fd, CTDB_TCP_ALIGNMENT,
+					    ctdb_tcp_tnode_cb, node, "to-node-%s", node->name);
+	
+	return 0;
+}
+
+/*
+  initialise transport structures
+*/
+static int ctdb_tcp_initialise(struct ctdb_context *ctdb)
+{
+	int i;
+
+	/* listen on our own address */
+	if (ctdb_tcp_listen(ctdb) != 0) {
+		DEBUG(DEBUG_CRIT, (__location__ " Failed to start listening on the CTDB socket\n"));
+		exit(1);
+	}
+
+	for (i=0; i < ctdb->num_nodes; i++) {
+		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		if (ctdb_tcp_add_node(ctdb->nodes[i]) != 0) {
+			DEBUG(DEBUG_CRIT, ("methods->add_node failed at %d\n", i));
+			return -1;
+		}
+	}
+	
+	return 0;
+}
+
+/*
+  start the protocol going
+*/
+static int ctdb_tcp_connect_node(struct ctdb_node *node)
+{
+	struct ctdb_context *ctdb = node->ctdb;
+	struct ctdb_tcp_node *tnode = talloc_get_type(
+		node->private_data, struct ctdb_tcp_node);
+
+	/* startup connection to the other server - will happen on
+	   next event loop */
+	if (!ctdb_same_address(&ctdb->address, &node->address)) {
+		tnode->connect_te = event_add_timed(ctdb->ev, tnode, 
+						    timeval_zero(), 
+						    ctdb_tcp_node_connect, node);
+	}
+
+	return 0;
+}
+
+/*
+  shutdown and try to restart a connection to a node after it has been
+  disconnected
+*/
+static void ctdb_tcp_restart(struct ctdb_node *node)
+{
+	struct ctdb_tcp_node *tnode = talloc_get_type(
+		node->private_data, struct ctdb_tcp_node);
+
+	DEBUG(DEBUG_NOTICE,("Tearing down connection to dead node :%d\n", node->pnn));
+
+	ctdb_tcp_stop_connection(node);
+
+	tnode->connect_te = event_add_timed(node->ctdb->ev, tnode, timeval_zero(), 
+					    ctdb_tcp_node_connect, node);
+}
+
+
+/*
+  shutdown the transport
+*/
+static void ctdb_tcp_shutdown(struct ctdb_context *ctdb)
+{
+	struct ctdb_tcp *ctcp = talloc_get_type(ctdb->private_data,
+						struct ctdb_tcp);
+	talloc_free(ctcp);
+	ctdb->private_data = NULL;
+}
+
+/*
+  start the transport
+*/
+static int ctdb_tcp_start(struct ctdb_context *ctdb)
+{
+	int i;
+
+	for (i=0; i < ctdb->num_nodes; i++) {
+		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		ctdb_tcp_connect_node(ctdb->nodes[i]);
+	}
+
+	return 0;
+}
+
+
+/*
+  transport packet allocator - allows transport to control memory for packets
+*/
+static void *ctdb_tcp_allocate_pkt(TALLOC_CTX *mem_ctx, size_t size)
+{
+	/* tcp transport needs to round to 8 byte alignment to ensure
+	   that we can use a length header and 64 bit elements in
+	   structures */
+	size = (size+(CTDB_TCP_ALIGNMENT-1)) & ~(CTDB_TCP_ALIGNMENT-1);
+	return talloc_size(mem_ctx, size);
+}
+
+
+static const struct ctdb_methods ctdb_tcp_methods = {
+	.initialise   = ctdb_tcp_initialise,
+	.start        = ctdb_tcp_start,
+	.queue_pkt    = ctdb_tcp_queue_pkt,
+	.add_node     = ctdb_tcp_add_node,
+	.connect_node = ctdb_tcp_connect_node,
+	.allocate_pkt = ctdb_tcp_allocate_pkt,
+	.shutdown     = ctdb_tcp_shutdown,
+	.restart      = ctdb_tcp_restart,
+};
+
+static int tcp_ctcp_destructor(struct ctdb_tcp *ctcp)
+{
+	ctcp->ctdb->private_data = NULL;
+	ctcp->ctdb->methods = NULL;
+	
+	return 0;
+}
+
+		
+/*
+  initialise tcp portion of ctdb 
+*/
+int ctdb_tcp_init(struct ctdb_context *ctdb)
+{
+	struct ctdb_tcp *ctcp;
+	ctcp = talloc_zero(ctdb, struct ctdb_tcp);
+	CTDB_NO_MEMORY(ctdb, ctcp);
+
+	ctcp->listen_fd = -1;
+	ctcp->ctdb      = ctdb;
+	ctdb->private_data = ctcp;
+	ctdb->methods = &ctdb_tcp_methods;
+
+	talloc_set_destructor(ctcp, tcp_ctcp_destructor);
+	return 0;
+}
+

Added: branches/ctdb/squeeze-backports/tcp/tcp_io.c
===================================================================
--- branches/ctdb/squeeze-backports/tcp/tcp_io.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tcp/tcp_io.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,89 @@
+/* 
+   ctdb over TCP
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/util/dlinklist.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "../include/ctdb_private.h"
+#include "ctdb_tcp.h"
+
+
+/*
+  called when a complete packet has come in
+ */
+void ctdb_tcp_read_cb(uint8_t *data, size_t cnt, void *args)
+{
+	struct ctdb_incoming *in = talloc_get_type(args, struct ctdb_incoming);
+	struct ctdb_req_header *hdr = (struct ctdb_req_header *)data;
+
+	if (data == NULL) {
+		/* incoming socket has died */
+		goto failed;
+	}
+
+	if (cnt < sizeof(*hdr)) {
+		DEBUG(DEBUG_ALERT,(__location__ " Bad packet length %u\n", (unsigned)cnt));
+		goto failed;
+	}
+
+	if (cnt & (CTDB_TCP_ALIGNMENT-1)) {
+		DEBUG(DEBUG_ALERT,(__location__ " Length 0x%x not multiple of alignment\n", 
+			 (unsigned)cnt));
+		goto failed;
+	}
+
+
+	if (cnt != hdr->length) {
+		DEBUG(DEBUG_ALERT,(__location__ " Bad header length %u expected %u\n", 
+			 (unsigned)hdr->length, (unsigned)cnt));
+		goto failed;
+	}
+
+	if (hdr->ctdb_magic != CTDB_MAGIC) {
+		DEBUG(DEBUG_ALERT,(__location__ " Non CTDB packet 0x%x rejected\n", 
+			 hdr->ctdb_magic));
+		goto failed;
+	}
+
+	if (hdr->ctdb_version != CTDB_VERSION) {
+		DEBUG(DEBUG_ALERT, (__location__ " Bad CTDB version 0x%x rejected\n", 
+			  hdr->ctdb_version));
+		goto failed;
+	}
+
+	/* tell the ctdb layer above that we have a packet */
+	in->ctdb->upcalls->recv_pkt(in->ctdb, data, cnt);
+	return;
+
+failed:
+	talloc_free(in);
+}
+
+/*
+  queue a packet for sending
+*/
+int ctdb_tcp_queue_pkt(struct ctdb_node *node, uint8_t *data, uint32_t length)
+{
+	struct ctdb_tcp_node *tnode = talloc_get_type(node->private_data,
+						      struct ctdb_tcp_node);
+	return ctdb_queue_send(tnode->out_queue, data, length);
+}

Added: branches/ctdb/squeeze-backports/tests/README
===================================================================
--- branches/ctdb/squeeze-backports/tests/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,106 @@
+Introduction
+------------
+
+The run_tests script can be run as follows:
+
+  scripts/run_tests simple/*.sh
+
+It can also be run from other places (e.g. the top level ctdb source
+directory), as it works out where the tree is.
+
+The pseudo-test simple/00_ctdb_init.sh causes ctdb to be (re)started
+on all nodes to attempt to force the cluster into a healthy state.  By
+default (i.e. if CTDB_TEST_REAL_CLUSTER is unset - see below) this
+causes some local daemons to be started on the local machine.  Tests
+can also be run against a real or virtual cluster.  All tests
+communicate with cluster nodes using onnode - when using local daemons
+this is accomplished via some test hooks in onnode and the ctdb
+client.
+
+Command-line options
+--------------------
+
+The most useful option is "-s", which causes a summary of test results
+to be printed at the end of testing.
+
+Environment variables
+---------------------
+
+run_tests supports several environment variables, mostly implemented
+in scripts/ctdb_test_env.  These are:
+
+* CTDB_TEST_REAL_CLUSTER
+
+  If set, testing will occur on a real or virtual cluster.
+
+  Assumptions:
+
+  - The ctdb client command can be found via $PATH on the nodes.
+
+  - Password-less ssh access to the cluster nodes is permitted from
+    the test host.
+
+  - $CTDB_NODES_FILE is set to the location of a file similar to
+    /etc/ctdb/nodes.  The file can be obtained by scping it from one
+    of the cluster nodes.
+
+  - See CTDB_TEST_REMOTE_DIR.
+
+  If not set, testing will proceed against local daemons.
+
+* CTDB_TEST_REMOTE_DIR
+
+  This may be required when running against a real or virtual cluster
+  (as opposed to local daemons).
+
+  If set, this points to a directory containing the contents of the
+  tests/scripts/ directory, as well as all of the test binaries.  This
+  can be accomplished in a couple of ways:
+
+  * By copying the relevant scripts/binaries to some directory.
+
+  * Building an RPM containing all of the test code that is required
+    on the cluster nodes and installing it on each node.  Hopefully
+    this will be supported in a future version of the CTDB packaging
+    process.
+
+  If not set, the test system assumes that the CTDB tree is available
+  in the same location on the cluster nodes as on the test host.  This
+  could be accomplished by copying or by sharing with NFS (or
+  similar).
+
+* VALGRIND
+
+  This can be used to cause all invocations of the ctdb client (and,
+  with local daemons, the ctdbd daemons themselves) to occur under
+  valgrind.
+
+  The easiest way of doing this is something like:
+
+    VALGRIND="valgrind -q" scripts/run_tests ...
+
+  NOTE: Some libc calls seem to do weird things and perhaps cause
+  spurious output from ctdbd at start time.  Please read valgrind
+  output carefully before reporting bugs.  :-)
+
+* CTDB
+
+  How to invoke the ctdb client.  If not already set and if $VALGRIND
+  is set, this is set to "$VALGRIND ctdb".  If this is not already set
+  but $VALGRIND is not set, this is simply set to "ctdb"
+
+Look, no run_test!
+------------------
+
+If you want to integrate individual tests into some other test
+environment you can use scripts/ctdb_test_env to wrap individual
+tests.  They will return 0 on success, non-zero otherwise, and will
+print the output omitting the test header/footer that surrounds test
+output when tests are run using run_tests.  So, you can do something
+like:
+
+  for i in simple/*.sh ; do
+      my_test_framework_wrapper scripts/ctdb_test_env $i
+  done
+
+to have your own framework process the test results and output.

Added: branches/ctdb/squeeze-backports/tests/TODO
===================================================================
--- branches/ctdb/squeeze-backports/tests/TODO	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/TODO	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,4 @@
+* Make tests know about IPv6.
+* Tests that write to database.
+* Tests that check actual network connectivity on failover.
+* Handle interrupting tests better.

Added: branches/ctdb/squeeze-backports/tests/complex/01_ctdb_nfs_skip_share_check.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/01_ctdb_nfs_skip_share_check.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/01_ctdb_nfs_skip_share_check.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,129 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that the CTDB_NFS_SKIP_SHARE_CHECK configuration option is respected.
+
+We create a file in /etc/ctdb/rc.local.d/ that creates a function
+called exportfs.  This effectively hooks the exportfs command,
+allowing us to provide a fake list of shares to check or not check.
+
+We create another file in the same directory to set and unset the
+CTDB_NFS_SKIP_SHARE_CHECK option, utilising the shell's "readonly"
+built-in to ensure that our value for the option is used.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.  There is nothing intrinsic to this test that forces
+  this - it is because tests run against local daemons don't use the
+  regular eventscripts.
+
+Steps:
+
+1.  Verify that the cluster is healthy.
+2.  Determine a timeout for state changes by adding MonitorInterval
+    and EventScriptTimeout.
+3.  Create a temporary directory on the test node using mktemp,
+    remember the name in $mydir.
+4.  On the test node create an executable file
+    /etc/ctdb/rc.local.d/fake-exportfs that contains a definiton for
+    the function exportfs, which prints a share definition for a
+    directory $mydir/foo (which does not currently exist).
+5.  On the test node create an executable file
+    /etc/ctdb/rc.local.d/nfs-skip-share-check that replaces the
+    loadconfig() function by one with equivalent functionality, but
+    which also sets CTDB_NFS_SKIP_SHARE_CHECK="no" if loading
+    "ctdb" configuration.
+6.  Wait for the test node to become unhealthy.
+7.  Create the directory $mydir/foo.
+8.  Wait for the test node to become healthy.
+9.  Modify /etc/ctdb/rc.local.d/nfs-skip-share-check so that it sets
+    CTDB_NFS_SKIP_SHARE_CHECK to "yes".
+10. Remove the directory $mydir/foo.
+11. Wait for  a monitor event and confirm that the the node is still
+    healthy.
+
+Expected results:
+
+* When an NFS share directory is missing CTDB should only mark a node
+  as unhealthy if CTDB_NFS_SKIP_SHARE_CHECK is set to "no".
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+select_test_node_and_ips
+
+# We need this for later, so we know how long to sleep.
+try_command_on_node $test_node $CTDB getvar MonitorInterval
+monitor_interval=${out#*= }
+try_command_on_node $test_node $CTDB getvar EventScriptTimeout
+event_script_timeout=${out#*= }
+
+monitor_timeout=$(($monitor_interval + $event_script_timeout))
+
+echo "Using timeout of ${monitor_timeout}s (MonitorInterval + EventScriptTimeout)..."
+
+
+mydir=$(onnode -q $test_node mktemp -d)
+rc_local_d="${CTDB_BASE:-/etc/ctdb}/rc.local.d"
+
+my_exit_hook ()
+{
+    ctdb_test_eventscript_uninstall
+    onnode -q $test_node "rm -f $mydir/*"
+    onnode -q $test_node "rmdir --ignore-fail-on-non-empty $mydir"
+    onnode -q $test_node "rm -f \"$rc_local_d/\"*"
+    onnode -q $test_node "rmdir --ignore-fail-on-non-empty \"$rc_local_d\""
+}
+
+ctdb_test_exit_hook_add my_exit_hook
+
+ctdb_test_eventscript_install
+
+foo_dir=$mydir/foo
+
+try_command_on_node -v $test_node "mkdir -p \"$rc_local_d\""
+
+f="$rc_local_d/fake-exportfs"
+echo "Installing \"$f\"..."
+try_command_on_node $test_node "echo \"function exportfs () { echo $foo_dir 127.0.0.1/32 ; }\" >\"$f\" ; chmod +x \"$f\""
+
+n="$rc_local_d/nfs-skip-share-check"
+n_contents='loadconfig() {
+    _loadconfig "$@"
+
+    if [ "$1" = "ctdb" -o "$1" = "nfs" ] ; then
+        CTDB_NFS_SKIP_SHARE_CHECK=no
+    fi
+}
+'
+echo "Installing \"$n\" with CTDB_NSF_SKIP_SHARE_CHECK=no..."
+try_command_on_node $test_node "echo '$n_contents' >\"$n\" ; chmod +x \"$n\""
+
+wait_until_node_has_status $test_node unhealthy $monitor_timeout
+
+try_command_on_node -v $test_node "mkdir $foo_dir"
+
+wait_until_node_has_status $test_node healthy $monitor_timeout
+
+echo "Re-installing \"$n\" with CTDB_NFS_SKIP_SHARE_CHECK=yes..."
+try_command_on_node $test_node "echo '${n_contents/=no/=yes}' >\"$n\" ; chmod +x \"$n\""
+
+try_command_on_node -v $test_node "rmdir $foo_dir"
+
+wait_for_monitor_event $test_node
+
+wait_until_node_has_status $test_node healthy 1


Property changes on: branches/ctdb/squeeze-backports/tests/complex/01_ctdb_nfs_skip_share_check.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/complex/02_ctdb_samba_skip_share_check.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/02_ctdb_samba_skip_share_check.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/02_ctdb_samba_skip_share_check.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,134 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that the CTDB_SAMBA_SKIP_SHARE_CHECK configuration option is respected.
+
+We create a file in /etc/ctdb/rc.local.d/ that creates a function
+called testparm.  This effectively hooks the testparm command,
+allowing us to provide a fake list of shares to check or not check.
+
+We create another file in the same directory to set and unset the
+CTDB_SAMBA_SKIP_SHARE_CHECK option, utilising the shell's "readonly"
+built-in to ensure that our value for the option is used.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.  There is nothing intrinsic to this test that forces
+  this - it is because tests run against local daemons don't use the
+  regular eventscripts.
+
+Steps:
+
+1.  Verify that the cluster is healthy.
+2.  Determine a timeout for state changes by adding MonitorInterval
+    and EventScriptTimeout.
+3.  Create a temporary directory using mktemp, remember the name in
+    $mydir.
+4.  Create an executable file /etc/ctdb/rc.local.d/fake-testparm that
+    contains a definiton for the function testparm, which prints a
+    share definition for a directory $mydir/foo (which does not
+    currently exist).
+5.  Create an executable file
+    /etc/ctdb/rc.local.d/samba-skip-share-check that replaces the
+    loadconfig() function by one with equivalent functionality, but
+    which also sets CTDB_SAMBA_SKIP_SHARE_CHECK="no" if loading
+    "ctdb" configuration.
+6.  Wait for a maximum of MonitorInterval seconds for the node to
+    become unhealthy.
+7.  Create the directory $mydir/foo.
+8.  Wait for a maximum of MonitorInterval seconds for the node to
+    become healthy.
+9.  Modify /etc/ctdb/rc.local.d/samba-skip-share-check so that it sets
+    CTDB_SAMBA_SKIP_SHARE_CHECK="yes".
+10. Remove the directory $mydir/foo.
+11. Wait for  a monitor event and confirm that the the node is still
+    healthy.
+
+Expected results:
+
+* When an SAMBA share directory is missing CTDB should only mark a node
+  as unhealthy if CTDB_SAMBA_SKIP_SHARE_CHECK is set to "no".
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+select_test_node_and_ips
+
+# We need this for later, so we know how long to sleep.
+# We need this for later, so we know how long to sleep.
+try_command_on_node $test_node $CTDB getvar MonitorInterval
+monitor_interval=${out#*= }
+try_command_on_node $test_node $CTDB getvar EventScriptTimeout
+event_script_timeout=${out#*= }
+
+monitor_timeout=$(($monitor_interval + $event_script_timeout))
+
+echo "Using timeout of ${monitor_timeout}s (MonitorInterval + EventScriptTimeout)..."
+
+mydir=$(onnode -q $test_node mktemp -d)
+rc_local_d="${CTDB_BASE:-/etc/ctdb}/rc.local.d"
+
+my_exit_hook ()
+{
+    ctdb_test_eventscript_uninstall
+    onnode -q $test_node "rm -f $mydir/*"
+    onnode -q $test_node "rmdir --ignore-fail-on-non-empty $mydir"
+    onnode -q $test_node "rm -f \"$rc_local_d/\"*"
+    onnode -q $test_node "rmdir --ignore-fail-on-non-empty \"$rc_local_d\""
+}
+
+ctdb_test_exit_hook_add my_exit_hook
+
+ctdb_test_eventscript_install
+
+foo_dir=$mydir/foo
+
+try_command_on_node -v $test_node "mkdir -p \"$rc_local_d\""
+
+f="$rc_local_d/fake-testparm"
+echo "Installing \"$f\"..."
+# Yes, the quoting is very tricky.  We want $foo_dir and $f expanded when
+# we echo the function definition but we don't want any of the other
+# items expanded until the function is run.
+try_command_on_node $test_node "echo 'function testparm () { tp=\$(which testparm 2>/dev/null) ; if [ -n \"\$2\" ] ; then echo path = '\"$foo_dir\"' ; else \$tp \"\$@\" ; fi ; }' >\"$f\" ; chmod +x \"$f\""
+
+n="$rc_local_d/samba-skip-share-check"
+n_contents='loadconfig() {
+    _loadconfig "$@"
+
+    if [ "$1" = "ctdb" ] ; then
+        CTDB_SAMBA_SKIP_SHARE_CHECK=no
+    fi
+}
+'
+echo "Installing \"$n\" with CTDB_SAMBA_SKIP_SHARE_CHECK=no..."
+try_command_on_node $test_node "echo '$n_contents' >\"$n\" ; chmod +x \"$n\""
+
+wait_until_node_has_status $test_node unhealthy $monitor_timeout
+
+try_command_on_node -v $test_node "mkdir $foo_dir"
+
+wait_until_node_has_status $test_node healthy $monitor_timeout
+
+echo "Re-installing \"$n\" with CTDB_SAMBA_SKIP_SHARE_CHECK=yes..."
+try_command_on_node $test_node "echo '${n_contents/=no/=yes}' >\"$n\" ; chmod +x \"$n\""
+
+try_command_on_node -v $test_node "rmdir $foo_dir"
+
+wait_for_monitor_event $test_node
+
+wait_until_node_has_status $test_node healthy 1


Property changes on: branches/ctdb/squeeze-backports/tests/complex/02_ctdb_samba_skip_share_check.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/complex/31_nfs_tickle.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/31_nfs_tickle.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/31_nfs_tickle.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,116 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that NFS connections are monitored and that NFS tickles are sent.
+
+We create a connection to the NFS server on a node and confirm that
+this connection is registered in the nfs-tickles/ subdirectory in
+shared storage.  Then disable the relevant NFS server node and ensure
+that it send an appropriate reset packet.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.
+
+* Test must not be run from a cluster node.
+
+* Cluster nodes must be listening on the NFS TCP port (2049).
+
+Steps:
+
+1. Verify that the cluster is healthy.
+2. Connect from the current host (test client) to TCP port 2049 using
+   the public address of a cluster node.
+3. Determine the source socket used for the connection.
+4. Ensure that CTDB records the source socket details in the nfs-tickles
+   directory on shared storage.
+5. Disable the node that the connection has been made to.
+6. Verify that a TCP tickle (a reset packet) is sent to the test client.
+
+Expected results:
+
+* CTDB should correctly record the socket in the nfs-tickles directory
+  and should send a reset packet when the node is disabled.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+ctdb_test_exit_hook_add ctdb_test_eventscript_uninstall
+
+ctdb_test_eventscript_install
+
+# We need this for later, so we know how long to sleep.
+try_command_on_node any $CTDB getvar MonitorInterval
+monitor_interval="${out#*= }"
+#echo "Monitor interval on node $test_node is $monitor_interval seconds."
+
+select_test_node_and_ips
+
+test_port=2049
+
+echo "Connecting to node ${test_node} on IP ${test_ip}:${test_port} with netcat..."
+
+nc -d -w $(($monitor_interval * 4)) $test_ip $test_port &
+nc_pid=$!
+ctdb_test_exit_hook_add "kill $nc_pid >/dev/null 2>&1"
+
+wait_until_get_src_socket "tcp" "${test_ip}:${test_port}" $nc_pid "nc"
+src_socket="$out"
+echo "Source socket is $src_socket"
+
+wait_for_monitor_event $test_node
+
+echo "Sleeping until tickles are synchronised across nodes..."
+try_command_on_node $test_node $CTDB getvar TickleUpdateInterval
+sleep_for "${out#*= }"
+
+if try_command_on_node any "test -r /etc/ctdb/events.d/61.nfstickle" ; then
+    echo "Trying to determine NFS_TICKLE_SHARED_DIRECTORY..."
+    f="/etc/sysconfig/nfs"
+    try_command_on_node -v any "[ -r $f ] &&  sed -n -e s@^NFS_TICKLE_SHARED_DIRECTORY=@@p $f" || true
+
+    nfs_tickle_shared_directory="${out:-/gpfs/.ctdb/nfs-tickles}"
+
+    try_command_on_node $test_node hostname
+    test_hostname=$out
+
+    try_command_on_node -v any cat "${nfs_tickle_shared_directory}/$test_hostname/$test_ip"
+else
+    echo "That's OK, we'll use \"ctdb gettickles\", which is newer..."
+    try_command_on_node -v any "ctdb -Y gettickles $test_ip $test_port"
+fi
+
+if [ "${out/${src_socket}/}" != "$out" ] ; then
+    echo "GOOD: NFS connection tracked OK."
+else
+    echo "BAD: Socket not tracked in NFS tickles."
+    testfailures=1
+fi
+
+tcptickle_sniff_start $src_socket "${test_ip}:${test_port}"
+
+# We need to be nasty to make that the node being failed out doesn't
+# get a chance to send any tickles and confuse our sniff.
+echo "Killing ctdbd on ${test_node}..."
+try_command_on_node $test_node killall -9 ctdbd
+
+wait_until_node_has_status $test_node disconnected
+
+tcptickle_sniff_wait_show


Property changes on: branches/ctdb/squeeze-backports/tests/complex/31_nfs_tickle.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/complex/32_cifs_tickle.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/32_cifs_tickle.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/32_cifs_tickle.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that CIFS connections are monitored and that CIFS tickles are sent.
+
+We create a connection to the CIFS server on a node and confirm that
+this connection is registered by CTDB.  Then disable the relevant CIFS
+server node and ensure that it send an appropriate reset packet.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.
+
+* Test must not be run from a cluster node.
+
+* Clustered Samba must be listening on TCP port 445.
+
+Steps:
+
+1. Verify that the cluster is healthy.
+2. Connect from the current host (test client) to TCP port 445 using
+   the public address of a cluster node.
+3. Determine the source socket used for the connection.
+4. Using the "ctdb gettickle" command, ensure that CTDB records the
+   connection details.
+5. Disable the node that the connection has been made to.
+6. Verify that a TCP tickle (a reset packet) is sent to the test client.
+
+Expected results:
+
+* CTDB should correctly record the connection and should send a reset
+  packet when the node is disabled.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+# We need this for later, so we know how long to sleep.
+try_command_on_node 0 $CTDB getvar MonitorInterval
+monitor_interval="${out#*= }"
+#echo "Monitor interval on node $test_node is $monitor_interval seconds."
+
+select_test_node_and_ips
+
+test_port=445
+
+echo "Connecting to node ${test_node} on IP ${test_ip}:${test_port} with netcat..."
+
+nc -d -w $(($monitor_interval * 4)) $test_ip $test_port &
+nc_pid=$!
+ctdb_test_exit_hook_add "kill $nc_pid >/dev/null 2>&1"
+
+wait_until_get_src_socket "tcp" "${test_ip}:${test_port}" $nc_pid "nc"
+src_socket="$out"
+echo "Source socket is $src_socket"
+
+# This should happen as soon as connection is up... but unless we wait
+# we sometimes beat the registration.
+check_tickles ()
+{
+    try_command_on_node 0 ctdb gettickles $test_ip -n $test_node
+    # SRC: 10.0.2.45:49091   DST: 10.0.2.143:445
+    [ "${out/SRC: ${src_socket} /}" != "$out" ]
+}
+
+echo "Checking if CIFS connection is tracked by CTDB..."
+wait_until 10 check_tickles
+echo "$out"
+
+if [ "${out/SRC: ${src_socket} /}" != "$out" ] ; then
+    echo "GOOD: CIFS connection tracked OK by CTDB."
+else
+    echo "BAD: Socket not tracked by CTDB."
+    testfailures=1
+fi
+
+tcptickle_sniff_start $src_socket "${test_ip}:${test_port}"
+
+echo "Disabling node $test_node"
+try_command_on_node 1 $CTDB disable -n $test_node
+wait_until_node_has_status $test_node disabled
+
+tcptickle_sniff_wait_show


Property changes on: branches/ctdb/squeeze-backports/tests/complex/32_cifs_tickle.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/complex/33_gratuitous_arp.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/33_gratuitous_arp.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/33_gratuitous_arp.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that a gratuitous ARP is sent when a node is failed out.
+
+We ping a public IP and lookup the MAC address in the ARP table.  We
+then disable the node and check the ARP table again - the MAC address
+should have changed.  This test does NOT test connectivity after the
+failover.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.
+
+* Test must not be run from a cluster node.
+
+Steps:
+
+1. Verify that the cluster is healthy.
+2. Select a public address and its corresponding node.
+3. Remove any entries for the chosen address from the ARP table.
+4. Send a single ping request packet to the selected public address.
+5. Determine the MAC address corresponding to the public address by
+   checking the ARP table.
+6. Disable the selected node.
+7. Check the ARP table and check the MAC associated with the public
+   address.
+
+Expected results:
+
+* When a node is disabled the MAC address associated with public
+  addresses on that node should change.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+select_test_node_and_ips
+
+echo "Removing ${test_ip} from the local ARP table..."
+arp -d $test_ip >/dev/null 2>&1 || true
+
+echo "Pinging ${test_ip}..."
+ping -q -n -c 1 $test_ip
+
+echo "Getting MAC address associated with ${test_ip}..."
+original_mac=$(arp -n $test_ip | awk '$2 == "ether" {print $3}')
+[ $? -eq 0 ]
+
+echo "MAC address is: ${original_mac}"
+
+gratarp_sniff_start
+
+echo "Disabling node $test_node"
+try_command_on_node 1 $CTDB disable -n $test_node
+wait_until_node_has_status $test_node disabled
+
+gratarp_sniff_wait_show
+
+echo "Getting MAC address associated with ${test_ip} again..."
+new_mac=$(arp -n $test_ip | awk '$2 == "ether" {print $3}')
+[ $? -eq 0 ]
+
+echo "MAC address is: ${new_mac}"
+
+if [ "$original_mac" != "$new_mac" ] ; then
+    echo "GOOD: MAC address changed"
+else
+    echo "BAD: MAC address did not change"
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/complex/33_gratuitous_arp.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/complex/41_failover_ping_discrete.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/41_failover_ping_discrete.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/41_failover_ping_discrete.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that it is possible to ping a public address after disabling a node.
+
+We ping a public IP, disable the node hosting it and then ping the
+public IP again.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.
+
+* Test must not be run from a cluster node.
+
+Steps:
+
+1. Verify that the cluster is healthy.
+2. Select a public address and its corresponding node.
+3. Send a single ping request packet to the selected public address.
+4. Disable the selected node.
+5. Send another single ping request packet to the selected public address.
+
+Expected results:
+
+* When a node is disabled the public address fails over and the
+  address is still pingable.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+select_test_node_and_ips
+
+echo "Removing ${test_ip} from the local ARP table..."
+arp -d $test_ip >/dev/null 2>&1 || true
+
+echo "Pinging ${test_ip}..."
+ping -q -n -c 1 $test_ip
+
+gratarp_sniff_start
+
+echo "Disabling node $test_node"
+try_command_on_node 1 $CTDB disable -n $test_node
+wait_until_node_has_status $test_node disabled
+
+gratarp_sniff_wait_show
+
+echo "Removing ${test_ip} from the local ARP table again..."
+arp -d $test_ip >/dev/null 2>&1 || true
+
+echo "Pinging ${test_ip} again..."
+ping -q -n -c 1 $test_ip


Property changes on: branches/ctdb/squeeze-backports/tests/complex/41_failover_ping_discrete.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/complex/42_failover_ssh_hostname.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/42_failover_ssh_hostname.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/42_failover_ssh_hostname.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that it is possible to SSH to a public address after disabling a node.
+
+We SSH to a public IP and check the hostname, disable the node hosting
+it and then SSH again to confirm that the hostname has changed.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.
+
+* Test must not be run from a cluster node.
+
+Steps:
+
+1. Verify that the cluster is healthy.
+2. Select a public address and its corresponding node.
+3. SSH to the selected public address and run hostname.
+4. Disable the selected node.
+5. SSH to the selected public address again and run hostname.
+
+Expected results:
+
+* When a node is disabled the public address fails over and it is
+  still possible to SSH to the node.  The hostname should change.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+select_test_node_and_ips
+
+echo "Removing ${test_ip} from the local ARP table..."
+arp -d $test_ip >/dev/null 2>&1 || true
+
+echo "SSHing to ${test_ip} and running hostname..."
+original_hostname=$(ssh -o "StrictHostKeyChecking no" $test_ip hostname)
+[ $? -eq 0 ]
+
+echo "Hostname is: ${original_hostname}"
+
+gratarp_sniff_start
+
+echo "Disabling node $test_node"
+try_command_on_node 1 $CTDB disable -n $test_node
+wait_until_node_has_status $test_node disabled
+
+gratarp_sniff_wait_show
+
+echo "SSHing to ${test_ip} and running hostname (again)..."
+new_hostname=$(ssh -o "StrictHostKeyChecking no" $test_ip hostname)
+[ $? -eq 0 ]
+
+echo "Hostname is: ${new_hostname}"
+
+if [ "$original_hostname" != "$new_hostname" ] ; then
+    echo "GOOD: hostname changed"
+else
+    echo "BAD: hostname did not change"
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/complex/42_failover_ssh_hostname.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/complex/43_failover_nfs_basic.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/43_failover_nfs_basic.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/43_failover_nfs_basic.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,86 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that a mounted NFS share is still operational after failover.
+
+We mount an NFS share from a node, write a file via NFS and then
+confirm that we can correctly read the file after a failover.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.
+
+* Test must not be run from a cluster node.
+
+Steps:
+
+1. Verify that the cluster is healthy.
+2. Select a public address and its corresponding node.
+3. Select the 1st NFS share exported on the node.
+4. Mount the selected NFS share.
+5. Create a file in the NFS mount and calculate its checksum.
+6. Disable the selected node.
+7. Read the file and calculate its checksum.
+8. Compare the checksums.
+
+Expected results:
+
+* When a node is disabled the public address fails over and it is
+  possible to correctly read a file over NFS.  The checksums should be
+  the same before and after.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+select_test_node_and_ips
+
+first_export=$(showmount -e $test_ip | sed -n -e '2s/ .*//p')
+mnt_d=$(mktemp -d)
+test_file="${mnt_d}/$RANDOM"
+
+ctdb_test_exit_hook_add rm -f "$test_file"
+ctdb_test_exit_hook_add umount -f "$mnt_d"
+ctdb_test_exit_hook_add rmdir "$mnt_d"
+
+echo "Mounting ${test_ip}:${first_export} on ${mnt_d} ..."
+mount -o timeo=1,hard,intr,vers=3 ${test_ip}:${first_export} ${mnt_d}
+
+echo "Create file containing random data..."
+dd if=/dev/urandom of=$test_file bs=1k count=1
+original_sum=$(sum $test_file)
+[ $? -eq 0 ]
+
+gratarp_sniff_start
+
+echo "Disabling node $test_node"
+try_command_on_node 0 $CTDB disable -n $test_node
+wait_until_node_has_status $test_node disabled
+
+gratarp_sniff_wait_show
+
+new_sum=$(sum $test_file)
+[ $? -eq 0 ]
+
+if [ "$original_md5" = "$new_md5" ] ; then
+    echo "GOOD: file contents unchanged after failover"
+else
+    echo "BAD: file contents are different after failover"
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/complex/43_failover_nfs_basic.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/complex/44_failover_nfs_oneway.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/complex/44_failover_nfs_oneway.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/complex/44_failover_nfs_oneway.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,107 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that a file created on a node is readable via NFS after a failover.
+
+We write a file into an exported directory on a node, mount the NFS
+share from a node, verify that we can read the file via NFS and that
+we can still read it after a failover.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 nodes with public addresses.
+
+* Test must be run on a real or virtual cluster rather than against
+  local daemons.
+
+* Test must not be run from a cluster node.
+
+Steps:
+
+1.  Verify that the cluster is healthy.
+2.  Select a public address and its corresponding node.
+3.  Select the 1st NFS share exported on the node.
+4.  Write a file into exported directory on the node and calculate its
+    checksum.
+5.  Mount the selected NFS share.
+6.  Read the file via the NFS mount and calculate its checksum.
+7.  Compare checksums.
+8.  Disable the selected node.
+9.  Read the file via NFS and calculate its checksum.
+10. Compare the checksums.
+
+Expected results:
+
+* Checksums for the file on all 3 occasions should be the same.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+set -e
+
+ctdb_test_init "$@"
+
+ctdb_test_check_real_cluster
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+select_test_node_and_ips
+
+first_export=$(showmount -e $test_ip | sed -n -e '2s/ .*//p')
+local_f=$(mktemp)
+mnt_d=$(mktemp -d)
+nfs_f="${mnt_d}/$RANDOM"
+remote_f="${test_ip}:${first_export}/$(basename $nfs_f)"
+
+ctdb_test_exit_hook_add rm -f "$local_f"
+ctdb_test_exit_hook_add rm -f "$nfs_f"
+ctdb_test_exit_hook_add umount -f "$mnt_d"
+ctdb_test_exit_hook_add rmdir "$mnt_d"
+
+echo "Create file containing random data..."
+dd if=/dev/urandom of=$local_f bs=1k count=1
+chmod 644 "$local_f" # needed for *_squash?
+local_sum=$(sum $local_f)
+[ $? -eq 0 ]
+
+scp -p "$local_f" "$remote_f"
+
+echo "Mounting ${test_ip}:${first_export} on ${mnt_d} ..."
+mount -o timeo=1,hard,intr,vers=3 ${test_ip}:${first_export} ${mnt_d}
+
+nfs_sum=$(sum $nfs_f)
+
+if [ "$local_sum" = "$nfs_sum" ] ; then
+    echo "GOOD: file contents read correctly via NFS"
+else
+    echo "BAD: file contents are different over NFS"
+    echo "  original file: $local_sum"
+    echo "       NFS file: $nfs_sum"
+    exit 1
+fi
+
+gratarp_sniff_start
+
+echo "Disabling node $test_node"
+try_command_on_node 0 $CTDB disable -n $test_node
+wait_until_node_has_status $test_node disabled
+
+gratarp_sniff_wait_show
+
+new_sum=$(sum $nfs_f)
+[ $? -eq 0 ]
+
+if [ "$nfs_sum" = "$new_sum" ] ; then
+    echo "GOOD: file contents unchanged after failover"
+else
+    echo "BAD: file contents are different after failover"
+    echo "  original file: $nfs_sum"
+    echo "       NFS file: $new_sum"
+    exit 1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/complex/44_failover_nfs_oneway.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/events.d/00.test
===================================================================
--- branches/ctdb/squeeze-backports/tests/events.d/00.test	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/events.d/00.test	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,104 @@
+#!/bin/sh
+# event script for 'make test'
+
+cmd="$1"
+shift
+
+case $cmd in 
+    monitor)
+	echo "monitor event"
+	echo "monitor event stderr" >&2
+	exit 0
+	;;
+
+     startrecovery)
+	echo "ctdb startrecovery event"
+	exit 0;	
+	;;
+
+     init)
+	echo "ctdb init event"
+	exit 0;
+	;;
+     setup)
+	echo "ctdb setup event"
+	exit 0;
+	;;
+     startup)
+	echo "ctdb startup event"
+	IFACES=`ctdb ifaces -Y | grep -v '^:Name:LinkStatus:References:'`
+	for I in $IFACES; do
+		IFACE=`echo -n "$I" | cut -d ':' -f2`
+		ctdb setifacelink $IFACE up
+	done
+	exit 0;
+	;;
+	
+     takeip)
+	if [ $# != 3 ]; then
+	   echo "must supply interface, IP and maskbits"
+	   exit 1
+	fi
+	iface=$1
+	ip=$2
+	maskbits=$3
+
+	[ `id -u` = 0 ] && {
+	    /sbin/ip addr add $ip/$maskbits dev $iface || {
+		echo "Failed to add $ip/$maskbits on dev $iface"
+		exit 1
+	    }
+	}
+	exit 0;
+	;;
+
+
+     ##################################################
+     # called when ctdbd wants to release an IP address
+     releaseip)
+	if [ $# != 3 ]; then
+	   echo "must supply interface, IP and maskbits"
+	   exit 1
+	fi
+	iface=$1
+	ip=$2
+	maskbits=$3
+	[ `id -u` = 0 ] && {
+	    /sbin/ip addr del $ip/$maskbits dev $iface || {
+		echo "Failed to del $ip on dev $iface"
+		exit 1
+	    }
+	}
+	echo "ctdb takeip event for $1 $2 $3"
+	exit 0
+	;;
+
+     updateip)
+	echo "ctdb updateip event for $1"
+	exit 0
+	;;
+
+     recovered)
+	echo "ctdb recovered event"
+	exit 0
+	;;
+
+     ipreallocated)
+	echo "ctdb ipreallocated event"
+	exit 0
+	;;
+
+
+     shutdown)
+	echo "ctdb shutdown event"
+	exit 0
+	;;
+
+     stopped)
+	echo "ctdb stopped event"
+	exit 0
+	;;
+esac
+
+echo "Invalid command $cmd"
+exit 1


Property changes on: branches/ctdb/squeeze-backports/tests/events.d/00.test
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/README
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,43 @@
+eventscript unit tests
+======================
+
+This directory contains some eventscript unit tests for CTDB.  These
+tests can be run as a non-privileged user.  There are a lot of stub
+implementations of commands (located in bin/) used to make the
+eventscripts think they're running against a real system.
+
+Examples:
+
+* ./run_tests.sh
+
+  Run all tests, displaying minimal output.
+
+* ./run_tests.sh -s
+
+  Run all tests, displaying minimal output and a summary.
+
+* ./run_tests.sh  -s simple/*.sh
+
+  Run all the tests in the simple/ subdirectory.
+
+* ./run_tests.sh -v -s
+
+  Run all tests, displaying extra output and a summary.
+
+* ./run_tests.sh -sq
+
+  Run all tests, displaying only a summary.
+
+* EVENTSCRIPTS_TESTS_TRACE="sh -x" \
+    ./run_tests.sh simple/10.interface.startup.002.sh
+
+  Run a test and have the eventscript itself run with "sh -x".  This
+  will usually make a test fail because the (undesirable) trace output
+  will be included with the output of the eventscript.  However, this
+  is useful for finding out why a test might be failing.  You can just
+  drop the "-x" (minimal command-line editing) to see if changes have
+  made a test pass.
+
+The simple/ subdirectory contains tests that exercise only a single
+eventscript.  Another directory containing tests that exercise
+interactions between eventscripts is coming soon...  :-)

Added: branches/ctdb/squeeze-backports/tests/eventscripts/common.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/common.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/common.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,845 @@
+# Hey Emacs, this is a -*- shell-script -*- !!!  :-)
+
+# Print a message and exit.
+die () { echo "$@" >&2 ; exit 1 ; }
+
+# Augment PATH with relevant stubs/ directories.  We do this by actually
+# setting PATH, and also by setting $EVENTSCRIPTS_PATH and then
+# prepending that to $PATH in rc.local to avoid the PATH reset in
+# functions.
+
+EVENTSCRIPTS_PATH=""
+
+if [ -d "${EVENTSCRIPTS_TESTS_DIR}/stubs" ] ; then
+    EVENTSCRIPTS_PATH="${EVENTSCRIPTS_TESTS_DIR}/stubs"
+fi
+
+export EVENTSCRIPTS_TESTCASE_DIR=$(dirname "$0")
+if [ $(basename "$EVENTSCRIPTS_TESTCASE_DIR") = "eventscripts" ] ; then
+    # Just a test script, no testcase subdirectory.
+    EVENTSCRIPTS_TESTCASE_DIR="$EVENTSCRIPTS_TESTS_DIR"
+else
+    if [ -d "${EVENTSCRIPTS_TESTCASE_DIR}/stubs" ] ; then
+	EVENTSCRIPTS_PATH="${EVENTSCRIPTS_TESTCASE_DIR}/stubs:${EVENTSCRIPTS_PATH}"
+    fi
+fi
+
+export EVENTSCRIPTS_PATH
+
+PATH="${EVENTSCRIPTS_PATH}:${PATH}"
+
+if [ -d "${EVENTSCRIPTS_TESTCASE_DIR}/etc" ] ; then
+    CTDB_ETCDIR="${EVENTSCRIPTS_TESTCASE_DIR}/etc"
+elif [ -d "${EVENTSCRIPTS_TESTS_DIR}/etc" ] ; then
+    CTDB_ETCDIR="${EVENTSCRIPTS_TESTS_DIR}/etc"
+else
+    die "Unable to set \$CTDB_ETCDIR"
+fi
+export CTDB_ETCDIR
+
+if [ -d "${EVENTSCRIPTS_TESTCASE_DIR}/etc-ctdb" ] ; then
+    CTDB_BASE="${EVENTSCRIPTS_TESTCASE_DIR}/etc-ctdb"
+elif [ -d "${EVENTSCRIPTS_TESTCASE_DIR}/etc/ctdb" ] ; then
+    CTDB_BASE="${EVENTSCRIPTS_TESTCASE_DIR}/etc/ctdb"
+elif [ -d "${EVENTSCRIPTS_TESTS_DIR}/etc-ctdb" ] ; then
+    CTDB_BASE="${EVENTSCRIPTS_TESTS_DIR}/etc-ctdb"
+else
+    die "Unable to set \$CTDB_BASE"
+fi
+export CTDB_BASE
+
+export EVENTSCRIPTS_TESTS_VAR_DIR="${EVENTSCRIPTS_TESTS_DIR}/var"
+if [ "$EVENTSCRIPTS_TESTS_VAR_DIR" != "/var" ] ; then
+    rm -r "$EVENTSCRIPTS_TESTS_VAR_DIR"
+fi
+mkdir -p "$EVENTSCRIPTS_TESTS_VAR_DIR"
+export CTDB_VARDIR="$EVENTSCRIPTS_TESTS_VAR_DIR/ctdb"
+
+######################################################################
+
+if [ "$EVENTSCRIPT_TESTS_VERBOSE" = "yes" ] ; then
+    debug () { echo "$@" ; }
+else
+    debug () { : ; }
+fi
+
+eventscripts_tests_cleanup_hooks=""
+
+# This loses quoting!
+eventscripts_test_add_cleanup ()
+{
+    eventscripts_tests_cleanup_hooks="${eventscripts_tests_cleanup_hooks}${eventscripts_tests_cleanup_hooks:+ ; }$*"
+}
+
+trap 'eval $eventscripts_tests_cleanup_hooks' 0
+
+
+######################################################################
+
+# General setup fakery
+
+setup_generic ()
+{
+    debug "Setting up shares (3 existing shares)"
+    # Create 3 fake shares/exports.
+    export FAKE_SHARES=""
+    for i in $(seq 1 3) ; do
+	_s="${EVENTSCRIPTS_TESTS_VAR_DIR}/shares/${i}_existing"
+	mkdir -p "$_s"
+	FAKE_SHARES="${FAKE_SHARES}${FAKE_SHARES:+ }${_s}"
+    done
+
+    export FAKE_PROC_NET_BONDING="$EVENTSCRIPTS_TESTS_VAR_DIR/proc-net-bonding"
+    mkdir -p "$FAKE_PROC_NET_BONDING"
+    rm -f "$FAKE_PROC_NET_BONDING"/*
+
+    export FAKE_ETHTOOL_LINK_DOWN="$EVENTSCRIPTS_TESTS_VAR_DIR/ethtool-link-down"
+    mkdir -p "$FAKE_ETHTOOL_LINK_DOWN"
+    rm -f "$FAKE_ETHTOOL_LINK_DOWN"/*
+
+    # This can only have 2 levels.  We don't want to resort to usings
+    # something dangerous like "rm -r" setup time.
+    export FAKE_IP_STATE="$EVENTSCRIPTS_TESTS_VAR_DIR/fake-ip-state"
+    mkdir -p "$FAKE_IP_STATE"
+    rm -f "$FAKE_IP_STATE"/*/*
+    rm -f "$FAKE_IP_STATE"/* 2>/dev/null || true
+    rmdir "$FAKE_IP_STATE"/* 2>/dev/null || true
+}
+
+tcp_port_down ()
+{
+    for _i ; do
+	debug "Marking TCP port \"${_i}\" as not listening"
+	FAKE_TCP_LISTEN=$(echo "$FAKE_TCP_LISTEN" | sed -r -e "s@[[:space:]]*[\.0-9]+:${_i}@@g")
+    done
+}
+
+shares_missing ()
+{
+    _fmt="$1" ; shift
+
+    # Replace some shares with non-existent ones.
+    _t=""
+    _n=1
+    _nl="
+"
+    export MISSING_SHARES_TEXT=""
+    for _i in $FAKE_SHARES ; do
+	if [ $_n = "$1" ] ; then
+	    shift
+	    _i="${_i%_existing}_missing"
+	    debug "Replacing share $_n with missing share \"$_i\""
+	    rmdir "$_i" 2>/dev/null || true
+	    MISSING_SHARES_TEXT="${MISSING_SHARES_TEXT}${MISSING_SHARES_TEXT:+${_nl}}"$(printf "$_fmt" "${_i}")
+	fi
+	_t="${_t}${_t:+ }${_i}"
+	_n=$(($_n + 1))
+    done
+    FAKE_SHARES="$_t"
+}
+
+# Setup some fake /proc/net/bonding files with just enough info for
+# the eventscripts.
+
+# arg1 is interface name, arg2 is currently active slave (use "None"
+# if none), arg3 is MII status ("up" or "down").
+setup_bond ()
+{
+    _iface="$1"
+    _slave="${2:-${_iface}_sl_0}"
+    _mii_s="${3:-up}"
+    _mii_subs="${4:-${_mii_s:-up}}"
+    echo "Setting $_iface to be a bond with active slave $_slave and MII status $_mii_s"
+    cat >"${FAKE_PROC_NET_BONDING}/$_iface" <<EOF
+Bonding Mode: IEEE 802.3ad Dynamic link aggregation
+Currently Active Slave: $_slave
+# Status of the bond
+MII Status: $_mii_s
+# Status of 1st pretend adapter
+MII Status: $_mii_subs
+# Status of 2nd pretend adapter
+MII Status: $_mii_subs
+EOF
+}
+
+ethtool_interfaces_down ()
+{
+    for _i ; do
+	echo "Marking interface $_i DOWN for ethtool"
+	touch "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
+    done
+}
+
+ethtool_interfaces_up ()
+{
+    for _i ; do
+	echo "Marking interface $_i UP for ethtool"
+	rm -f "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
+    done
+}
+
+setup_nmap_output_filter ()
+{
+    OUT_FILTER="-e 's@^(DEBUG: # Nmap 5.21 scan initiated) .+ (as:)@\1 DATE \2@' -e 's@^(DEBUG: # Nmap done at) .+ (--)@\1 DATE \2@'"
+}
+
+######################################################################
+
+# CTDB fakery
+
+# Evaluate an expression that probably calls functions or uses
+# variables from the CTDB functions file.  This is used for test
+# initialisation.
+eventscript_call ()
+{
+    (
+	. "$CTDB_BASE/functions"
+	"$@"
+    )
+}
+
+# Set output for ctdb command.  Option 1st argument is return code.
+ctdb_set_output ()
+{
+    _out="$EVENTSCRIPTS_TESTS_VAR_DIR/ctdb.out"
+    cat >"$_out"
+
+    _rc="$EVENTSCRIPTS_TESTS_VAR_DIR/ctdb.rc"
+    echo "${1:-0}" >"$_rc"
+
+    eventscripts_test_add_cleanup "rm -f $_out $_rc"
+}
+
+setup_ctdb ()
+{
+    setup_generic
+
+    export FAKE_CTDB_NUMNODES="${1:-3}"
+    echo "Setting up CTDB with ${FAKE_CTDB_NUMNODES} fake nodes"
+
+    export FAKE_CTDB_PNN="${2:-0}"
+    echo "Setting up CTDB with PNN ${FAKE_CTDB_PNN}"
+
+    if [ -n "$3" ] ; then
+	echo "Setting up CTDB_PUBLIC_ADDRESSES: $3"
+	export CTDB_PUBLIC_ADDRESSES=$(mktemp)
+	for _i in $3 ; do
+	    _ip="${_i%@*}"
+	    _ifaces="${_i#*@}"
+	    echo "${_ip} ${_ifaces}" >>"$CTDB_PUBLIC_ADDRESSES"
+	done
+	eventscripts_test_add_cleanup "rm -f $CTDB_PUBLIC_ADDRESSES"
+    fi
+
+    export FAKE_CTDB_IFACES_DOWN="$EVENTSCRIPTS_TESTS_VAR_DIR/fake-ctdb/ifaces-down"
+    mkdir -p "$FAKE_CTDB_IFACES_DOWN"
+    rm -f "$FAKE_CTDB_IFACES_DOWN"/*
+
+    export FAKE_CTDB_NODES_DOWN="$EVENTSCRIPTS_TESTS_VAR_DIR/nodes-down"
+    mkdir -p "$FAKE_CTDB_NODES_DOWN"
+    rm -f "$FAKE_CTDB_NODES_DOWN"/*
+
+    export FAKE_CTDB_SCRIPTSTATUS="$EVENTSCRIPTS_TESTS_VAR_DIR/scriptstatus"
+    mkdir -p "$FAKE_CTDB_SCRIPTSTATUS"
+    rm -f "$FAKE_CTDB_SCRIPTSTATUS"/*
+}
+
+
+
+ctdb_nodes_up ()
+{
+    for _i ; do
+	rm -f "${FAKE_CTDB_NODES_DOWN}/${_i}"
+    done
+}
+
+ctdb_nodes_down ()
+{
+    for _i ; do
+	touch "${FAKE_CTDB_NODES_DOWN}/${_i}"
+    done
+}
+
+ctdb_get_interfaces ()
+{
+    # The echo/subshell forces all the output onto 1 line.
+    echo $(ctdb ifaces -Y | awk -F: 'FNR > 1 {print $2}')
+}
+
+ctdb_get_1_interface ()
+{
+    _t=$(ctdb_get_interfaces)
+    echo ${_t%% *}
+}
+
+ctdb_get_public_addresses ()
+{
+    _f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}"
+    echo $(if [ -r "$_f" ] ; then 
+	while read _ip _iface ; do
+	    echo "${_ip}@${_iface}"
+	done <"$_f"
+	fi)
+}
+
+# Prints the 1st public address as: interface IP maskbits
+# This is suitable for passing to 10.interfaces takeip/releaseip
+ctdb_get_1_public_address ()
+{
+    _addrs=$(ctdb_get_public_addresses)
+    echo "${_addrs%% *}" | sed -r -e 's#(.*)/(.*)@(.*)#\3 \1 \2#g'
+}
+
+ctdb_not_implemented ()
+{
+    export CTDB_NOT_IMPLEMENTED="$1"
+    ctdb_not_implemented="\
+DEBUG: ctdb: command \"$1\" not implemented in stub"
+}
+
+ctdb_fake_scriptstatus ()
+{
+    _code="$1"
+    _status="$2"
+    _err_out="$3"
+
+    _d1=$(date '+%s.%N')
+    _d2=$(date '+%s.%N')
+
+    echo "$_code $_status $_err_out" >"$FAKE_CTDB_SCRIPTSTATUS/$script"
+}
+
+######################################################################
+
+# Samba fakery
+
+setup_samba ()
+{
+    setup_ctdb
+
+    if [ "$1" != "down" ] ; then
+
+	debug "Marking Samba services as up, listening and managed by CTDB"
+        # Get into known state.
+	for i in "samba" "winbind" ; do
+	    eventscript_call ctdb_service_managed "$i"
+	done
+        # All possible service names for all known distros.
+	for i in "smb" "nmb" "winbind" "samba" ; do
+	    service "$i" force-started
+	done
+
+	export CTDB_SAMBA_SKIP_SHARE_CHECK="no"
+	export CTDB_MANAGED_SERVICES="foo samba winbind bar"
+
+	export FAKE_TCP_LISTEN="0.0.0.0:445 0.0.0.0:139"
+	export FAKE_WBINFO_FAIL="no"
+
+	# Some things in 50.samba are backgrounded and waited for.  If
+	# we don't sleep at all then timeouts can happen.  This avoids
+	# that...  :-)
+	export FAKE_SLEEP_FORCE=0.1
+    else
+	debug "Marking Samba services as down, not listening and not managed by CTDB"
+        # Get into known state.
+	for i in "samba" "winbind" ; do
+	    eventscript_call ctdb_service_unmanaged "$i"
+	done
+        # All possible service names for all known distros.
+	for i in "smb" "nmb" "winbind" "samba" ; do
+	    service "$i" force-stopped
+	done
+
+	export CTDB_SAMBA_SKIP_SHARE_CHECK="no"
+	export CTDB_MANAGED_SERVICES="foo bar"
+	unset CTDB_MANAGES_SAMBA
+	unset CTDB_MANAGES_WINBIND
+
+	export FAKE_TCP_LISTEN=""
+	export FAKE_WBINFO_FAIL="yes"
+    fi
+
+    # This is ugly but if this file isn't removed before each test
+    # then configuration changes between tests don't stick.
+    rm -f "$CTDB_VARDIR/state/samba/smb.conf.cache"
+}
+
+wbinfo_down ()
+{
+    debug "Making wbinfo commands fail"
+    FAKE_WBINFO_FAIL="yes"
+}
+
+######################################################################
+
+# NFS fakery
+
+setup_nfs ()
+{
+    setup_ctdb
+
+    export FAKE_RPCINFO_SERVICES=""
+
+    export CTDB_NFS_SKIP_SHARE_CHECK="no"
+    export CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK="no"
+
+    # Reset the failcounts for nfs services.
+    eventscript_call eval rm -f '$ctdb_fail_dir/nfs_*'
+
+    rpc_fail_limits_file="${EVENTSCRIPTS_TESTS_VAR_DIR}/rpc_fail_limits"
+
+    # Force this file to exist so tests can be individually run.
+    if [ ! -f "$rpc_fail_limits_file" ] ; then
+	# This is gross... but is needed to fake through the nfs monitor event.
+	eventscript_call ctdb_service_managed "nfs"
+	service "nfs" force-started  # might not be enough
+	CTDB_RC_LOCAL="$CTDB_BASE/rc.local.nfs.monitor.get-limits" \
+	    CTDB_MANAGES_NFS="yes" \
+	    "${CTDB_BASE}/events.d/60.nfs" "monitor" >"$rpc_fail_limits_file"
+    fi
+    
+    if [ "$1" != "down" ] ; then
+	debug "Setting up NFS environment: all RPC services up, NFS managed by CTDB"
+
+	eventscript_call ctdb_service_managed "nfs"
+	service "nfs" force-started  # might not be enough
+
+	export CTDB_MANAGED_SERVICES="foo nfs bar"
+
+	rpc_services_up "nfs" "mountd" "rquotad" "nlockmgr" "status"
+    else
+	debug "Setting up NFS environment: all RPC services down, NFS not managed by CTDB"
+
+	eventscript_call ctdb_service_unmanaged "nfs"
+	service "nfs" force-stopped  # might not be enough
+	eventscript_call startstop_nfs stop
+
+	export CTDB_MANAGED_SERVICES="foo bar"
+	unset CTDB_MANAGES_NFS
+    fi
+}
+
+rpc_services_down ()
+{
+    for _i ; do
+	debug "Marking RPC service \"${_i}\" as unavailable"
+	FAKE_RPCINFO_SERVICES=$(echo "$FAKE_RPCINFO_SERVICES" | sed -r -e "s@[[:space:]]*${_i}:[0-9]+:[0-9]+@@g")
+    done
+}
+
+rpc_services_up ()
+{
+    for _i ; do
+	debug "Marking RPC service \"${_i}\" as available"
+	case "$_i" in
+	    nfs)      _t="2:3" ;;
+	    mountd)   _t="1:3" ;;
+	    rquotad)  _t="1:2" ;;
+	    nlockmgr) _t="3:4" ;;
+	    status)   _t="1:1" ;;
+	    *) die "Internal error - unsupported RPC service \"${_i}\"" ;;
+	esac
+
+	FAKE_RPCINFO_SERVICES="${FAKE_RPCINFO_SERVICES}${FAKE_RPCINFO_SERVICES:+ }${_i}:${_t}"
+    done
+}
+
+# Set the required result for a particular RPC program having failed
+# for a certain number of iterations.  This is probably still a work
+# in progress.  Note that we could hook aggressively
+# nfs_check_rpc_service() to try to implement this but we're better
+# off testing nfs_check_rpc_service() using independent code...  even
+# if it is incomplete and hacky.  So, if the 60.nfs eventscript
+# changes and the tests start to fail then it may be due to this
+# function being incomplete.
+rpc_set_service_failure_response ()
+{
+    _progname="$1"
+    # The number of failures defaults to the iteration number.  This
+    # will be true when we fail from the 1st iteration... but we need
+    # the flexibility to set the number of failures.
+    _numfails="${2:-${iteration}}"
+
+    _c="${CTDB_ETCDIR}/sysconfig/nfs"
+    if [ -r "$_c" ] ; then
+	. "$_c"
+    fi
+
+    # A handy newline.  :-)
+    _nl="
+"
+
+    # Default
+    ok_null
+
+    _ts=$(sed -n -e "s@^${_progname} @@p" "$rpc_fail_limits_file")
+
+    while [ -n "$_ts" ] ; do
+	# Get the triple: operator, fail limit and actions.
+	_op="${_ts%% *}" ; _ts="${_ts#* }"
+	_li="${_ts%% *}" ; _ts="${_ts#* }"
+	# We've lost some of the quoting but we can simulate
+	# because we know an operator is always the first in a
+	# triple.
+  	_actions=""
+	while [ -n "$_ts" ] ; do
+	    # If this is an operator then we've got all of the
+	    # actions.
+	    case "$_ts" in
+		-*) break ;;
+	    esac
+
+	    _actions="${_actions}${_actions:+ }${_ts%% *}"
+	    # Special case for end of list.
+	    if [ "$_ts" != "${_ts#* }" ] ; then
+		_ts="${_ts#* }"
+	    else
+		_ts=""
+	    fi
+	done
+
+	if [ "$_numfails" "$_op" "$_li" ] ; then
+	    _out=""
+	    _rc=0
+	    for _action in $_actions ; do
+		case "$_action" in
+		    verbose)
+			_ver=1
+			_pn="$_progname"
+			case "$_progname" in
+			    knfsd) _ver=3 ; _pn="nfs" ;;
+			    lockd) _ver=4 ; _pn="nlockmgr" ;;
+			    statd) _pn="status" ;;
+			esac
+			_out="\
+ERROR: $_pn failed RPC check:
+rpcinfo: RPC: Program not registered
+program $_pn version $_ver is not available"
+			;;
+		    restart|restart:*)
+			_opts=""
+			_p="rpc.${_progname}"
+			case "$_progname" in
+			    statd)
+				_opts="${STATD_HOSTNAME:+ -n }${STATD_HOSTNAME}"
+				;;
+			esac
+			case "${_progname}${_action#restart}" in
+			    knfsd)
+				_t="\
+Trying to restart NFS service
+Starting nfslock: OK
+Starting nfs: OK"
+				;;
+			    knfsd:bs)
+				_t="Trying to restart NFS service"
+				;;
+			    lockd)
+				_t="\
+Trying to restart lock manager service
+Stopping nfslock: OK
+Starting nfslock: OK"
+				;;
+			    lockd:*)
+				_t="Trying to restart lock manager service"
+				;;
+			    *)
+				_t="Trying to restart $_progname [${_p}${_opts}]"
+			esac
+			_out="${_out}${_out:+${_nl}}${_t}"
+			;;
+		    unhealthy)
+			_rc=1
+		esac
+	    done
+	    required_result $_rc "$_out"
+	    return
+	fi
+    done
+}
+
+######################################################################
+
+# VSFTPD fakery
+
+setup_vsftpd ()
+{
+    if [ "$1" != "down" ] ; then
+	die "setup_vsftpd up not implemented!!!"
+    else
+	debug "Setting up VSFTPD environment: service down, not managed by CTDB"
+
+	eventscript_call ctdb_service_unmanaged vsftpd
+	service vsftpd force-stopped
+
+	export CTDB_MANAGED_SERVICES="foo"
+	unset CTDB_MANAGES_VSFTPD
+    fi
+}
+
+######################################################################
+
+# HTTPD fakery
+
+setup_httpd ()
+{
+    if [ "$1" != "down" ] ; then
+	die "setup_httpd up not implemented!!!"
+    else
+	debug "Setting up HTTPD environment: service down, not managed by CTDB"
+
+	for i in "apache2" "httpd" ; do
+	    eventscript_call ctdb_service_unmanaged "$i"
+	    service "$i" force-stopped
+	done
+
+	export CTDB_MANAGED_SERVICES="foo"
+	unset CTDB_MANAGES_HTTPD
+    fi
+}
+
+######################################################################
+
+# Result and test functions
+
+# Set some globals and print the summary.
+define_test ()
+{
+    desc="$1"
+
+    _f="$0"
+    _f="${_f#./}"          # strip leading ./
+    _f="${_f#simple/}"     # strip leading simple/
+    _f="${_f#multievent/}" # strip leading multievent/
+    _f="${_f%%/*}"         # if subdir, strip off file
+    _f="${_f%.sh}"         # strip off .sh suffix if any
+
+    # Remaining format should be NN.service.event.NNN or NN.service.NNN:
+    _num="${_f##*.}"
+    _f="${_f%.*}"
+    case "$_f" in
+	*.*.*)
+	    script="${_f%.*}"
+	    event="${_f##*.}"
+	    ;;
+	*.*)
+	    script="$_f"
+	    unset event
+	    ;;
+	*)
+	    die "Internal error - unknown testcase filename format"
+    esac
+
+    printf "%-14s %-10s %-4s - %s\n\n" "$script" "$event" "$_num" "$desc"
+}
+
+# Set the required result for a test.
+# - Argument 1 is exit code.
+# - Argument 2, if present is the required test output but "--"
+#   indicates empty output.
+# If argument 2 is not present or null then read required test output
+# from stdin.
+required_result ()
+{
+    required_rc="${1:-0}"
+    if [ -n "$2" ] ; then
+	if [ "$2" = "--" ] ; then
+	    required_output=""
+	else
+	    required_output="$2"
+	fi
+    else
+	if ! tty -s ; then
+	    required_output=$(cat)
+	else
+	    required_output=""
+	fi
+    fi
+}
+
+ok ()
+{
+    required_result 0 "$@"
+}
+
+ok_null ()
+{
+    ok --
+}
+
+result_print ()
+{
+    _passed="$1"
+    _out="$2"
+    _rc="$3"
+    _iteration="$4"
+
+    if [ "$EVENTSCRIPT_TESTS_VERBOSE" = "yes" ] || ! $_passed ; then
+	if [ -n "$_iteration" ] ; then
+	    cat <<EOF
+
+==================================================
+Iteration $_iteration
+EOF
+	fi
+
+cat <<EOF
+--------------------------------------------------
+Output (Exit status: ${_rc}):
+--------------------------------------------------
+$_out
+EOF
+    fi
+
+    if ! $_passed ; then
+	cat <<EOF
+--------------------------------------------------
+Required output (Exit status: ${required_rc}):
+--------------------------------------------------
+$required_output
+EOF
+    fi
+}
+
+result_footer ()
+{
+    _passed="$1"
+
+    if [ "$EVENTSCRIPT_TESTS_VERBOSE" = "yes" ] || ! $_passed ; then
+
+	cat <<EOF
+--------------------------------------------------
+CTDB_BASE="$CTDB_BASE"
+CTDB_ETCDIR="$CTDB_ETCDIR"
+ctdb client is "$(which ctdb)"
+--------------------------------------------------
+EOF
+    fi
+
+    if $_passed ; then
+	echo "PASSED"
+	return 0
+    else
+	echo
+	echo "FAILED"
+	return 1
+    fi
+}
+
+# Run an eventscript once.  The test passes if the return code and
+# output match those required.
+
+# Any args are passed to the eventscript.
+
+# Eventscript tracing can be done by setting:
+#   EVENTSCRIPTS_TESTS_TRACE="sh -x"
+
+# or similar.  This will almost certainly make a test fail but is
+# useful for debugging.
+simple_test ()
+{
+    [ -n "$event" ] || die 'simple_test: $event not set'
+
+    echo "Running \"$script $event${1:+ }$*\""
+    _out=$($EVENTSCRIPTS_TESTS_TRACE "${CTDB_BASE}/events.d/$script" "$event" "$@" 2>&1)
+    _rc=$?
+
+    if [ -n "$OUT_FILTER" ] ; then
+	_fout=$(echo "$_out" | eval sed -r $OUT_FILTER)
+    else
+	_fout="$_out"
+    fi
+
+    if [ "$_fout" = "$required_output" -a $_rc = $required_rc ] ; then
+	_passed=true
+    else
+	_passed=false
+    fi
+
+    result_print "$_passed" "$_out" "$_rc"
+    result_footer "$_passed"
+}
+
+simple_test_event ()
+{
+    # If something has previously failed then don't continue.
+    : ${_passed:=true}
+    $_passed || return 1
+
+    event="$1" ; shift
+    echo "##################################################"
+    simple_test "$@"
+}
+
+# Run an eventscript iteratively.
+# - 1st argument is the number of iterations.
+# - 2nd argument is something to eval to do setup for every iteration.
+#   The easiest thing to do here is to define a function and pass it
+#   here.
+# - Subsequent arguments come in pairs: an iteration number and
+#   something to eval for that iteration.  Each time an iteration
+#   number is matched the associated argument is given to eval after
+#   the default setup is done.  The iteration numbers need to be given
+#   in ascending order.
+#
+# Some optional args can be given *before* these, surrounded by extra
+# "--" args.  These args are passed to the eventscript.  Quoting is
+# lost.
+#
+# One use of the 2nd and further arguments is to call
+# required_result() to change what is expected of a particular
+# iteration.
+iterate_test ()
+{
+    [ -n "$event" ] || die 'simple_test: $event not set'
+
+    args=""
+    if [ "$1" = "--" ] ; then
+	shift
+	while [ "$1" != "--" ] ; do
+	    args="${args}${args:+ }$1"
+	    shift
+	done
+	shift
+    fi
+
+    _repeats="$1"
+    _setup_default="$2"
+    shift 2
+
+    echo "Running $_repeats iterations of \"$script $event\" $args"
+
+    _result=true
+
+    for iteration in $(seq 1 $_repeats) ; do
+	# This is inefficient because the iteration-specific setup
+	# might completely replace the default one.  However, running
+	# the default is good because it allows you to revert to a
+	# particular result without needing to specify it explicitly.
+	eval $_setup_default
+	if [ $iteration = "$1" ] ; then
+	    eval $2
+	    shift 2
+	fi
+
+	_out=$($EVENTSCRIPTS_TESTS_TRACE "${CTDB_BASE}/events.d/$script" "$event" $args 2>&1)
+	_rc=$?
+
+    if [ -n "$OUT_FILTER" ] ; then
+	_fout=$(echo "$_out" | eval sed -r $OUT_FILTER)
+    else
+	_fout="$_out"
+    fi
+
+	if [ "$_fout" = "$required_output" -a $_rc = $required_rc ] ; then
+	    _passed=true
+	else
+	    _passed=false
+	    _result=false
+	fi
+
+	result_print "$_passed" "$_out" "$_rc" "$iteration"
+    done
+
+    result_footer "$_result"
+}

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfs
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfs	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfs	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# This is not used.  The fake "service" script is used instead.  This
+# is only needed to shut up functions like startstop_nfs(), which look
+# for this script.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfs
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfslock
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfslock	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfslock	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# This is not used.  The fake "service" script is used instead.  This
+# is only needed to shut up functions like startstop_nfs(), which look
+# for this script.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc/init.d/nfslock
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc/samba/smb.conf
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc/samba/smb.conf	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc/samba/smb.conf	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,42 @@
+[global]
+	# enable clustering
+	clustering=yes
+	ctdb:registry.tdb=yes
+
+	security = ADS
+	auth methods = guest sam winbind
+
+	netbios name = cluster1
+	workgroup = CLUSTER1
+	realm = CLUSTER1.COM
+	server string = "Clustered Samba"
+	disable netbios = yes
+	disable spoolss = yes
+	fileid:mapping = fsname
+	use mmap = yes
+	gpfs:sharemodes = yes
+	gpfs:leases = yes
+	passdb backend = tdbsam
+	preferred master = no
+	kernel oplocks = yes
+	syslog = 1
+	host msdfs = no
+	notify:inotify = no
+	vfs objects = shadow_copy2 syncops gpfs fileid
+	shadow:snapdir = .snapshots
+	shadow:fixinodes = yes
+	wide links = no
+	smbd:backgroundqueue = False
+	read only = no
+	use sendfile = yes
+	strict locking = yes
+	posix locking = yes
+	large readwrite = yes
+	force unknown acl user = yes
+	nfs4:mode = special
+	nfs4:chown = yes
+	nfs4:acedup = merge
+	nfs4:sidmap = /etc/samba/sidmap.tdb
+	map readonly = no
+	ea support = yes
+	dmapi support = no

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/ctdb
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/ctdb	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/ctdb	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+link ../../../../config/ctdb.sysconfig
\ No newline at end of file


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/ctdb
___________________________________________________________________
Added: svn:special
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/nfs
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/nfs	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc/sysconfig/nfs	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,2 @@
+NFS_HOSTNAME="cluster1"
+STATD_HOSTNAME="$NFS_HOSTNAME -H /etc/ctdb/statd-callout "

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/events.d
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/events.d	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/events.d	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+link ../../../config/events.d
\ No newline at end of file


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/events.d
___________________________________________________________________
Added: svn:special
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/functions
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/functions	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/functions	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+link ../../../config/functions
\ No newline at end of file


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/functions
___________________________________________________________________
Added: svn:special
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/interface_modify.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/interface_modify.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/interface_modify.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1 @@
+link ../../../config/interface_modify.sh
\ No newline at end of file


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/interface_modify.sh
___________________________________________________________________
Added: svn:special
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/public_addresses
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/public_addresses	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/public_addresses	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,4 @@
+10.0.0.1/24 dev123
+10.0.0.2/24 dev123
+10.0.1.1/24 dev456
+10.0.1.2/24 dev456

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,46 @@
+# Hey Emacs, this is a -*- shell-script -*- !!!  :-)
+
+# Use a "service" command in $PATH if one exists.
+service ()
+{
+    if _t=$(which "service" 2>/dev/null) ; then
+	"$_t" "$@"
+    else
+	_nice=""
+	_service "$@"
+    fi
+}
+
+nice_service ()
+{
+    if _t=$(which "service" 2>/dev/null) ; then
+	nice "$_t" "$@"
+    else
+	_nice="nice"
+	_service "$@"
+    fi
+}
+
+# Always succeeds
+set_proc () { : ; }
+
+get_proc ()
+{
+    case "$1" in
+	net/bonding/*)
+	    cat "$FAKE_PROC_NET_BONDING/${1##*/}"
+	    ;;
+	sys/net/ipv4/conf/all/arp_filter)
+	    echo 1
+	    ;;
+	*)
+	    echo "get_proc: \"$1\" not implemented"
+	    exit 1
+    esac
+}
+
+# Always succeeds
+iptables () { : ; }
+
+CTDB_INIT_STYLE="redhat"
+PATH="${EVENTSCRIPTS_PATH}:$PATH"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local.nfs.monitor.get-limits
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local.nfs.monitor.get-limits	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local.nfs.monitor.get-limits	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,25 @@
+# Hey Emacs, this is a -*- shell-script -*- !!!  :-)
+
+# This scripts nobble the 60.nfs monitor event so that it prints out
+# the service fail limits for each RPC service.
+
+CTDB_INIT_STYLE="redhat"
+PATH="${EVENTSCRIPTS_PATH}:$PATH"
+
+service () { : ; }
+
+update_tickles () { : ; }
+
+ctdb_setup_service_state_dir "nfs"
+
+CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK="no"
+CTDB_NFS_SKIP_SHARE_CHECK="yes"
+
+# Ugly but necessary - if this file was touched less then 60 seconds
+# ago then this skips some code.
+touch "$service_state_dir/update-trigger"
+
+nfs_check_rpc_service ()
+{
+    echo "$*"
+}


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/rc.local.nfs.monitor.get-limits
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/statd-callout
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/statd-callout	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/statd-callout	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# For now, always succeed.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/etc-ctdb/statd-callout
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/10.interface.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/multievent/10.interface.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/multievent/10.interface.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "takeip, removeip"
+
+setup_ctdb
+
+public_address=$(ctdb_get_1_public_address)
+
+ok_null
+
+simple_test_event "takeip" $public_address
+simple_test_event "releaseip" $public_address


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/10.interface.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "takeip, ipreallocated -> reconfigure"
+
+setup_nfs
+
+public_address=$(ctdb_get_1_public_address)
+
+ok_null
+
+simple_test_event "takeip" $public_address
+
+ok <<EOF
+Reconfiguring service "nfs"...
+Starting nfslock: OK
+Starting nfs: OK
+EOF
+
+simple_test_event "ipreallocated"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "takeip, monitor -> reconfigure"
+
+setup_nfs
+
+public_address=$(ctdb_get_1_public_address)
+
+ok_null
+
+simple_test_event "takeip" $public_address
+
+# This currently assumes that ctdb scriptstatus will always return a
+# good status (when replaying).  That should change and we will need
+# to split this into 2 tests.
+ok <<EOF
+Reconfiguring service "nfs"...
+Starting nfslock: OK
+Starting nfs: OK
+Replaying previous status for this script due to reconfigure...
+EOF
+
+simple_test_event "monitor"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.003.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.003.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.003.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "takeip, monitor -> reconfigure, replay error"
+
+setup_nfs
+
+public_address=$(ctdb_get_1_public_address)
+
+err="foo: bar error occurred"
+
+ok_null
+
+simple_test_event "takeip" $public_address
+
+ctdb_fake_scriptstatus 1 "ERROR" "$err"
+
+required_result 1 <<EOF
+Reconfiguring service "nfs"...
+Starting nfslock: OK
+Starting nfs: OK
+Replaying previous status for this script due to reconfigure...
+$err
+EOF
+
+simple_test_event "monitor"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.003.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.004.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.004.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.004.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "takeip, monitor -> reconfigure, replay timedout"
+
+setup_nfs
+
+public_address=$(ctdb_get_1_public_address)
+
+err="waiting, waiting..."
+
+ok_null
+
+simple_test_event "takeip" $public_address
+
+ctdb_fake_scriptstatus -62 "TIMEDOUT" "$err"
+
+required_result 1 <<EOF
+Reconfiguring service "nfs"...
+Starting nfslock: OK
+Starting nfs: OK
+Replaying previous status for this script due to reconfigure...
+[Replay of TIMEDOUT scriptstatus - note incorrect return code.] $err
+EOF
+
+simple_test_event "monitor"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.004.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.005.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.005.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.005.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "takeip, monitor -> reconfigure, replay disabled"
+
+setup_nfs
+
+public_address=$(ctdb_get_1_public_address)
+
+err=""
+
+ok_null
+
+simple_test_event "takeip" $public_address
+
+ctdb_fake_scriptstatus -8 "DISABLED" "$err"
+
+ok <<EOF
+Reconfiguring service "nfs"...
+Starting nfslock: OK
+Starting nfs: OK
+Replaying previous status for this script due to reconfigure...
+[Replay of DISABLED scriptstatus - note incorrect return code.] $err
+EOF
+
+simple_test_event "monitor"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.005.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.006.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.006.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.006.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "reconfigure (synthetic), twice"
+# This checks that the lock is released...
+
+setup_nfs
+
+public_address=$(ctdb_get_1_public_address)
+
+err=""
+
+ok <<EOF
+Reconfiguring service "nfs"...
+Starting nfslock: OK
+Starting nfs: OK
+EOF
+
+simple_test_event "reconfigure"
+simple_test_event "reconfigure"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/multievent/60.nfs.006.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/run_tests.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/run_tests.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/run_tests.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+# Eventscript unit test harness.
+
+cd $(dirname "$0")
+export EVENTSCRIPTS_TESTS_DIR=$(pwd)
+
+test_dir=$(dirname "$EVENTSCRIPTS_TESTS_DIR")
+
+opts="-d"
+
+for i ; do
+    case "$i" in
+	-v)
+	    export EVENTSCRIPT_TESTS_VERBOSE="yes"
+	    shift
+	    ;;
+	-T)
+	    # This will cause tests to fail but is good for debugging
+	    # individual tests when they fail.
+	    export EVENTSCRIPTS_TESTS_TRACE="sh -x"
+	    shift
+	    ;;
+	-*)
+	    opts="$opts $i"
+	    shift
+	    ;;
+	*)
+	    break
+    esac
+done
+
+tests=""
+if [ -z "$*" ] ; then
+    tests=$(ls simple/[0-9][0-9].*.*.[0-9][0-9][0-9].sh simple/[0-9][0-9].*.*.[0-9][0-9][0-9]/run_test.sh 2>/dev/null)
+fi
+
+"$test_dir/scripts/run_tests" $opts "$@" $tests || exit 1
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/run_tests.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "no public addresses"
+
+setup_ctdb
+
+export CTDB_PUBLIC_ADDRESSES="$CTDB_ETC/does/not/exist"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "all interfaces up"
+
+setup_ctdb
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.init.002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "no public addresses"
+
+setup_ctdb
+
+export CTDB_PUBLIC_ADDRESSES="$CTDB_ETC/does/not/exist"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "all interfaces up"
+
+setup_ctdb
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.003.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.003.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.003.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "1 interface down"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+ethtool_interfaces_down $iface
+
+required_result 1 "ERROR: No link on the public network interface $iface"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.003.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.004.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.004.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.004.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "all interfaces up, 1 is a bond"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+setup_bond $iface
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.004.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.005.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.005.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.005.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "1 bond, no active slaves"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+setup_bond $iface "None"
+
+required_result 1 "ERROR: No active slaves for bond device $iface"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.005.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.006.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.006.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.006.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "1 bond, active slaves, link down"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+setup_bond $iface "" "down"
+
+required_result 1 "ERROR: public network interface $iface is down"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.006.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.007.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.007.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.007.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "unknown interface, up"
+
+setup_ctdb
+
+export CTDB_PUBLIC_INTERFACE="dev999"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.007.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.008.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.008.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.008.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "unknown interface, down, up"
+
+setup_ctdb
+
+iface="dev999"
+export CTDB_PUBLIC_INTERFACE="$iface"
+
+#EVENTSCRIPTS_TESTS_TRACE="sh -x"
+iterate_test 3 "ok_null" \
+    1 'ethtool_interfaces_down "$iface" ; required_result 1 "ERROR: No link on the public network interface $iface"' \
+    2 'ethtool_interfaces_up "$iface"'


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.008.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.009.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.009.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.009.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "CTDB_PARTIALLY_ONLINE_INTERFACES, 1 down"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+export CTDB_PARTIALLY_ONLINE_INTERFACES="yes"
+
+ethtool_interfaces_down "$iface"
+
+ok "ERROR: No link on the public network interface $iface"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.009.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.010.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.010.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.010.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "CTDB_PARTIALLY_ONLINE_INTERFACES, all down"
+
+setup_ctdb
+
+ifaces=$(ctdb_get_interfaces)
+
+export CTDB_PARTIALLY_ONLINE_INTERFACES="yes"
+
+ethtool_interfaces_down $ifaces
+
+msg=$(for i in $ifaces ; do echo "ERROR: No link on the public network interface $i" ; done)
+
+required_result 1 "$msg"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.010.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.011.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.011.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.011.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "CTDB_PARTIALLY_ONLINE_INTERFACES, 1 bond down"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+setup_bond $iface "None"
+
+export CTDB_PARTIALLY_ONLINE_INTERFACES="yes"
+
+ethtool_interfaces_down "$iface"
+
+ok "ERROR: No active slaves for bond device $iface"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.011.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.012.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.012.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.012.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "CTDB_PARTIALLY_ONLINE_INTERFACES, 1 bond down"
+
+setup_ctdb
+
+ifaces=$(ctdb_get_interfaces)
+
+for i in $ifaces ; do
+    setup_bond $i "None"
+done
+
+export CTDB_PARTIALLY_ONLINE_INTERFACES="yes"
+
+ethtool_interfaces_down $ifaces
+
+msg=$(for i in $ifaces ; do echo "ERROR: No active slaves for bond device $i" ; done)
+
+required_result 1 "$msg"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.012.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.013.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.013.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.013.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "1 bond, active slaves, link down"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+setup_bond $iface "" "up" "down"
+
+required_result 1 "ERROR: No active slaves for 802.ad bond device $iface"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.monitor.013.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "error - no args given"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+required_result 1 "ERROR: must supply interface, IP and maskbits"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "error - remove a non-existent ip"
+
+setup_ctdb
+
+public_address=$(ctdb_get_1_public_address)
+ip="${public_address% *}" ; ip="${ip#* }"
+
+required_result 1 <<EOF
+RTNETLINK answers: Cannot assign requested address
+Failed to del ${ip} on dev ${public_address%% *}
+EOF
+
+simple_test $public_address


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.releaseip.002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "no public addresses"
+
+setup_ctdb
+
+export CTDB_PUBLIC_ADDRESSES="$CTDB_ETC/does/not/exist"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "all interfaces up"
+
+setup_ctdb
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.startup.002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "error - no args given"
+
+setup_ctdb
+
+iface=$(ctdb_get_1_interface)
+
+required_result 1 "ERROR: must supply interface, IP and maskbits"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "add an ip"
+
+setup_ctdb
+
+public_address=$(ctdb_get_1_public_address)
+
+ok_null
+
+simple_test $public_address


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.003.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.003.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.003.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "error - add same IP twice"
+
+setup_ctdb
+
+public_address=$(ctdb_get_1_public_address)
+
+# This is a bit gross and contrived.  The method of quoting the error
+# message so it makes it to required_result() is horrible.  Hopefully
+# improvements will come.
+
+err2="\
+RTNETLINK answers: File exists
+Failed to add 10.0.0.1/24 on dev dev123"
+
+#EVENTSCRIPTS_TESTS_TRACE="sh -x"
+iterate_test -- $public_address -- 2 "ok_null" \
+    2 'required_result 1 "$err2"'


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/10.interface.takeip.003.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/40.vsftpd.monitor.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/40.vsftpd.monitor.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/40.vsftpd.monitor.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "not managed, check no-op"
+
+setup_vsftpd "down"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/40.vsftpd.monitor.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/41.httpd.monitor.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/41.httpd.monitor.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/41.httpd.monitor.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "not managed, check no-op"
+
+setup_httpd "down"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/41.httpd.monitor.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "not managed, check no-op"
+
+setup_samba "down"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.050.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.050.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.050.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "auto-start, simple"
+
+setup_samba "down"
+
+export CTDB_MANAGED_SERVICES="foo samba winbind bar"
+
+ok <<EOF
+Starting service "samba" - now managed
+Starting winbind: OK
+Starting smb: OK
+EOF
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.050.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.051.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.051.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.051.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "auto-stop, simple"
+
+setup_samba
+
+export CTDB_MANAGED_SERVICES="foo"
+unset CTDB_MANAGES_SAMBA
+unset CTDB_MANAGES_WINBIND
+
+ok <<EOF
+Stopping service "samba" - no longer managed
+Stopping smb: OK
+Stopping winbind: OK
+EOF
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.051.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.101.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.101.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.101.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "all OK"
+
+setup_samba
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.101.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.102.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.102.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.102.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "winbind down"
+
+setup_samba
+wbinfo_down
+
+required_result 1 "ERROR: winbind - wbinfo -p returned error"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.102.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.103.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.103.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.103.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "port 445 down"
+
+setup_samba
+tcp_port_down 445
+
+required_result 1 "ERROR: samba tcp port 445 is not responding"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.103.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.104.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.104.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.104.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "port 139 down"
+
+setup_samba
+tcp_port_down 139
+
+required_result 1 "ERROR: samba tcp port 139 is not responding"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.104.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.105.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.105.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.105.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "non-existent share path"
+
+setup_samba
+shares_missing "ERROR: samba directory \"%s\" not available" 2
+
+required_result 1 "$MISSING_SHARES_TEXT"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.105.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.106.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.106.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.106.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "non-existent share - not checked"
+
+setup_samba
+shares_missing "ERROR: samba directory \"%s\" not available" 2
+
+export CTDB_SAMBA_SKIP_SHARE_CHECK="yes"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.106.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.107.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.107.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.107.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "port 139 down, default tcp checker, debug"
+
+# This has to go before the setup, otherwise it will write a dud file.
+export CTDB_DEBUGLEVEL=4
+
+setup_samba
+tcp_port_down 139
+
+required_result 1 <<EOF
+ERROR: samba tcp port 139 is not responding
+DEBUG: "ctdb checktcpport 139" was able to bind to port
+EOF
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.107.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.108.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.108.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.108.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "port 139 down, ctdb checktcpport not implemented"
+
+# TODO: create nmap stub
+export CTDB_NOT_IMPLEMENTED="checktcpport"
+
+setup_samba
+tcp_port_down 139
+
+required_result 1 "ERROR: samba tcp port 139 is not responding"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.108.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.109.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.109.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.109.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "port 139 down, ctdb checktcpport not implemented, debug"
+
+ctdb_not_implemented "checktcpport"
+
+# This has to go before the setup, otherwise it will write a dud file.
+export CTDB_DEBUGLEVEL=4
+
+setup_nmap_output_filter
+
+setup_samba
+tcp_port_down 139
+
+required_result 1 <<EOF
+DEBUG: ctdb_check_ports - checker ctdb not implemented
+DEBUG: output from checker was:
+DEBUG: ctdb checktcpport 445 (exited with 1) with output:
+$ctdb_not_implemented
+ERROR: samba tcp port 139 is not responding
+DEBUG: nmap -n -oG - -PS 127.0.0.1 -p 445,139 shows this output:
+DEBUG: # Nmap 5.21 scan initiated DATE as: nmap -n -oG - -PS 127.0.0.1 -p 445,139
+DEBUG: Host: 127.0.0.1 ()	Status: Up
+DEBUG: Host: 127.0.0.1 ()	Ports: 445/open/tcp//microsoft-ds///, 139/closed/tcp//netbios-ssn///
+DEBUG: # Nmap done at DATE -- 1 IP address (1 host up) scanned in 0.04 seconds
+EOF
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.109.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.110.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.110.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.110.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "port 139 down, ctdb checktcpport/nmap not implemented, debug"
+
+ctdb_not_implemented "checktcpport"
+export FAKE_NMAP_NOT_FOUND="yes"
+
+# This has to go before the setup, otherwise it will write a dud file.
+export CTDB_DEBUGLEVEL=4
+
+setup_nmap_output_filter
+
+setup_samba
+tcp_port_down 139
+
+required_result 1 <<EOF
+DEBUG: ctdb_check_ports - checker ctdb not implemented
+DEBUG: output from checker was:
+DEBUG: ctdb checktcpport 445 (exited with 1) with output:
+$ctdb_not_implemented
+DEBUG: ctdb_check_ports - checker nmap not implemented
+DEBUG: output from checker was:
+DEBUG: sh: nmap: command not found
+ERROR: samba tcp port 139 is not responding
+DEBUG: netstat -l -t -n shows this output:
+DEBUG: Active Internet connections (servers only)
+DEBUG: Proto Recv-Q Send-Q Local Address           Foreign Address         State
+DEBUG: tcp        0      0 0.0.0.0:445             0.0.0.0:*               LISTEN
+EOF
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.110.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.111.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.111.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.111.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "port 139 down, ctdb checktcpport/nmap/netstat not implemented"
+
+ctdb_not_implemented "checktcpport"
+export FAKE_NMAP_NOT_FOUND="yes"
+export FAKE_NETSTAT_NOT_FOUND="yes"
+
+setup_nmap_output_filter
+
+setup_samba
+tcp_port_down 139
+
+required_result 127 <<EOF
+INTERNAL ERROR: ctdb_check_ports - no working checkers in CTDB_TCP_PORT_CHECKERS="ctdb nmap netstat"
+EOF
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/50.samba.monitor.111.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "not managed, check no-op"
+
+setup_nfs "down"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.100.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.100.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.100.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "get RPC service fail limits/actions"
+
+setup_nfs
+
+set -e
+
+rm -f "$rpc_fail_limits_file"
+CTDB_RC_LOCAL="$CTDB_BASE/rc.local.nfs.monitor.get-limits" \
+    "${CTDB_BASE}/events.d/60.nfs" "monitor" >"$rpc_fail_limits_file"
+
+services="knfsd|mountd|rquotad|lockd|statd"
+
+echo "Doing rough check of file format..."
+
+! grep -v -E "^(${services}) " "$rpc_fail_limits_file"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.100.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.101.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.101.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.101.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "all services available"
+
+setup_nfs
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.101.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.111.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.111.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.111.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "knfsd down, 1 iteration"
+
+setup_nfs
+rpc_services_down "nfs"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.111.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.112.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.112.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.112.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "knfsd down, 6 iterations"
+
+# knfsd fails and attempts to restart it fail.
+
+setup_nfs
+rpc_services_down "nfs"
+
+iterate_test 6 'ok_null' \
+    2 'rpc_set_service_failure_response "knfsd"' \
+    4 'rpc_set_service_failure_response "knfsd"' \
+    6 'rpc_set_service_failure_response "knfsd"'


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.112.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.121.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.121.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.121.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "lockd down, 15 iterations"
+
+# This simulates an ongoing failure in the eventscript's automated
+# attempts to restart the service.  That is, the eventscript is unable
+# to restart the service.
+
+setup_nfs
+rpc_services_down "nlockmgr"
+
+#EVENTSCRIPTS_TESTS_TRACE="sh -x"
+iterate_test 15 "ok_null" \
+    10 "rpc_set_service_failure_response 'lockd'" \
+    15 "rpc_set_service_failure_response 'lockd'"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.121.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.122.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.122.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.122.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "lockd down, 15 iterations, back up after 10"
+
+# This simulates a success the eventscript's automated attempts to
+# restart the service.
+
+setup_nfs
+rpc_services_down "nlockmgr"
+
+# Iteration 10 should try to restart rpc.lockd.  However, our test
+# stub rpc.lockd does nothing, so we have to explicitly flag it as up.
+
+iterate_test 15 "ok_null" \
+    10 "rpc_set_service_failure_response 'lockd'" \
+    11 "rpc_services_up nlockmgr"
+


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.122.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.131.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.131.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.131.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "rquotad down, 5 iterations"
+
+setup_nfs
+rpc_services_down "rquotad"
+
+iterate_test 5 'rpc_set_service_failure_response "rquotad"'


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.131.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.132.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.132.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.132.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "rquotad down, 5 iterations, back up after 1"
+
+# rquotad fails once but then comes back of its own accord after 1
+# failure.
+
+setup_nfs
+rpc_services_down "rquotad"
+
+iterate_test 5 'ok_null' \
+    1 'rpc_set_service_failure_response "rquotad"' \
+    2 'rpc_services_up "rquotad"'


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.132.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.141.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.141.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.141.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "statd down, 6 iterations"
+
+# statd fails and attempts to restart it fail.
+
+setup_nfs
+rpc_services_down "status"
+
+iterate_test 6 'ok_null' \
+    2 'rpc_set_service_failure_response "statd"' \
+    4 'rpc_set_service_failure_response "statd"' \
+    6 'rpc_set_service_failure_response "statd"'


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.141.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.142.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.142.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.142.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "statd down, 8 iterations, back up after 2"
+
+# statd fails and the first attempt to restart it succeeds.
+
+setup_nfs
+rpc_services_down "status"
+
+iterate_test 8 'ok_null' \
+    2 'rpc_set_service_failure_response "statd"' \
+    3 'rpc_services_up "status"'


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.142.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.151.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.151.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.151.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "mountd down, 1 iteration"
+
+setup_nfs
+rpc_services_down "mountd"
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.151.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.152.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.152.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.152.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "mountd down, 10 iterations"
+
+# This simulates an ongoing failure in the eventscript's automated
+# attempts to restart the service.  That is, the eventscript is unable
+# to restart the service.
+
+setup_nfs
+rpc_services_down "mountd"
+
+iterate_test 10 "ok_null" \
+    5 "rpc_set_service_failure_response 'mountd'" \
+    10 "rpc_set_service_failure_response 'mountd'"
+
+#export FAKE_NETSTAT_TCP_ESTABLISHED="10.0.0.1:2049|10.254.254.1:12301 10.0.0.1:2049|10.254.254.1:12302 10.0.0.1:2049|10.254.254.1:12303 10.0.0.1:2049|10.254.254.2:12304 10.0.0.1:2049|10.254.254.2:12305"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.152.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.153.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.153.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.153.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "mountd down, 10 iterations, back up after 5"
+
+setup_nfs
+rpc_services_down "mountd"
+
+# Iteration 5 should try to restart rpc.mountd.  However, our test
+# stub rpc.mountd does nothing, so we have to explicitly flag it as
+# up.
+iterate_test 10 "ok_null" \
+    5 "rpc_set_service_failure_response 'mountd'" \
+    6 "rpc_services_up mountd"


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.153.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.161.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.161.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.161.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "2nd share missing"
+
+setup_nfs
+
+shares_missing "ERROR: nfs directory \"%s\" not available" 2
+
+required_result 1 "$MISSING_SHARES_TEXT"
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.161.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.162.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.162.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.162.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. "${EVENTSCRIPTS_TESTS_DIR}/common.sh"
+
+define_test "2nd share missing, skipping share checks"
+
+setup_nfs
+export CTDB_NFS_SKIP_SHARE_CHECK="yes"
+
+shares_missing "ERROR: nfs directory \"%s\" not available" 2
+
+ok_null
+
+simple_test


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/simple/60.nfs.monitor.162.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ctdb
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ctdb	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ctdb	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,227 @@
+#!/bin/sh
+
+prog="ctdb"
+
+not_implemented_exit_code=1
+
+usage ()
+{
+    cat >&2 <<EOF
+Usage: $prog [-Y] cmd
+
+A fake CTDB stub that prints items depending on the variables
+FAKE_CTDB_PNN (default 0) depending on command-line options.
+EOF
+    exit 1
+}
+
+not_implemented ()
+{
+    echo "${prog}: command \"$1\" not implemented in stub" >&2
+    exit $not_implemented_exit_code
+}
+
+# Don't set $POSIXLY_CORRECT here.
+_temp=$(getopt -n "$prog" -o "Yvh" -l help -- "$@") || \
+    usage
+
+eval set -- "$_temp"
+
+verbose=false
+machine_readable=false
+
+while true ; do
+    case "$1" in
+	-Y) machine_readable=true ; shift ;;
+	-v) verbose=true ; shift ;;
+	--) shift ; break ;;
+	-h|--help|*) usage ;; # * shouldn't happen, so this is reasonable.
+    esac
+done
+
+[ $# -ge 1 ] || usage
+
+setup_tickles ()
+{
+    # Make sure tickles file exists.
+    tickles_file="$CTDB_VARDIR/fake-ctdb/tickles"
+    mkdir -p $(dirname "$tickles_file")
+    touch "$tickles_file"
+}
+
+setup_pstore ()
+{
+    pstore_dir="$CTDB_VARDIR/fake-ctdb/pstore/$1"
+    mkdir -p "$pstore_dir"
+}
+
+# For testing backward compatibility...
+for i in $CTDB_NOT_IMPLEMENTED ; do
+    if [ "$i" = "$1" ] ; then
+	not_implemented "$i"
+    fi
+done
+
+case "$1" in
+    ip)
+	# NOTE: all nodes share the same public addresses file.
+
+	# This is completely stateless and IPs move unnecessarily.
+	_f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}"
+	if [ -f "$_f" ] ; then
+	    if $verbose ; then
+		echo ":Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:"
+
+	    else
+		echo ":Public IP:Node:"
+	    fi
+	    # Here IPs are distributed across nodes in a stupid way...
+	    _n=0
+	    while read _ip _ifaces ; do
+		case "_$ip" in
+		    \#*) : ;;
+		    *)
+			# Find a node that is up... but don't loop forever.
+			_orig=$_n
+			while [ -f "${FAKE_CTDB_NODES_DOWN}/${_n}" ] ; do
+			    _n=$(($_n + 1))
+			    if [ _n -eq $FAKE_CTDB_NUMNODES ] ; then
+				_n=0
+			    fi
+			    if [ $_n -eq $_orig ] ; then
+				_n=-1 # Never down!  :-)
+			    fi
+			done
+			if $verbose ; then
+			    # If more than 1 interface, assume all
+			    # addresses are on the 1st.
+			    _first_iface="${_ifaces%%,*}"
+			    # Only show interface if address is on
+			    # this node.
+			    _my_iface=""
+			    if [ "PNN:$_n" = $(ctdb -Y pnn) ]; then
+				_my_iface="$_first_iface"
+			    fi
+			    echo ":${_ip}:${_n}:${_my_iface}:${_first_iface}:${_ifaces}:"
+			else
+			    echo ":${_ip}:${_n}:"
+			fi
+		esac
+	    done <"$_f"
+	fi
+	;;
+    pnn|xpnn)
+	# Defaults to 0
+	echo "PNN:${FAKE_CTDB_PNN:-0}"
+	;;
+    gettickles)
+	setup_tickles
+	echo ":source ip:port:destination ip:port:"
+	while read src dst ; do
+	    echo ":${src}:${dst}:"
+	done <"$tickles_file"
+	;;
+    addtickle)
+	setup_tickles
+	echo "$2 $3" >>"$tickles_file"
+	;;
+    deltickle)
+	setup_tickles
+	_t=$(grep -F -v "$2 $3" "$tickles_file")
+	echo "$_t" >"$tickles_file"
+	;;
+    pstore)
+	setup_pstore "$2"
+	cat "$4" >"${pstore_dir}/$3"
+	;;
+    pfetch)
+	setup_pstore "$2"
+	cat "${pstore_dir}/$3" >"$4" 2>/dev/null
+	;;
+    ifaces)
+	# Assume -Y.
+	echo ":Name:LinkStatus:References:"
+	_f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}"
+	if [ -r "$_f" ] ; then
+	    while read _ip _iface ; do
+		case "_$ip" in
+		    \#*) : ;;
+		    *)
+			_status=1
+			# For now assume _iface contains only 1.
+			if [ -f "{FAKE_CTDB_IFACES_DOWN}/${_iface}" ] ; then
+			    _status=0
+			fi
+			# Nobody looks at references
+			echo ":${_iface}:${_status}:0"
+		esac
+	    done <"$_f" |
+	    sort -u
+	fi
+	;;
+    setifacelink)
+	# Existence of file means CTDB thinks interface is down.
+	_f="${FAKE_CTDB_IFACES_DOWN}/$2"
+	case "$3" in
+	    up)   rm -f "$_f" ;;
+	    down) touch "$_f" ;;
+	    *)
+		echo "ctdb setifacelink: unsupported interface status $3"
+		exit 1
+	esac
+	;;
+    getdebug)
+	case "${CTDB_DEBUGLEVEL:-0}" in
+	    -3) _t="EMERG"  ;;
+	    -2) _t="ALERT"  ;;
+	    -1) _t="CRIT"   ;;
+	    0) _t="ERR"     ;;
+	    1) _t="WARNING" ;;
+	    2) _t="NOTICE"  ;;
+	    3) _t="INFO"    ;;
+	    4) _t="DEBUG"   ;;
+	    *) _t="ERR"     ;;
+	esac
+
+	cat<<EOF
+:Name:Level:
+:${_t}:${CTDB_DEBUGLEVEL}:
+EOF
+	;;
+    checktcpport)
+	for _i in $FAKE_TCP_LISTEN ; do
+	    if [ "$2" = "${_i##*:}" ] ; then
+		exit 98
+	    fi
+	done
+
+	exit 0
+	;;
+    scriptstatus)
+	$machine_readable || not_implemented "$1, without -Y"
+	[ "$2" != "all" ] || not_implemented "scriptstatus all"
+	# For now just assume everything is good.
+	echo ":Type:Name:Code:Status:Start:End:Error Output...:"
+	for _i in "$CTDB_BASE/events.d/"*.* ; do
+	    _d1=$(date '+%s.%N')
+	    _b="${_i##*/}" # basename
+
+	    _f="$FAKE_CTDB_SCRIPTSTATUS/$_b"
+	    if [ -r "$_f" ] ; then
+		read _code _status _err_out <"$_f"
+	    else
+		_code="0"
+		_status="OK"
+		if [ ! -x "$_i" ] ; then
+		    _status="DISABLED"
+		    _code="-8"
+		fi
+		_err_out=""
+	    fi
+	    _d2=$(date '+%s.%N')
+	    echo ":${2:-monitor}:${_b}:${_code}:${_status}:${_d1}:${_d2}:${_err_out}:"
+	done
+	;;
+    *)
+	not_implemented "$1"
+esac


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ctdb
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ethtool
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ethtool	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ethtool	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+link="yes"
+
+if [ -f  "${FAKE_ETHTOOL_LINK_DOWN}/${1}" ] ; then
+    link="no"
+fi
+
+# Expect to add more fields later.
+cat <<EOF
+	Link detected: ${link}
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ethtool
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/exportfs
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/exportfs	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/exportfs	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+opts="10.0.0.0/16(rw,async,insecure,no_root_squash,no_subtree_check)"
+
+for i in $FAKE_SHARES ; do
+    # Directories longer than 15 characters are printed on their own
+    # line.
+    if [ ${#i} -ge 15 ] ; then
+	printf '%s\n\t\t%s\n' "$i" "$opts"
+    else
+	printf '%s\t%s\n' "$i" "$opts"
+    fi
+done


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/exportfs
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ip
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ip	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ip	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,205 @@
+#!/bin/sh
+
+: ${FAKE_IP_STATE:=${PWD}/var/fake-ip-state}
+
+not_implemented ()
+{
+    echo "ip stub command: \"$1\" not implemented"
+    exit 127
+}
+
+
+case "$1" in
+    link)
+	case "$2" in
+	    set)
+		iface="$3"
+		case "$4" in
+		    up)
+			rm -f "${FAKE_IP_STATE}/interfaces-down/${iface}"
+			;;
+		    down)
+			mkdir -p "${FAKE_IP_STATE}/interfaces-down"
+			touch "${FAKE_IP_STATE}/interfaces-down/${iface}"
+			;;
+		    *)
+			not_implemented "$*"
+		esac
+		;;
+	    *)
+		not_implemented "$1 $2"
+	esac
+	
+	;;
+    addr)
+	case "$2" in
+	    add)
+		shift 2
+		local=""
+		dev=""
+		brd=""
+		while [ -n "$1" ] ; do
+		    case "$1" in
+			*.*.*.*/*)
+			    local="$1" ; shift
+			    ;;
+			local)
+			    local="$2" ; shift 2
+			    ;;
+			broadcast|brd)
+			    # For now assume this is always '+'.
+			    if [ "$2" != "+" ] ; then
+				not_implemented "addr add ... brd $2 ..."
+			    fi
+			    shift 2
+			    ;;
+			dev)
+			    dev="$2" ; shift 2
+			    ;;
+			*)
+			    not_implemented "addr add ... $1 ..."
+		    esac
+		done
+		if [ -z "$dev" ] ; then
+		    not_implemented "addr add (without dev)"
+		fi
+		mkdir -p "${FAKE_IP_STATE}/addresses"
+		pf="${FAKE_IP_STATE}/addresses/${dev}-primary"
+		sf="${FAKE_IP_STATE}/addresses/${dev}-secondary"
+		# We could lock here... but we should be the only ones
+		# playing around here with these stubs.
+		if [ ! -f "$pf" ] ; then
+		    echo "$local" >"$pf"
+		elif grep -Fq "$local" "$pf" ; then 
+		    echo "RTNETLINK answers: File exists" >&2
+		    exit 254
+		elif [ -f "$sf" ] && grep -Fq "$local" "$sf" ; then 
+		    echo "RTNETLINK answers: File exists" >&2
+		    exit 254
+		else
+		    echo "$local" >>"$sf"
+		fi
+		;;
+	    delete|del)
+		shift 2
+		local=""
+		dev=""
+		while [ -n "$1" ] ; do
+		    case "$1" in
+			*.*.*.*/*)
+			    local="$1" ; shift
+			    ;;
+			local)
+			    local="$2" ; shift 2
+			    ;;
+			dev)
+			    dev="$2" ; shift 2
+			    ;;
+			*)
+			    not_implemented "addr del ... $1 ..."
+		    esac
+		done
+		if [ -z "$dev" ] ; then
+		    not_implemented "addr del (without dev)"
+		fi
+		mkdir -p "${FAKE_IP_STATE}/addresses"
+		pf="${FAKE_IP_STATE}/addresses/${dev}-primary"
+		sf="${FAKE_IP_STATE}/addresses/${dev}-secondary"
+		# We could lock here... but we should be the only ones
+		# playing around here with these stubs.
+		if [ ! -f "$pf" ] ; then
+		    echo "RTNETLINK answers: Cannot assign requested address" >&2
+		    exit 254
+		elif grep -Fq "$local" "$pf" ; then
+		    # Remove primaries AND SECONDARIES.
+		    rm -f "$pf" "$sf"
+		elif [ -f "$sf" ] && grep -Fq "$local" "$sf" ; then 
+		    grep -Fv "$local" "$sf" >"${sf}.new"
+		    mv "${sf}.new" "$sf"
+		else
+		    echo "RTNETLINK answers: Cannot assign requested address" >&2
+		    exit 254
+		fi
+		;;
+	    show|list)
+		shift 2
+		dev=""
+		primary=true
+		secondary=true
+		while [ -n "$1" ] ; do
+		    case "$1" in
+			dev)
+			    dev="$2" ; shift 2
+			    ;;
+			# Do stupid things and stupid things will happen!
+			primary)
+			    primary=true ; secondary=false ; shift
+			    ;;
+			secondary)
+			    secondary=true ; primary=false ; shift
+			    ;;
+			*)
+			    # Assume an interface name
+			    dev="$1" ; shift 1
+		    esac
+		done
+		devices="$dev"
+		if [ -z "$devices" ] ; then
+		    # No device specified?  Get all the primaries...
+		    devices=$(ls "${FAKE_IP_STATE}/addresses/"*-primary 2>/dev/null | \
+			sed -e 's at .*/@@' -e 's at -primary$@@')
+		fi
+		calc_brd ()
+		{
+		    case "${local#*/}" in
+			24)
+			    brd="${local%.*}.255"
+			    ;;
+			*)
+			   not_implemented "list ... fake bits other than 24: ${local#*/}"
+		    esac
+		}
+		show_iface()
+		{
+		    pf="${FAKE_IP_STATE}/addresses/${dev}-primary"
+		    sf="${FAKE_IP_STATE}/addresses/${dev}-secondary"
+		    mac=$(echo $dev | md5sum | sed -r -e 's@(..)(..)(..)(..)(..)(..).*@\1:\2:\3:\4:\5:\6@')
+		    cat <<EOF
+${n}: ${dev}: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
+    link/ether ${mac} brd ff:ff:ff:ff:ff:ff
+EOF
+		    if $primary && [ -r "$pf" ] ; then
+			read local <"$pf"
+			calc_brd
+cat <<EOF
+    inet ${local} brd ${brd} scope global ${dev}
+EOF
+		    fi
+		    if $secondary && [ -r "$sf" ] ; then
+			while read local ; do
+			    calc_brd
+cat <<EOF
+    inet ${local} brd ${brd} scope global secondary ${dev}
+EOF
+			done <"$sf"
+		    fi
+cat <<EOF
+       valid_lft forever preferred_lft forever
+EOF
+
+		}
+		n=1
+		for dev in $devices ; do
+		    show_iface
+		    n=$(($n + 1))
+		done
+		;;
+	    *)
+		not_implemented "$1 $2"
+	esac
+	;;
+    *)
+	not_implemented "$1"
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/ip
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/iptables
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/iptables	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/iptables	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# Always succeed.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/iptables
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/kill
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/kill	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/kill	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Always succeed.  This means that kill -0 will always find a
+# process and anything else will successfully kill.  This should
+# exercise a good avriety of code paths.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/kill
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/killall
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/killall	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/killall	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Always succeed.  This means that killall -0 will always find a
+# process and anything else will successfully kill.  This should
+# exercise a good avriety of code paths.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/killall
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/net
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/net	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/net	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# Always succeed for now...
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/net
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/netstat
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/netstat	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/netstat	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+prog="netstat"
+
+# Pretty that we're the shell and that this command could not be
+# found.
+if [ "$FAKE_NETSTAT_NOT_FOUND" = "yes" ] ; then
+    echo "sh: ${prog}: command not found" >&2
+    exit 127
+fi
+
+usage ()
+{
+    cat >&2 <<EOF
+Usage: $prog [ -t | --unix ] [ -n ] [ -a ] [ -l ]
+
+A fake netstat stub that prints items depending on the variables
+FAKE_NETSTAT_TCP_ESTABLISHED, FAKE_TCP_LISTEN,
+FAKE_NETSTAT_UNIX_LISTEN, depending on command-line options.
+
+Note that -n is ignored.
+
+EOF
+    exit 1
+}
+
+# Defaults.
+tcp=false
+unix=false
+all=false
+listen=false
+
+parse_options ()
+{
+    # $POSIXLY_CORRECT means that the command passed to onnode can
+    # take options and getopt won't reorder things to make them
+    # options to this script.
+    _temp=$(POSIXLY_CORRECT=1 getopt -n "$prog" -o "tnalh" -l unix -l help -- "$@")
+
+    [ $? != 0 ] && usage
+
+    eval set -- "$_temp"
+
+    while true ; do
+	case "$1" in
+	    -n) shift ;;
+	    -a) all=true ; shift ;;
+	    -t) tcp=true ; shift ;;
+	    -l) listen=true ; shift ;;
+	    --unix) unix=true ; shift ;;
+	    --) shift ; break ;;
+	    -h|--help|*) usage ;; # * shouldn't happen, so this is reasonable.
+	esac
+    done
+
+    [ $# -gt 0 ] && usage
+
+    # If neither -t or --unix specified then print all.
+    $tcp || $unix || { tcp=true ; unix=true ; }
+}
+
+parse_options "$@"
+
+if $tcp ; then
+    if $listen ; then
+	echo "Active Internet connections (servers only)"
+    elif $all ; then
+	echo "Active Internet connections (servers and established)"
+    else
+	echo "Active Internet connections (w/o servers)"
+    fi
+
+    echo "Proto Recv-Q Send-Q Local Address           Foreign Address         State"
+
+    tcp_fmt="tcp        0      0 %-23s %-23s %s\n"
+    for i in $FAKE_NETSTAT_TCP_ESTABLISHED ; do
+	src="${i%|*}"
+	dst="${i#*|}"
+	printf "$tcp_fmt" $src $dst "ESTABLISHED"
+    done
+
+    if $all || $listen ; then
+	for i in $FAKE_TCP_LISTEN ; do
+	    printf "$tcp_fmt" $i "0.0.0.0:*" "LISTEN"
+	done
+    fi
+fi
+
+if $unix ; then
+    if $listen ; then
+	echo "Active UNIX domain sockets (servers only)"
+    elif $all ; then
+	echo "Active UNIX domain sockets (servers and established)"
+    else
+	echo "Active UNIX domain sockets (w/o servers)"
+    fi
+    
+    echo "Proto RefCnt Flags       Type       State         I-Node   Path"
+
+    unix_fmt="unix  2      [ ACC ]     STREAM     LISTENING     %-8d %s\n"
+    if $all || $listen ; then
+	for i in $FAKE_NETSTAT_UNIX_LISTEN ; do
+	    printf "$unix_fmt" 12345 "$i"
+	done
+    fi
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/netstat
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/nmap
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/nmap	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/nmap	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+prog="nmap"
+
+# Pretty that we're the shell and that this command could not be
+# found.
+if [ "$FAKE_NMAP_NOT_FOUND" = "yes" ] ; then
+    echo "sh: ${prog}: command not found" >&2
+    exit 127
+fi
+
+usage ()
+{
+    cat >&2 <<EOF
+Usage: $prog -n -oG - -PS 127.0.0.1 -p <port>[,<port> ...]
+
+A fake nmap stub that prints items depending on the variable
+FAKE_TCP_LISTEN and the ports specified.
+
+Note that all options apart from -p are ignored.
+
+EOF
+    exit 1
+}
+
+ports=""
+
+parse_options ()
+{
+    _temp=$(getopt -n "$prog" -a -o "np:" -l help -l PS: -l oG: -- "$@")
+
+    [ $? != 0 ] && usage
+
+    eval set -- "$_temp"
+
+    while true ; do
+	case "$1" in
+	    -n) shift ;;
+	    --oG|--PS) shift 2 ;;
+	    -p) ports="${ports}${ports:+ }${2//,/ }" ; shift 2 ;;
+	    --) shift ; break ;;
+	    -h|--help|*) usage ;; # * shouldn't happen, so this is reasonable.
+	esac
+    done
+
+    [ $# -gt 0 ] && usage
+
+    [ -n "$ports" ] || usage
+}
+
+# For printing out...
+args="$*"
+
+parse_options "$@"
+
+port_states=""
+
+for p in $ports ; do
+    pn=$(getent services "$p" | sed -e 's@[[:space:]].*@@')
+    for i in $FAKE_TCP_LISTEN ; do
+	lp="${i##*:}"
+	if [ "$p" = "$lp" ] ; then
+	    port_states="${port_states}${port_states:+, }${p}/open/tcp//${pn}///"
+	    continue 2
+	fi
+    done
+    port_states="${port_states}${port_states:+, }${p}/closed/tcp//${pn}///"
+done
+
+cat <<EOF
+# Nmap 5.21 scan initiated $(date) as: nmap $args
+Host: 127.0.0.1 ()	Status: Up
+Host: 127.0.0.1 ()	Ports: $port_states
+# Nmap done at $(date) -- 1 IP address (1 host up) scanned in 0.04 seconds
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/nmap
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/pkill
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/pkill	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/pkill	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Always succeed.  This means that pkill -0 will always find a
+# process and anything else will successfully kill.  This should
+# exercise a good avriety of code paths.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/pkill
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.lockd
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.lockd	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.lockd	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Restart always "works".  However, the test infrastructure may
+# continue to mark the service as down, so that's what matters.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.lockd
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.mountd
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.mountd	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.mountd	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Restart always "works".  However, the test infrastructure may
+# continue to mark the service as down, so that's what matters.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.mountd
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.rquotad
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.rquotad	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.rquotad	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Restart always "works".  However, the test infrastructure may
+# continue to mark the service as down, so that's what matters.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.rquotad
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.statd
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.statd	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.statd	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Restart always "works".  However, the test infrastructure may
+# continue to mark the service as down, so that's what matters.
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpc.statd
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpcinfo
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpcinfo	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpcinfo	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+prog="rpcinfo"
+
+usage ()
+{
+    cat >&2 <<EOF
+Usage: $prog -u host program [version]
+
+A fake rpcinfo stub that succeeds for items in FAKE_RPCINFO_SERVICES,
+depending on command-line options.
+
+Note that "-u host" is ignored.
+
+EOF
+    exit 1
+}
+
+parse_options ()
+{
+    # $POSIXLY_CORRECT means that the command passed to onnode can
+    # take options and getopt won't reorder things to make them
+    # options to this script.
+    _temp=$(POSIXLY_CORRECT=1 getopt -n "$prog" -o "u:h" -l unix -l help -- "$@")
+
+    [ $? != 0 ] && usage
+
+    eval set -- "$_temp"
+
+    while true ; do
+	case "$1" in
+	    -u) shift 2 ;;  # ignore
+	    --) shift ; break ;;
+	    -h|--help|*) usage ;; # * shouldn't happen, so this is reasonable.
+	esac
+    done
+
+    [ 1 -le $# -a $# -le 2 ] || usage
+
+    p="$1"
+    v="$2"
+}
+
+parse_options "$@"
+
+for i in ${FAKE_RPCINFO_SERVICES} ; do
+    # This is stupidly cummulative, but needs to happen after the
+    # initial split of the list above.
+    IFS="${IFS}:"
+    set -- $i
+    # $1 = program, $2 = low version, $3 = high version
+    
+    if [ "$1" = "$p" ] ; then
+	if [ -n "$v" ] ; then
+	    if [ "$2" -le "$v" -a "$v" -le "$3" ] ; then
+		echo "program ${p} version ${v} ready and waiting"
+		exit 0
+	    else
+		echo "rpcinfo: RPC: Program/version mismatch; low version = ${2}, high version = ${3}" >&2
+		echo "program ${p} version ${v} is not available"
+		exit 1
+	    fi
+	else
+	    for j in $(seq $2 $3) ; do
+		echo "program ${p} version ${j} ready and waiting"
+	    done
+	    exit 0
+	fi
+    fi
+done
+
+echo "rpcinfo: RPC: Program not registered" >&2
+if [ -n "$v" ] ; then
+    echo "program ${p} version ${v} is not available"
+else
+    echo "program ${p} is not available"
+fi
+
+exit 1


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/rpcinfo
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/service
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/service	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/service	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+service_status_dir="${EVENTSCRIPTS_TESTS_VAR_DIR}/service_fake_status"
+mkdir -p "$service_status_dir"
+
+service="$1"
+flag="${service_status_dir}/${service}"
+
+start()
+{
+    if [ -f "$flag" ] ; then
+	echo "service: can't start ${service} - already running"
+	exit 1
+    else
+	touch "$flag"
+	echo "Starting ${service}: OK"
+    fi
+}
+
+stop ()
+{
+    if [ -f "$flag" ] ; then
+	echo "Stopping ${service}: OK"
+	rm -f "$flag"
+    else
+	echo "service: can't stop ${service} - not running"
+	exit 1
+    fi
+}
+
+case "$2" in
+    start)
+	start
+	;;
+    stop)
+	stop
+	;;
+    restart|reload)
+	stop
+	start
+	;;
+    status)
+	if [ -f "$flag" ] ; then
+	    echo "$service running"
+	    exit 0
+	else
+	    echo "$service not running"
+	    exit 3
+	fi
+	;;
+    force-started)
+	# For test setup...
+	touch "$flag"
+	;;
+    force-stopped)
+	# For test setup...
+	rm -f "$flag"
+	;;
+    *)
+	echo "service $service $2 not supported"
+	exit 1
+esac
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/service
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/sleep
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/sleep	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/sleep	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if [ "$FAKE_SLEEP_REALLY" = "yes" ] ; then
+    /bin/sleep "$@"
+elif [ -n "$FAKE_SLEEP_FORCE" ] ; then
+    /bin/sleep "$FAKE_SLEEP_FORCE"
+else
+    :
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/sleep
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/testparm
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/testparm	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/testparm	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# Ensure that testparm always uses our canned configuration instead of
+# the global one, unless some other file is specified.  This requires
+# testparm to be installed but is quicker than reimplementing all the
+# various command-line options.
+
+file_specified=false
+for i ; do
+    case "$i" in
+	-*) : ;;
+	*) file_specified=true
+    esac
+done
+
+if $file_specified ; then
+    # This should include the shares, since this is used when the
+    # samba eventscript caches the output.
+    /usr/bin/testparm "$@"
+else
+    # We force our own smb.conf and add the shares.
+    /usr/bin/testparm "$@" "${CTDB_ETCDIR}/samba/smb.conf"
+
+    for i in $FAKE_SHARES ; do
+	bi=$(basename "$i")
+cat <<EOF
+
+[${bi}]
+	path		= $i
+	comment		= fake share $bi
+	guest ok  	= no
+	read only	= no
+	browseable	= yes
+EOF
+    done
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/testparm
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/wbinfo
===================================================================
--- branches/ctdb/squeeze-backports/tests/eventscripts/stubs/wbinfo	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/eventscripts/stubs/wbinfo	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ "$FAKE_WBINFO_FAIL" = "yes" ] ; then
+   exit 1
+fi
+
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/eventscripts/stubs/wbinfo
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE all hostname"
+
+define_test "$cmd" "all nodes OK"
+
+required_result <<EOF
+
+>> NODE: 192.168.1.101 <<
+-n 192.168.1.101 hostname
+
+>> NODE: 192.168.1.102 <<
+-n 192.168.1.102 hostname
+
+>> NODE: 192.168.1.103 <<
+-n 192.168.1.103 hostname
+
+>> NODE: 192.168.1.104 <<
+-n 192.168.1.104 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE -q all hostname"
+
+define_test "$cmd" "all nodes OK"
+
+required_result <<EOF
+-n 192.168.1.101 hostname
+-n 192.168.1.102 hostname
+-n 192.168.1.103 hostname
+-n 192.168.1.104 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0003.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0003.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0003.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE -p all hostname"
+
+define_test "$cmd" "all nodes OK"
+
+required_result <<EOF
+[192.168.1.101] -n 192.168.1.101 hostname
+[192.168.1.102] -n 192.168.1.102 hostname
+[192.168.1.103] -n 192.168.1.103 hostname
+[192.168.1.104] -n 192.168.1.104 hostname
+EOF
+
+simple_test -s $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0003.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0004.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0004.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0004.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE -pq all hostname"
+
+define_test "$cmd" "all nodes OK"
+
+required_result <<EOF
+-n 192.168.1.101 hostname
+-n 192.168.1.102 hostname
+-n 192.168.1.103 hostname
+-n 192.168.1.104 hostname
+EOF
+
+simple_test -s $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0004.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0005.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0005.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0005.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE 3 hostname"
+
+define_test "$cmd" "all nodes OK"
+
+required_result <<EOF
+-n 192.168.1.104 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0005.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0006.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0006.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0006.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE -v 3 hostname"
+
+define_test "$cmd" "all nodes OK"
+
+required_result <<EOF
+
+>> NODE: 192.168.1.104 <<
+-n 192.168.1.104 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0006.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0070.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0070.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0070.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE ok hostname"
+
+define_test "$cmd" "all nodes OK"
+
+ctdb_set_output <<EOF
+:Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:Inactive:
+:0:192.168.1.101:0:0:0:0:0:0:
+:1:192.168.1.102:0:0:0:0:0:0:
+:2:192.168.1.103:0:0:0:0:0:0:
+:3:192.168.1.104:0:0:0:0:0:0:
+EOF
+
+required_result <<EOF
+
+>> NODE: 192.168.1.101 <<
+-n 192.168.1.101 hostname
+
+>> NODE: 192.168.1.102 <<
+-n 192.168.1.102 hostname
+
+>> NODE: 192.168.1.103 <<
+-n 192.168.1.103 hostname
+
+>> NODE: 192.168.1.104 <<
+-n 192.168.1.104 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0070.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0071.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0071.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0071.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE ok hostname"
+
+define_test "$cmd" "2nd node disconnected"
+
+ctdb_set_output  <<EOF 
+ctdb_set_output <<EOF
+:Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:Inactive:
+:0:192.168.1.101:0:0:0:0:0:0:
+:1:192.168.1.102:1:0:0:0:0:0:
+:2:192.168.1.103:0:0:0:0:0:0:
+:3:192.168.1.104:0:0:0:0:0:0:
+EOF
+
+required_result <<EOF
+
+>> NODE: 192.168.1.101 <<
+-n 192.168.1.101 hostname
+
+>> NODE: 192.168.1.103 <<
+-n 192.168.1.103 hostname
+
+>> NODE: 192.168.1.104 <<
+-n 192.168.1.104 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0071.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0072.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0072.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0072.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE ok hostname"
+
+define_test "$cmd" "2nd node disconnected, extra status columns"
+
+ctdb_set_output <<EOF
+:Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:Inactive:X1:X2:X3:X4:
+:0:192.168.1.101:0:0:0:0:0:0:0:0:0:0:
+:1:192.168.1.102:1:0:0:0:0:0:0:0:0:0:
+:2:192.168.1.103:0:0:0:0:0:0:0:0:0:0:
+:3:192.168.1.104:0:0:0:0:0:0:0:0:0:0:
+EOF
+
+required_result <<EOF
+
+>> NODE: 192.168.1.101 <<
+-n 192.168.1.101 hostname
+
+>> NODE: 192.168.1.103 <<
+-n 192.168.1.103 hostname
+
+>> NODE: 192.168.1.104 <<
+-n 192.168.1.104 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0072.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0075.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0075.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0075.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE con hostname"
+
+define_test "$cmd" "1st node disconnected"
+
+ctdb_set_output <<EOF
+:Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:Inactive:
+:0:192.168.1.101:1:0:0:0:0:0:
+:1:192.168.1.102:0:0:0:0:0:0:
+:2:192.168.1.103:0:0:0:0:0:0:
+:3:192.168.1.104:0:0:0:0:0:0:
+EOF
+
+required_result <<EOF
+
+>> NODE: 192.168.1.102 <<
+-n 192.168.1.102 hostname
+
+>> NODE: 192.168.1.103 <<
+-n 192.168.1.103 hostname
+
+>> NODE: 192.168.1.104 <<
+-n 192.168.1.104 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0075.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0080.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0080.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0080.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE recmaster hostname"
+
+define_test "$cmd" "node 1 (192.168.1.102) is recmaster"
+
+ctdb_set_output <<EOF
+1
+EOF
+
+required_result <<EOF
+-n 192.168.1.102 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0080.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0081.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0081.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0081.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE lvsmaster hostname"
+
+define_test "$cmd" "no lvsmaster"
+
+ctdb_set_output 255 <<EOF
+There is no LVS master
+EOF
+
+required_result 1 <<EOF
+onnode: No lvsmaster available
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0081.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0090.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0090.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0090.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE natgw hostname"
+
+define_test "$cmd" "no natgw"
+
+ctdb_set_output <<EOF
+-1 0.0.0.0
+:0:192.168.1.101:0:0:0:0:0:
+:1:192.168.1.102:0:0:0:0:0:
+:2:192.168.1.103:0:0:0:0:0:
+:3:192.168.1.104:0:0:0:0:0:
+EOF
+
+required_result 1 <<EOF
+onnode: No natgwlist available
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0090.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/0091.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/0091.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/0091.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+. "${ONNODE_TESTS_DIR}/common.sh"
+
+cmd="$ONNODE natgw hostname"
+
+define_test "$cmd" "node 2 (192.168.1.103) is natgw"
+
+ctdb_set_output <<EOF
+2 192.168.1.103
+:0:192.168.1.101:0:0:0:0:0:
+:1:192.168.1.102:0:0:0:0:0:
+:2:192.168.1.103:0:0:0:0:0:
+:3:192.168.1.104:0:0:0:0:0:
+EOF
+
+required_result <<EOF
+-n 192.168.1.103 hostname
+EOF
+
+simple_test $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/0091.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/README
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,38 @@
+onnode unit tests
+=================
+
+Examples:
+
+* ./run_tests.sh
+
+  Run all tests, displaying output.
+
+* ./run_tests.sh -s
+
+  Run all tests, displaying output and a summary.
+
+* ./run_tests.sh -sq
+
+  Run all tests, displaying only a summary.
+
+* ONNODE=onnode-buggy-001 ./run_tests.sh -s
+
+  Run against stubs/onnode-buggy-001 instead of default onnode version.
+
+  Add more buggy versions of onnode to this directory as bugs are
+  fixed to enable test validation using this feature.
+
+* ./run_tests.sh ./009*.sh
+
+  Run only the specified tests.
+
+* ONNODE="bash -x stubs/onnode-buggy-001" ./run_tests.sh ./0090.sh
+  ONNODE="bash -x ../../tools/onnode" ./run_tests.sh ./0090.sh
+
+  Debug the specified test or test failure.  The test will fail
+  because the bash trace output will be included in the test output.
+  However, this at least makes it easy to trace onnode while running
+  the test...
+
+  To see if the test pases, the -x can be dropped... so command-line
+  editing can be kept to a minimum.

Added: branches/ctdb/squeeze-backports/tests/onnode/common.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/common.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/common.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,103 @@
+# Hey Emacs, this is a -*- shell-script -*- !!!  :-)
+
+# Set indirectly by run_tests at top level.
+unset CTDB_NODES_SOCKETS
+
+# Default to just "onnode".
+: ${ONNODE:=onnode}
+
+# Augment PATH with relevant stubs/ directories.
+
+if [ -d "${ONNODE_TESTS_DIR}/stubs" ] ; then
+    PATH="${ONNODE_TESTS_DIR}/stubs:$PATH"
+fi
+
+export ONNODE_TESTCASE_DIR=$(dirname "$0")
+if [ $(basename "$ONNODE_TESTCASE_DIR") = "onnode" ] ; then
+    # Just a test script, no testcase subdirectory.
+    ONNODE_TESTCASE_DIR="$ONNODE_TESTS_DIR"
+else
+    if [ -d "${ONNODE_TESTCASE_DIR}/stubs" ] ; then
+	PATH="${ONNODE_TESTCASE_DIR}/stubs:$PATH"
+    fi
+fi
+
+# Find CTDB nodes file.
+if [ -z "$CTDB_NODES_FILE" ] ; then
+    if [ -r "${ONNODE_TESTCASE_DIR}/nodes" ] ; then
+	CTDB_NODES_FILE="${ONNODE_TESTCASE_DIR}/nodes"
+    elif [ -r "${ONNODE_TESTS_DIR}/nodes" ] ; then
+	CTDB_NODES_FILE="${ONNODE_TESTS_DIR}/nodes"
+    else
+	CTDB_NODES_FILE="${CTDB_BASE:-/etc/ctdb}/nodes"
+    fi
+fi
+
+export CTDB_NODES_FILE
+
+export ONNODE_TESTS_VAR_DIR="${ONNODE_TESTS_DIR}/var"
+mkdir -p "$ONNODE_TESTS_VAR_DIR"
+
+if [ -z "$CTDB_BASE" ] ; then
+    export CTDB_BASE=$(dirname "$CTDB_NODES_FILE")
+fi
+
+define_test ()
+{
+    _f="$0"
+    _f="${_f#./}"  # strip leading ./
+    _f="${_f%%/*}" # if subdir, strip off file
+    _f="${_f%.sh}" # strip off .sh suffix if any
+
+    echo "$_f $1 - $2"
+}
+
+# Set output for ctdb command.  Option 1st argument is return code.
+ctdb_set_output ()
+{
+    _out="$ONNODE_TESTS_VAR_DIR/ctdb.out"
+    cat >"$_out"
+
+    _rc="$ONNODE_TESTS_VAR_DIR/ctdb.rc"
+    echo "${1:-0}" >"$_rc"
+
+    trap "rm -f $_out $_rc" 0
+}
+
+required_result ()
+{
+    required_rc="${1:-0}"
+    required_output=$(cat)
+}
+
+simple_test ()
+{
+    _sort="cat"
+    if [ "$1" = "-s" ] ; then
+	shift
+	_sort="sort"
+    fi
+    _out=$("$@" 2>&1)
+    _rc=$?
+    _out=$(echo "$_out" | $_sort )
+
+    if [ "$_out" = "$required_output" -a $_rc = $required_rc ] ; then
+	echo "PASSED"
+    else
+	cat <<EOF
+CTDB_NODES_FILE="${CTDB_NODES_FILE}"
+CTDB_BASE="$CTDB_BASE"
+$(which ctdb)
+
+##################################################
+Required output (Exit status: ${required_rc}):
+##################################################
+$required_output
+##################################################
+Actual output (Exit status: ${_rc}):
+##################################################
+$_out
+EOF
+	return 1
+    fi
+}

Added: branches/ctdb/squeeze-backports/tests/onnode/nodes
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/nodes	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/nodes	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,4 @@
+192.168.1.101
+192.168.1.102
+192.168.1.103
+192.168.1.104

Added: branches/ctdb/squeeze-backports/tests/onnode/run_tests.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/run_tests.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/run_tests.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# Run some onnode unit tests.
+
+cd $(dirname "$0")
+export ONNODE_TESTS_DIR=$(pwd)
+
+test_dir=$(dirname "$ONNODE_TESTS_DIR")
+
+opts="-d"
+
+for i ; do
+    case "$i" in
+	-*)
+	    opts="$opts $i"
+	    shift
+	    ;;
+	*)
+	    break
+    esac
+done
+
+tests=""
+if [ -z "$*" ] ; then
+    tests=$(ls ./[0-9][0-9][0-9][0-9].sh ./[0-9][0-9][0-9][0-9]/run_test.sh 2>/dev/null)
+fi
+
+"$test_dir/scripts/run_tests" $opts "$@" $tests || exit 1
+
+echo "All OK"
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/run_tests.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/stubs/ctdb
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/stubs/ctdb	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/stubs/ctdb	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# Fake ctdb client for onnode tests.
+
+cmd=$(echo "$*" | sed -r -e 's@[[:space:]]+ at _@g')
+
+out="${ONNODE_TESTS_VAR_DIR}/ctdb.out"
+if [ -r "$out" ] ; then
+    cat "$out"
+
+    rc="${ONNODE_TESTS_VAR_DIR}/ctdb.rc"
+    if [ -r "$rc" ] ; then
+	exit $(cat "$rc")
+    fi
+
+    exit 0
+fi
+
+f="${ONNODE_TESTCASE_DIR}/ctdb.d/${cmd}.sh"
+if [ -x "$f" ] ; then
+    "$f"
+    exit $?
+fi
+
+f="${ONNODE_TESTCASE_DIR}/ctdb.d/${cmd}.out"
+if [ -r "$f" ] ; then
+    cat "$f"
+    exit 0
+fi
+
+echo "fake ctdb: no implementation for \"$*\""
+
+exit 1


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/stubs/ctdb
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/stubs/onnode-buggy-001
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/stubs/onnode-buggy-001	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/stubs/onnode-buggy-001	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,376 @@
+#!/bin/bash
+
+# Run commands on CTDB nodes.
+
+# See http://ctdb.samba.org/ for more information about CTDB.
+
+# Copyright (C) Martin Schwenke  2008
+
+# Based on an earlier script by Andrew Tridgell and Ronnie Sahlberg.
+
+# Copyright (C) Andrew Tridgell  2007
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+   
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+   
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+prog=$(basename $0)
+
+usage ()
+{
+    cat >&2 <<EOF
+Usage: onnode [OPTION] ... <NODES> <COMMAND> ...
+  options:
+    -c          Run in current working directory on specified nodes.
+    -o <prefix> Save standard output from each node to file <prefix>.<ip>
+    -p          Run command in parallel on specified nodes.
+    -q          Do not print node addresses (overrides -v).
+    -n          Allow nodes to be specified by name.
+    -f          Specify nodes file, overrides CTDB_NODES_FILE.
+    -v          Print node address even for a single node.
+  <NODES>       "all", "any", "ok" (or "healthy"), "con" (or "connected"),
+                "rm" (or "recmaster"), "lvs" (or "lvsmaster"),
+                "natgw" (or "natgwlist"); or
+                a node number (0 base); or
+                a hostname (if -n is specified); or
+                list (comma separated) of <NODES>; or
+                range (hyphen separated) of node numbers.
+EOF
+    exit 1
+
+}
+
+invalid_nodespec ()
+{
+    echo "Invalid <nodespec>" >&2 ; echo >&2
+    usage
+}
+
+# Defaults.
+current=false
+parallel=false
+verbose=false
+quiet=false
+prefix=""
+names_ok=false
+
+ctdb_base="${CTDB_BASE:-/etc/ctdb}"
+
+parse_options ()
+{
+    # $POSIXLY_CORRECT means that the command passed to onnode can
+    # take options and getopt won't reorder things to make them
+    # options ot onnode.
+    local temp
+    # Not on the previous line - local returns 0!
+    temp=$(POSIXLY_CORRECT=1 getopt -n "$prog" -o "cf:hno:pqv" -l help -- "$@")
+
+    [ $? != 0 ] && usage
+
+    eval set -- "$temp"
+
+    while true ; do
+	case "$1" in
+	    -c) current=true ; shift ;;
+	    -f) CTDB_NODES_FILE="$2" ; shift 2 ;;
+	    -n) names_ok=true ; shift ;;
+	    -o) prefix="$2" ; shift 2 ;;
+	    -p) parallel=true ; shift ;;
+	    -q) quiet=true ; shift ;;
+	    -v) verbose=true ; shift ;;
+	    --) shift ; break ;;
+	    -h|--help|*) usage ;; # Shouldn't happen, so this is reasonable.
+	esac
+    done
+
+    [ $# -lt 2 ] && usage
+
+    nodespec="$1" ; shift
+    command="$@"
+}
+
+echo_nth ()
+{
+    local n="$1" ; shift
+
+    shift $n
+    local node="$1"
+
+    if [ -n "$node" -a "$node" != "#DEAD" ] ; then
+	echo $node
+    else
+	echo "${prog}: \"node ${n}\" does not exist" >&2
+	exit 1
+    fi
+}
+
+parse_nodespec ()
+{
+    # Subshell avoids hacks to restore $IFS.
+    (
+	IFS=","
+	for i in $1 ; do
+	    case "$i" in
+		*-*) seq "${i%-*}" "${i#*-}" 2>/dev/null || invalid_nodespec ;;
+		# Separate lines for readability.
+		all|any|ok|healthy|con|connected) echo "$i" ;;
+		rm|recmaster|lvs|lvsmaster|natgw|natgwlist) echo "$i" ;;
+		*)
+		    [ $i -gt -1 ] 2>/dev/null || $names_ok || invalid_nodespec
+		    echo $i
+	    esac
+	done
+    )
+}
+
+ctdb_status_output="" # cache
+get_nodes_with_status ()
+{
+    local all_nodes="$1"
+    local status="$2"
+
+    local bits
+    case "$status" in
+	healthy)
+	    bits="0:0:0:0:0:0"
+	    ;;
+	connected)
+	    bits="0:[0-1]:[0-1]:[0-1]:[0-1]:[0-1]"
+	    ;;
+	*)
+	    invalid_nodespec
+    esac
+
+    if [ -z "$ctdb_status_output" ] ; then
+	# FIXME: need to do something if $CTDB_NODES_SOCKETS is set.
+	ctdb_status_output=$(ctdb -Y status 2>/dev/null)
+	if [ $? -ne 0 ] ; then
+	    echo "${prog}: unable to get status of CTDB nodes" >&2
+	    exit 1
+	fi
+	ctdb_status_output="${ctdb_status_output#* }"
+    fi
+
+    local nodes=""
+    local i
+    for i in $ctdb_status_output ; do
+	# Try removing bits from end.
+	local t="${i%:${bits}:}"
+	if [ "$t" != "$i" ] ; then
+	    # Succeeded.  Get address.  NOTE: this is an optimisation.
+	    # It might be better to get the node number and then get
+	    # the nth node to get the address.  This would make things
+	    # more consistent if $ctdb_base/nodes actually contained
+	    # hostnames.
+	    nodes="${nodes} ${t#:*:}"
+	fi
+    done
+
+    echo $nodes
+}
+
+ctdb_props="" # cache
+get_node_with_property ()
+{
+    local all_nodes="$1"
+    local prop="$2"
+
+    local prop_node=""
+    if [ "${ctdb_props##:${prop}:}" = "$ctdb_props" ] ; then
+	prop_node=$(ctdb "$prop" -Y 2>/dev/null)
+	# We only want the first line.
+	local nl="
+"
+	prop_node="${prop_node%%${nl}*}"
+	if [ $? -eq 0 ] ; then
+	    ctdb_props="${ctdb_props}${ctdb_props:+ }:${prop}:${prop_node}"
+	else
+	    prop_node=""
+	fi
+    else
+	prop_node="${ctdb_props##:${prop}:}"
+	prop_node="${prop_node%% *}"
+    fi
+    if [ -n "$prop_node" ] ; then
+	echo_nth "$prop_node" $all_nodes
+    else
+	echo "${prog}: No ${prop} available" >&2
+	exit 1
+    fi
+}
+
+get_any_available_node ()
+{
+    local all_nodes="$1"
+
+    # We do a recursive onnode to find which nodes are up and running.
+    local out=$($0 -pq all ctdb pnn 2>&1)
+    local line
+    while read line ; do 
+	local pnn="${line#PNN:}"
+	if [ "$pnn" != "$line" ] ; then
+	    echo_nth "$pnn" $all_nodes
+	    return 0
+	fi
+	# Else must be an error message from a down node.
+    done <<<"$out"
+    return 1
+}
+
+get_nodes ()
+{
+    local all_nodes
+
+    if [ -n "$CTDB_NODES_SOCKETS" ] ; then 
+	all_nodes="$CTDB_NODES_SOCKETS"
+    else
+	local f="${ctdb_base}/nodes"
+	if [ -n "$CTDB_NODES_FILE" ] ; then
+	    f="$CTDB_NODES_FILE"
+	    if [ ! -e "$f" -a "${f#/}" = "$f" ] ; then
+		# $f is relative, try in $ctdb_base
+		f="${ctdb_base}/${f}"
+	    fi
+	fi
+
+	if [ ! -r "$f" ] ; then
+	    echo "${prog}: unable to open nodes file  \"${f}\"" >&2
+	    exit 1
+	fi
+
+	all_nodes=$(sed -e 's@#.*@@g' -e 's@ *@@g' -e 's@^$@#DEAD@' "$f")
+    fi
+
+    local nodes=""
+    local n
+    for n in $(parse_nodespec "$1") ; do
+	[ $? != 0 ] && exit 1  # Required to catch exit in above subshell.
+	case "$n" in
+	    all)
+		echo "${all_nodes//#DEAD/}"
+		;;
+	    any)
+		get_any_available_node "$all_nodes" || exit 1
+		;;
+	    ok|healthy) 
+		get_nodes_with_status "$all_nodes" "healthy" || exit 1
+		;;
+	    con|connected) 
+		get_nodes_with_status "$all_nodes" "connected" || exit 1
+		;;
+	    rm|recmaster)
+		get_node_with_property "$all_nodes" "recmaster" || exit 1
+		;;
+	    lvs|lvsmaster)
+		get_node_with_property "$all_nodes" "lvsmaster" || exit 1
+		;;
+	    natgw|natgwlist)
+		get_node_with_property "$all_nodes" "natgwlist" || exit 1
+		;;
+	    [0-9]|[0-9][0-9]|[0-9][0-9][0-9])
+		echo_nth $n $all_nodes
+		;;
+	    *)
+		$names_ok || invalid_nodespec
+		echo $n
+	esac
+    done
+}
+
+fakessh ()
+{
+    CTDB_SOCKET="$1" sh -c "$2" 3>/dev/null
+}
+
+stdout_filter ()
+{
+    if [ -n "$prefix" ] ; then
+	cat >"${prefix}.${n//\//_}"
+    elif $verbose && $parallel ; then
+	sed -e "s@^@[$n] @"
+    else
+	cat
+    fi
+}
+
+stderr_filter ()
+{
+    if $verbose && $parallel ; then
+	sed -e "s@^@[$n] @"
+    else
+	cat
+    fi
+}
+
+######################################################################
+
+parse_options "$@"
+
+$current && command="cd $PWD && $command"
+
+ssh_opts=
+if [ -n "$CTDB_NODES_SOCKETS" ] ; then
+    SSH=fakessh
+else 
+    # Could "2>/dev/null || true" but want to see errors from typos in file.
+    [ -r "${ctdb_base}/onnode.conf" ] && . "${ctdb_base}/onnode.conf"
+    [ -n "$SSH" ] || SSH=ssh
+    if [ "$SSH" = "ssh" ] ; then
+	ssh_opts="-n"
+    else
+	: # rsh? All bets are off!
+    fi
+fi
+
+######################################################################
+
+nodes=$(get_nodes "$nodespec")
+[ $? != 0 ] && exit 1   # Required to catch exit in above subshell.
+
+if $quiet ; then
+    verbose=false
+else
+    # If $nodes contains a space or a newline then assume multiple nodes.
+    nl="
+"
+    [ "$nodes" != "${nodes%[ ${nl}]*}" ] && verbose=true
+fi
+
+pids=""
+trap 'kill -TERM $pids 2>/dev/null' INT TERM
+# There's a small race here where the kill can fail if no processes
+# have been added to $pids and the script is interrupted.  However,
+# the part of the window where it matter is very small.
+retcode=0
+for n in $nodes ; do
+    set -o pipefail 2>/dev/null
+    if $parallel ; then
+	{ exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS $n "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; } &
+	pids="${pids} $!"
+    else
+	if $verbose ; then
+	    echo >&2 ; echo ">> NODE: $n <<" >&2
+	fi
+
+	{ exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS $n "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; }
+	[ $? = 0 ] || retcode=$?
+    fi
+done
+
+$parallel && {
+    for p in $pids; do
+	wait $p
+	[ $? = 0 ] || retcode=$?
+    done
+}
+
+exit $retcode


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/stubs/onnode-buggy-001
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/onnode/stubs/ssh
===================================================================
--- branches/ctdb/squeeze-backports/tests/onnode/stubs/ssh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/onnode/stubs/ssh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo "$*"


Property changes on: branches/ctdb/squeeze-backports/tests/onnode/stubs/ssh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/recover.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/recover.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/recover.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+killall -q ctdbd
+
+echo "Starting 4 ctdb daemons"
+bin/ctdbd --recovery-daemon --nlist tests/4nodes.txt
+bin/ctdbd --recovery-daemon --nlist tests/4nodes.txt --listen=127.0.0.2 --socket=/tmp/ctdb.socket.127.0.0.2
+bin/ctdbd --recovery-daemon --nlist tests/4nodes.txt --listen=127.0.0.3 --socket=/tmp/ctdb.socket.127.0.0.3
+bin/ctdbd --recovery-daemon --nlist tests/4nodes.txt --listen=127.0.0.4 --socket=/tmp/ctdb.socket.127.0.0.4
+
+echo
+echo "Attaching to some databases"
+bin/ctdb_control attach test1.tdb || exit 1
+bin/ctdb_control attach test2.tdb || exit 1
+bin/ctdb_control attach test3.tdb || exit 1
+bin/ctdb_control attach test4.tdb || exit 1
+
+echo "Clearing all databases to make sure they are all empty"
+bin/ctdb_control getdbmap 0 | egrep "^dbid:" | sed -e "s/^dbid://" -e "s/ .*$//" | while read DB; do
+	seq 0 3 | while read NODE; do
+		bin/ctdb_control cleardb $NODE $DB
+	done
+done
+
+
+echo
+echo
+echo "Printing all databases on all nodes. they should all be empty"
+echo "============================================================="
+bin/ctdb_control getdbmap 0 | egrep "^dbid:" | sed -e "s/^.*name://" -e "s/ .*$//" | while read DBNAME; do
+	seq 0 3 | while read NODE; do
+		echo "Content of DBNAME:$DBNAME NODE:$NODE :"
+		bin/ctdb_control catdb $DBNAME $NODE
+	done
+done
+
+echo
+echo
+echo "Populating the databases"
+./bin/ctdb_control writerecord 0 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control setdmaster 0 0x220c2a7b 1
+
+./bin/ctdb_control writerecord 1 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control writerecord 1 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control setdmaster 1 0x220c2a7b 2
+
+./bin/ctdb_control writerecord 2 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control writerecord 2 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control writerecord 2 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control setdmaster 2 0x220c2a7b 3
+
+./bin/ctdb_control writerecord 3 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control writerecord 3 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control writerecord 3 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control writerecord 3 0x220c2a7b testkey1 testdata1
+./bin/ctdb_control setdmaster 3 0x220c2a7b 3
+
+
+echo
+echo
+echo "Printing all databases on all nodes. there should be a record there"
+echo "============================================================="
+bin/ctdb_control getdbmap 0 | egrep "^dbid:" | sed -e "s/^.*name://" -e "s/ .*$//" | while read DBNAME; do
+	seq 0 3 | while read NODE; do
+		echo "Content of DBNAME:$DBNAME NODE:$NODE :"
+		bin/ctdb_control catdb $DBNAME $NODE
+	done
+done
+
+echo
+echo
+echo "killing off node #2"
+echo "==================="
+CTDBPID=`./bin/ctdb_control getpid 2 | sed -e "s/Pid://"`
+kill $CTDBPID
+sleep 1
+
+
+echo
+echo
+echo "wait 3 seconds to let the recovery daemon do its job"
+echo "===================================================="
+sleep 3
+
+echo
+echo
+echo "Printing all databases on all nodes."
+echo "The databases should be the same now on all nodes"
+echo "and the record will have been migrated to node 0"
+echo "================================================="
+echo "Node 0:"
+bin/ctdb_control catdb test4.tdb 0
+echo "Node 1:"
+bin/ctdb_control catdb test4.tdb 1
+echo "Node 3:"
+bin/ctdb_control catdb test4.tdb 3
+echo "nodemap:"
+bin/ctdb_control getnodemap 0
+
+echo
+echo
+echo "Traverse the cluster and dump the database"
+bin/ctdb_control catdb test4.tdb
+
+
+#leave the ctdb daemons running   so one can look at the box in more detail
+#killall -q ctdbd


Property changes on: branches/ctdb/squeeze-backports/tests/recover.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/run_tests.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/run_tests.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/run_tests.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+tests/scripts/run_tests -s tests/simple/*.sh || exit 1
+
+echo "All OK"
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/run_tests.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_env
===================================================================
--- branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_env	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_env	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+ctdb_test_scripts_dir=$(cd $(dirname $0) ; pwd)
+export CTDB_DIR=$(dirname $(dirname $ctdb_test_scripts_dir))
+var_dir=$CTDB_DIR/tests/var
+
+######################################################################
+
+ctdb_tools_dir=$CTDB_DIR/tools
+
+PATH="${ctdb_test_scripts_dir}:${ctdb_tools_dir}:${PATH}"
+
+export CTDB_TIMEOUT=60
+
+######################################################################
+
+if [ -n "$CTDB_TEST_REMOTE_DIR" ] ; then
+    CTDB_TEST_WRAPPER="${CTDB_TEST_REMOTE_DIR}/test_wrap"
+else
+    CTDB_TEST_WRAPPER="${ctdb_test_scripts_dir}/test_wrap"
+fi
+export CTDB_TEST_WRAPPER
+
+# If we're not running on a real cluster then we need a local copy of
+# ctdb (and other stuff) in $PATH and we will use local daemons.
+if [ ! -n "$CTDB_TEST_REAL_CLUSTER" ] ; then
+    export CTDB_TEST_NUM_DAEMONS=3
+
+    export CTDB_NODES_SOCKETS=""
+    for i in $(seq 0 $(($CTDB_TEST_NUM_DAEMONS -1))) ; do
+	CTDB_NODES_SOCKETS="${CTDB_NODES_SOCKETS}${CTDB_NODES_SOCKETS:+ }${var_dir}/sock.${i}"
+    done
+
+    PATH="${CTDB_DIR}/bin:${CTDB_DIR}/tests/bin:${PATH}"
+fi
+
+# If $VALGRIND is set then use it whenever ctdb is called, but only if
+# $CTDB is not already set.
+[ -n "$CTDB" ] || export CTDB="${VALGRIND}${VALGRIND:+ }ctdb"
+
+######################################################################
+
+"$@"


Property changes on: branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_env
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_functions.bash
===================================================================
--- branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_functions.bash	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/scripts/ctdb_test_functions.bash	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1115 @@
+# Hey Emacs, this is a -*- shell-script -*- !!!  :-)
+
+fail ()
+{
+    echo "$*"
+    exit 1
+}
+
+######################################################################
+
+ctdb_test_begin ()
+{
+    local name="$1"
+
+    teststarttime=$(date '+%s')
+    testduration=0
+
+    echo "--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--"
+    echo "Running test $name ($(date '+%T'))"
+    echo "--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--"
+}
+
+ctdb_test_end ()
+{
+    local name="$1" ; shift
+    local status="$1" ; shift
+    # "$@" is command-line
+
+    local interp="SKIPPED"
+    local statstr=" (reason $*)"
+    if [ -n "$status" ] ; then
+	if [ $status -eq 0 ] ; then
+	    interp="PASSED"
+	    statstr=""
+	    echo "ALL OK: $*"
+	else
+	    interp="FAILED"
+	    statstr=" (status $status)"
+	    testfailures=$(($testfailures+1))
+	fi
+    fi
+
+    testduration=$(($(date +%s)-$teststarttime))
+
+    echo "=========================================================================="
+    echo "TEST ${interp}: ${name}${statstr} (duration: ${testduration}s)"
+    echo "=========================================================================="
+
+}
+
+test_exit ()
+{
+    exit $(($testfailures+0))
+}
+
+ctdb_check_time_logs ()
+{
+    local threshold=20
+
+    local jump=false
+    local prev=""
+    local ds_prev=""
+    local node=""
+
+    out=$(onnode all tail -n 20 /var/log/ctdb.test.time.log 2>&1)
+
+    if [ $? -eq 0 ] ; then
+	local line
+	while read line ; do
+	    case "$line" in
+		\>\>\ NODE:\ *\ \<\<)
+		    node="${line#>> NODE: }"
+		    node=${node% <<*}
+		    ds_prev=""
+		    ;;
+		*\ *)
+		    set -- $line
+		    ds_curr="$1${2:0:1}"
+		    if [ -n "$ds_prev" ] && \
+			[ $(($ds_curr - $ds_prev)) -ge $threshold ] ; then
+			echo "Node $node had time jump of $(($ds_curr - $ds_prev))ds between $(date +'%T' -d @${ds_prev%?}) and $(date +'%T' -d @${ds_curr%?})"
+			jump=true
+		    fi
+		    prev="$line"
+		    ds_prev="$ds_curr"
+		    ;;
+	    esac
+	done <<<"$out"
+    else
+	echo Error getting time logs
+    fi
+    if $jump ; then
+	echo "Check time sync (test client first):"
+	date
+	onnode -p all date
+	echo "Information from test client:"
+	hostname
+	top -b -n 1
+	echo "Information from cluster nodes:"
+	onnode all "top -b -n 1 ; echo '/proc/slabinfo' ; cat /proc/slabinfo"
+    fi
+}
+
+ctdb_test_exit ()
+{
+    local status=$?
+
+    trap - 0
+
+    [ $(($testfailures+0)) -eq 0 -a $status -ne 0 ] && testfailures=$status
+    status=$(($testfailures+0))
+
+    # Avoid making a test fail from this point onwards.  The test is
+    # now complete.
+    set +e
+
+    echo "*** TEST COMPLETED (RC=$status) AT $(date '+%F %T'), CLEANING UP..."
+
+    if [ -n "$CTDB_TEST_REAL_CLUSTER" -a $status -ne 0 ] ; then
+	ctdb_check_time_logs
+    fi
+
+    eval "$ctdb_test_exit_hook" || true
+    unset ctdb_test_exit_hook
+
+    if $ctdb_test_restart_scheduled || ! cluster_is_healthy ; then
+
+	restart_ctdb
+    else
+	# This could be made unconditional but then we might get
+	# duplication from the recovery in restart_ctdb.  We want to
+	# leave the recovery in restart_ctdb so that future tests that
+	# might do a manual restart mid-test will benefit.
+	echo "Forcing a recovery..."
+	onnode 0 $CTDB recover
+    fi
+
+    exit $status
+}
+
+ctdb_test_exit_hook_add ()
+{
+    ctdb_test_exit_hook="${ctdb_test_exit_hook}${ctdb_test_exit_hook:+ ; }$*"
+}
+
+ctdb_test_run ()
+{
+    local name="$1" ; shift
+    
+    [ -n "$1" ] || set -- "$name"
+
+    ctdb_test_begin "$name"
+
+    local status=0
+    "$@" || status=$?
+
+    ctdb_test_end "$name" "$status" "$*"
+    
+    return $status
+}
+
+ctdb_test_usage()
+{
+    local status=${1:-2}
+    
+    cat <<EOF
+Usage: $0 [option]
+
+Options:	
+    -h, --help          show this screen.
+    -v, --version       show test case version.
+    --category          show the test category (ACL, CTDB, Samba ...).
+    -d, --description   show test case description.
+    --summary           show short test case summary.
+    -x                  trace test using set -x
+EOF
+
+    exit $status
+}
+
+ctdb_test_version ()
+{
+    [ -n "$CTDB_DIR" ] || fail "Can not determine version."
+
+    (cd "$CTDB_DIR" && git describe)
+}
+
+ctdb_test_cmd_options()
+{
+    [ -n "$1" ] || return 0
+
+    case "$1" in
+        -h|--help)        ctdb_test_usage 0   ;;
+        -v|--version)     ctdb_test_version   ;;
+        --category)       echo "CTDB"         ;; 
+        -d|--description) test_info           ;;
+	-x)               set -x ; return 0   ;;
+	*)
+	    echo "Error: Unknown parameter = $1"
+	    echo
+	    ctdb_test_usage 2
+	    ;;
+    esac
+
+    exit 0
+}
+
+ctdb_test_init () 
+{
+    scriptname=$(basename "$0")
+    testfailures=0
+    ctdb_test_restart_scheduled=false
+
+    ctdb_test_cmd_options $@
+
+    trap "ctdb_test_exit" 0
+}
+
+ctdb_test_check_real_cluster ()
+{
+    [ -n "$CTDB_TEST_REAL_CLUSTER" ] && return 0
+
+    echo "ERROR: This test must be run on a real/virtual cluster, not local daemons."
+    return 1
+}
+
+########################################
+
+# Sets: $out
+try_command_on_node ()
+{
+    local nodespec="$1" ; shift
+
+    local verbose=false
+    local onnode_opts=""
+
+    while [ "${nodespec#-}" != "$nodespec" ] ; do
+	if [ "$nodespec" = "-v" ] ; then
+	    verbose=true
+	else
+	    onnode_opts="$nodespec"
+	fi
+	nodespec="$1" ; shift
+    done
+
+    local cmd="$*"
+
+    out=$(onnode -q $onnode_opts "$nodespec" "$cmd" 2>&1) || {
+
+	echo "Failed to execute \"$cmd\" on node(s) \"$nodespec\""
+	echo "$out"
+	return 1
+    }
+
+    if $verbose ; then
+	echo "Output of \"$cmd\":"
+	echo "$out"
+    fi
+}
+
+sanity_check_output ()
+{
+    local min_lines="$1"
+    local regexp="$2" # Should be anchored as necessary.
+    local output="$3"
+
+    local ret=0
+
+    local num_lines=$(echo "$output" | wc -l)
+    echo "There are $num_lines lines of output"
+    if [ $num_lines -lt $min_lines ] ; then
+	echo "BAD: that's less than the required number (${min_lines})"
+	ret=1
+    fi
+
+    local status=0
+    local unexpected # local doesn't pass through status of command on RHS.
+    unexpected=$(echo "$output" | egrep -v "$regexp") || status=$?
+
+    # Note that this is reversed.
+    if [ $status -eq 0 ] ; then
+	echo "BAD: unexpected lines in output:"
+	echo "$unexpected" | cat -A
+	ret=1
+    else
+	echo "Output lines look OK"
+    fi
+
+    return $ret
+}
+
+sanity_check_ips ()
+{
+    local ips="$1" # list of "ip node" lines
+
+    echo "Sanity checking IPs..."
+
+    local x ipp prev
+    prev=""
+    while read x ipp ; do
+	[ "$ipp" = "-1" ] && break
+	if [ -n "$prev" -a "$ipp" != "$prev" ] ; then
+	    echo "OK"
+	    return 0
+	fi
+	prev="$ipp"
+    done <<<"$ips"
+
+    echo "BAD: a node was -1 or IPs are only assigned to one node"
+    echo "Are you running an old version of CTDB?"
+    return 1
+}
+
+# This returns a list of "ip node" lines in $out
+all_ips_on_node()
+{
+    local node=$@
+    try_command_on_node $node "$CTDB ip -Y -n all | cut -d ':' -f1-3 | sed -e '1d' -e 's@^:@@' -e 's@:@ @g'"
+}
+
+select_test_node_and_ips ()
+{
+    all_ips_on_node 0
+
+    # When selecting test_node we just want a node that has public
+    # IPs.  This will work and is economically semi-random.  :-)
+    local x
+    read x test_node <<<"$out"
+
+    test_node_ips=""
+    local ip pnn
+    while read ip pnn ; do
+	if [ "$pnn" = "$test_node" ] ; then
+            test_node_ips="${test_node_ips}${test_node_ips:+ }${ip}"
+	fi
+    done <<<"$out" # bashism to avoid problem setting variable in pipeline.
+
+    echo "Selected node ${test_node} with IPs: ${test_node_ips}."
+    test_ip="${test_node_ips%% *}"
+}
+
+#######################################
+
+# Wait until either timeout expires or command succeeds.  The command
+# will be tried once per second.
+wait_until ()
+{
+    local timeout="$1" ; shift # "$@" is the command...
+
+    local negate=false
+    if [ "$1" = "!" ] ; then
+	negate=true
+	shift
+    fi
+
+    echo -n "<${timeout}|"
+    local t=$timeout
+    while [ $t -gt 0 ] ; do
+	local rc=0
+	"$@" || rc=$?
+	if { ! $negate && [ $rc -eq 0 ] ; } || \
+	    { $negate && [ $rc -ne 0 ] ; } ; then
+	    echo "|$(($timeout - $t))|"
+	    echo "OK"
+	    return 0
+	fi
+	echo -n .
+	t=$(($t - 1))
+	sleep 1
+    done
+    
+    echo "*TIMEOUT*"
+    
+    return 1
+}
+
+sleep_for ()
+{
+    echo -n "=${1}|"
+    for i in $(seq 1 $1) ; do
+	echo -n '.'
+	sleep 1
+    done
+    echo '|'
+}
+
+_cluster_is_healthy ()
+{
+    local out x count line
+
+    out=$($CTDB -Y status 2>/dev/null) || return 1
+
+    {
+        read x
+	count=0
+        while read line ; do
+	    # We need to see valid lines if we're going to be healthy.
+	    [ "${line#:[0-9]}" != "$line" ] && count=$(($count + 1))
+	    # A line indicating a node is unhealthy causes failure.
+	    [ "${line##:*:*:*1:}" != "$line" ] && return 1
+        done
+	[ $count -gt 0 ] && return $?
+    } <<<"$out" # Yay bash!
+}
+
+cluster_is_healthy ()
+{
+    if onnode 0 $CTDB_TEST_WRAPPER _cluster_is_healthy ; then
+	echo "Cluster is HEALTHY"
+	return 0
+    else
+	echo "Cluster is UNHEALTHY"
+	if ! ${ctdb_test_restart_scheduled:-false} ; then
+	    echo "DEBUG AT $(date '+%F %T'):"
+	    local i
+	    for i in "onnode -q 0 $CTDB status" "onnode -q 0 onnode all $CTDB scriptstatus" ; do
+		echo "$i"
+		$i || true
+	    done
+	fi
+	return 1
+    fi
+}
+
+wait_until_healthy ()
+{
+    local timeout="${1:-120}"
+
+    echo "Waiting for cluster to become healthy..."
+
+    wait_until 120 _cluster_is_healthy
+}
+
+# This function is becoming nicely overloaded.  Soon it will collapse!  :-)
+node_has_status ()
+{
+    local pnn="$1"
+    local status="$2"
+
+    local bits fpat mpat
+    case "$status" in
+	(unhealthy)    bits="?:?:?:1:*" ;;
+	(healthy)      bits="?:?:?:0:*" ;;
+	(disconnected) bits="1:*" ;;
+	(connected)    bits="0:*" ;;
+	(banned)       bits="?:1:*" ;;
+	(unbanned)     bits="?:0:*" ;;
+	(disabled)     bits="?:?:1:*" ;;
+	(enabled)      bits="?:?:0:*" ;;
+	(stopped)      bits="?:?:?:?:1:*" ;;
+	(notstopped)   bits="?:?:?:?:0:*" ;;
+	(frozen)       fpat='^[[:space:]]+frozen[[:space:]]+1$' ;;
+	(unfrozen)     fpat='^[[:space:]]+frozen[[:space:]]+0$' ;;
+	(monon)        mpat='^Monitoring mode:ACTIVE \(0\)$' ;;
+	(monoff)       mpat='^Monitoring mode:DISABLED \(1\)$' ;;
+	*)
+	    echo "node_has_status: unknown status \"$status\""
+	    return 1
+    esac
+
+    if [ -n "$bits" ] ; then
+	local out x line
+
+	out=$($CTDB -Y status 2>&1) || return 1
+
+	{
+            read x
+            while read line ; do
+		# This needs to be done in 2 steps to avoid false matches.
+		local line_bits="${line#:${pnn}:*:}"
+		[ "$line_bits" = "$line" ] && continue
+		[ "${line_bits#${bits}}" != "$line_bits" ] && return 0
+            done
+	    return 1
+	} <<<"$out" # Yay bash!
+    elif [ -n "$fpat" ] ; then
+	$CTDB statistics -n "$pnn" | egrep -q "$fpat"
+    elif [ -n "$mpat" ] ; then
+	$CTDB getmonmode -n "$pnn" | egrep -q "$mpat"
+    else
+	echo 'node_has_status: unknown mode, neither $bits nor $fpat is set'
+	return 1
+    fi
+}
+
+wait_until_node_has_status ()
+{
+    local pnn="$1"
+    local status="$2"
+    local timeout="${3:-30}"
+    local proxy_pnn="${4:-any}"
+
+    echo "Waiting until node $pnn has status \"$status\"..."
+
+    if ! wait_until $timeout onnode $proxy_pnn $CTDB_TEST_WRAPPER node_has_status "$pnn" "$status" ; then
+	for i in "onnode -q any $CTDB status" "onnode -q any onnode all $CTDB scriptstatus" ; do
+	    echo "$i"
+	    $i || true
+	done
+
+	return 1
+    fi
+
+}
+
+# Useful for superficially testing IP failover.
+# IPs must be on nodes matching nodeglob.
+ips_are_on_nodeglob ()
+{
+    local nodeglob="$1" ; shift
+    local ips="$*"
+
+    local out
+
+    all_ips_on_node 1
+
+    while read ip pnn ; do
+	for check in $ips ; do
+	    if [ "$check" = "$ip" ] ; then
+		case "$pnn" in
+		    ($nodeglob) : ;;
+		    (*) return 1  ;;
+		esac
+		ips="${ips/${ip}}" # Remove from list
+	    fi
+	done
+    done <<<"$out" # bashism to avoid problem setting variable in pipeline.
+
+    ips="${ips// }" # Remove any spaces.
+    [ -z "$ips" ]
+}
+
+wait_until_ips_are_on_nodeglob ()
+{
+    echo "Waiting for IPs to fail over..."
+
+    wait_until 60 ips_are_on_nodeglob "$@"
+}
+
+node_has_some_ips ()
+{
+    local node="$1"
+
+    local out
+
+    all_ips_on_node 1
+
+    while read ip pnn ; do
+	if [ "$node" = "$pnn" ] ; then
+	    return 0
+	fi
+    done <<<"$out" # bashism to avoid problem setting variable in pipeline.
+
+    return 1
+}
+
+wait_until_node_has_some_ips ()
+{
+    echo "Waiting for node to have some IPs..."
+
+    wait_until 60 node_has_some_ips "$@"
+}
+
+get_src_socket ()
+{
+    local proto="$1"
+    local dst_socket="$2"
+    local pid="$3"
+    local prog="$4"
+
+    local pat="^${proto}[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+[[:space:]]+[^[:space:]]+[[:space:]]+${dst_socket//./\\.}[[:space:]]+ESTABLISHED[[:space:]]+${pid}/${prog}[[:space:]]*\$"
+    out=$(netstat -tanp |
+	egrep "$pat" |
+	awk '{ print $4 }')
+
+    [ -n "$out" ]
+}
+
+wait_until_get_src_socket ()
+{
+    local proto="$1"
+    local dst_socket="$2"
+    local pid="$3"
+    local prog="$4"
+
+    echo "Waiting for ${prog} to establish connection to ${dst_socket}..."
+
+    wait_until 5 get_src_socket "$@"
+}
+
+#######################################
+
+# filename will be in $tcpdump_filename, pid in $tcpdump_pid
+tcpdump_start ()
+{
+    tcpdump_filter="$1" # global
+
+    echo "Running tcpdump..."
+    tcpdump_filename=$(mktemp)
+    ctdb_test_exit_hook_add "rm -f $tcpdump_filename"
+
+    # The only way of being sure that tcpdump is listening is to send
+    # some packets that it will see.  So we use dummy pings - the -U
+    # option to tcpdump ensures that packets are flushed to the file
+    # as they are captured.
+    local dummy_addr="127.3.2.1"
+    local dummy="icmp and dst host ${dummy_addr} and icmp[icmptype] == icmp-echo"
+    tcpdump -n -p -s 0 -e -U -w $tcpdump_filename -i any "($tcpdump_filter) or ($dummy)" &
+    ctdb_test_exit_hook_add "kill $! >/dev/null 2>&1"
+
+    echo "Waiting for tcpdump output file to be ready..."
+    ping -q "$dummy_addr" >/dev/null 2>&1 &
+    ctdb_test_exit_hook_add "kill $! >/dev/null 2>&1"
+
+    tcpdump_listen_for_dummy ()
+    {
+	tcpdump -n -r $tcpdump_filename -c 1 "$dummy" >/dev/null 2>&1
+    }
+
+    wait_until 10 tcpdump_listen_for_dummy
+}
+
+# By default, wait for 1 matching packet.
+tcpdump_wait ()
+{
+    local count="${1:-1}"
+    local filter="${2:-${tcpdump_filter}}"
+
+    tcpdump_check ()
+    {
+	local found=$(tcpdump -n -r $tcpdump_filename "$filter" 2>/dev/null | wc -l)
+	[ $found -ge $count ]
+    }
+
+    echo "Waiting for tcpdump to capture some packets..."
+    if ! wait_until 30 tcpdump_check ; then
+	echo "DEBUG AT $(date '+%F %T'):"
+	local i
+	for i in "onnode -q 0 $CTDB status" "netstat -tanp" "tcpdump -n -e -r $tcpdump_filename" ; do
+	    echo "$i"
+	    $i || true
+	done
+	return 1
+    fi
+}
+
+tcpdump_show ()
+{
+    local filter="${1:-${tcpdump_filter}}"
+
+    tcpdump -n -r $tcpdump_filename  "$filter" 2>/dev/null
+}
+
+tcptickle_sniff_start ()
+{
+    local src="$1"
+    local dst="$2"
+
+    local in="src host ${dst%:*} and tcp src port ${dst##*:} and dst host ${src%:*} and tcp dst port ${src##*:}"
+    local out="src host ${src%:*} and tcp src port ${src##*:} and dst host ${dst%:*} and tcp dst port ${dst##*:}"
+    local tickle_ack="${in} and (tcp[tcpflags] & tcp-ack != 0) and (tcp[14] == 4) and (tcp[15] == 210)" # win == 1234
+    local ack_ack="${out} and (tcp[tcpflags] & tcp-ack != 0)"
+    tcptickle_reset="${in} and tcp[tcpflags] & tcp-rst != 0"
+    local filter="(${tickle_ack}) or (${ack_ack}) or (${tcptickle_reset})"
+
+    tcpdump_start "$filter"
+}
+
+tcptickle_sniff_wait_show ()
+{
+    tcpdump_wait 1 "$tcptickle_reset"
+
+    echo "GOOD: here are some TCP tickle packets:"
+    tcpdump_show
+}
+
+gratarp_sniff_start ()
+{
+    tcpdump_start "arp host ${test_ip}"
+}
+
+gratarp_sniff_wait_show ()
+{
+    tcpdump_wait 2
+
+    echo "GOOD: this should be the some gratuitous ARPs:"
+    tcpdump_show
+}
+
+
+#######################################
+
+daemons_stop ()
+{
+    echo "Attempting to politely shutdown daemons..."
+    onnode 1 $CTDB shutdown -n all || true
+
+    echo "Sleeping for a while..."
+    sleep_for 1
+
+    if pgrep -f $CTDB_DIR/bin/ctdbd >/dev/null ; then
+	echo "Killing remaining daemons..."
+	pkill -f $CTDB_DIR/bin/ctdbd
+
+	if pgrep -f $CTDB_DIR/bin/ctdbd >/dev/null ; then
+	    echo "Once more with feeling.."
+	    pkill -9 $CTDB_DIR/bin/ctdbd
+	fi
+    fi
+
+    local var_dir=$CTDB_DIR/tests/var
+    rm -rf $var_dir/test.db
+}
+
+daemons_setup ()
+{
+    local num_nodes="${CTDB_TEST_NUM_DAEMONS:-2}" # default is 2 nodes
+
+    local var_dir=$CTDB_DIR/tests/var
+
+    mkdir -p $var_dir/test.db/persistent
+
+    local nodes=$var_dir/nodes.txt
+    local public_addresses=$var_dir/public_addresses.txt
+    local no_public_addresses=$var_dir/no_public_addresses.txt
+    rm -f $nodes $public_addresses $no_public_addresses
+
+    # If there are (strictly) greater than 2 nodes then we'll randomly
+    # choose a node to have no public addresses.
+    local no_public_ips=-1
+    [ $num_nodes -gt 2 ] && no_public_ips=$(($RANDOM % $num_nodes))
+    echo "$no_public_ips" >$no_public_addresses
+
+    local i
+    for i in $(seq 1 $num_nodes) ; do
+	if [ "${CTDB_USE_IPV6}x" != "x" ]; then
+	    echo ::$i >> $nodes
+	    ip addr add ::$i/128 dev lo
+	else
+	    echo 127.0.0.$i >> $nodes
+	    # 2 public addresses on most nodes, just to make things interesting.
+	    if [ $(($i - 1)) -ne $no_public_ips ] ; then
+		echo "192.0.2.$i/24 lo" >> $public_addresses
+		echo "192.0.2.$(($i + $num_nodes))/24 lo" >> $public_addresses
+	    fi
+	fi
+    done
+}
+
+daemons_start_1 ()
+{
+    local pnn="$1"
+    shift # "$@" gets passed to ctdbd
+
+    local var_dir=$CTDB_DIR/tests/var
+
+    local nodes=$var_dir/nodes.txt
+    local public_addresses=$var_dir/public_addresses.txt
+    local no_public_addresses=$var_dir/no_public_addresses.txt
+
+    local no_public_ips=-1
+    [ -r $no_public_addresses ] && read no_public_ips <$no_public_addresses
+
+    if  [ "$no_public_ips" = $pnn ] ; then
+	echo "Node $no_public_ips will have no public IPs."
+    fi
+
+    local ctdb_options="--reclock=$var_dir/rec.lock --nlist $nodes --nopublicipcheck --event-script-dir=$CTDB_DIR/tests/events.d --logfile=$var_dir/daemons.log -d 0 --dbdir=$var_dir/test.db --dbdir-persistent=$var_dir/test.db/persistent --dbdir-state=$var_dir/test.db/state"
+
+    if [ $(id -u) -eq 0 ]; then
+        ctdb_options="$ctdb_options --public-interface=lo"
+    fi
+
+    if [ $pnn -eq $no_public_ips ] ; then
+	ctdb_options="$ctdb_options --public-addresses=/dev/null"
+    else
+	ctdb_options="$ctdb_options --public-addresses=$public_addresses"
+    fi
+
+    # Need full path so we can use "pkill -f" to kill the daemons.
+    $VALGRIND $CTDB_DIR/bin/ctdbd --socket=$var_dir/sock.$pnn $ctdb_options "$@" ||return 1
+}
+
+daemons_start ()
+{
+    # "$@" gets passed to ctdbd
+
+    local num_nodes="${CTDB_TEST_NUM_DAEMONS:-2}" # default is 2 nodes
+
+    echo "Starting $num_nodes ctdb daemons..."
+
+    for i in $(seq 0 $(($num_nodes - 1))) ; do
+	daemons_start_1 $i "$@"
+    done
+
+    local var_dir=$CTDB_DIR/tests/var
+
+    if [ -L /tmp/ctdb.socket -o ! -S /tmp/ctdb.socket ] ; then 
+	ln -sf $var_dir/sock.0 /tmp/ctdb.socket || return 1
+    fi
+}
+
+#######################################
+
+_ctdb_hack_options ()
+{
+    local ctdb_options="$*"
+
+    # We really just want to pass CTDB_OPTIONS but on RH
+    # /etc/sysconfig/ctdb can, and frequently does, set that variable.
+    # So instead, we hack badly.  We'll add these as we use them.
+    # Note that these may still be overridden by the above file... but
+    # we tend to use the exotic options here... so that is unlikely.
+
+    case "$ctdb_options" in
+	*--start-as-stopped*)
+	    export CTDB_START_AS_STOPPED="yes"
+    esac
+}
+
+_restart_ctdb ()
+{
+    _ctdb_hack_options "$@"
+
+    if [ -e /etc/redhat-release ] ; then
+	service ctdb restart
+    else
+	/etc/init.d/ctdb restart
+    fi
+}
+
+_ctdb_start ()
+{
+    _ctdb_hack_options "$@"
+
+    /etc/init.d/ctdb start
+}
+
+setup_ctdb ()
+{
+    if [ -n "$CTDB_NODES_SOCKETS" ] ; then
+	daemons_setup
+    fi
+}
+
+# Common things to do after starting one or more nodes.
+_ctdb_start_post ()
+{
+    onnode -q 1  $CTDB_TEST_WRAPPER wait_until_healthy || return 1
+
+    echo "Setting RerecoveryTimeout to 1"
+    onnode -pq all "$CTDB setvar RerecoveryTimeout 1"
+
+    # In recent versions of CTDB, forcing a recovery like this blocks
+    # until the recovery is complete.  Hopefully this will help the
+    # cluster to stabilise before a subsequent test.
+    echo "Forcing a recovery..."
+    onnode -q 0 $CTDB recover
+    sleep_for 1
+    echo "Forcing a recovery..."
+    onnode -q 0 $CTDB recover
+
+    echo "ctdb is ready"
+}
+
+# This assumes that ctdbd is not running on the given node.
+ctdb_start_1 ()
+{
+    local pnn="$1"
+    shift # "$@" is passed to ctdbd start.
+
+    echo -n "Starting CTDB on node ${pnn}..."
+    
+    if [ -n "$CTDB_NODES_SOCKETS" ] ; then
+	daemons_start_1 $pnn "$@"
+    else
+	onnode $pnn $CTDB_TEST_WRAPPER _ctdb_start "$@"
+    fi
+
+    # If we're starting only 1 node then we're doing something weird.
+    ctdb_restart_when_done
+}
+
+restart_ctdb ()
+{
+    # "$@" is passed to ctdbd start.
+
+    echo -n "Restarting CTDB"
+    if $ctdb_test_restart_scheduled ; then
+	echo -n " (scheduled)"
+    fi
+    echo "..."
+
+    local i
+    for i in $(seq 1 5) ; do
+	if [ -n "$CTDB_NODES_SOCKETS" ] ; then
+	    daemons_stop
+	    daemons_start "$@"
+	else
+	    onnode -p all $CTDB_TEST_WRAPPER _restart_ctdb "$@"
+	fi || {
+	    echo "Restart failed.  Trying again in a few seconds..."
+	    sleep_for 5
+	    continue
+	}
+
+	onnode -q 1  $CTDB_TEST_WRAPPER wait_until_healthy || {
+	    echo "Cluster didn't become healthy.  Restarting..."
+	    continue
+	}
+
+	local debug_out=$(onnode -p all ctdb status -Y 2>&1; onnode -p all ctdb scriptstatus 2>&1)
+
+	echo "Setting RerecoveryTimeout to 1"
+	onnode -pq all "$CTDB setvar RerecoveryTimeout 1"
+
+	# In recent versions of CTDB, forcing a recovery like this
+	# blocks until the recovery is complete.  Hopefully this will
+	# help the cluster to stabilise before a subsequent test.
+	echo "Forcing a recovery..."
+	onnode -q 0 $CTDB recover
+	sleep_for 1
+	echo "Forcing a recovery..."
+	onnode -q 0 $CTDB recover
+
+	# Cluster is still healthy.  Good, we're done!
+	if ! onnode 0 $CTDB_TEST_WRAPPER _cluster_is_healthy ; then
+	    echo "Cluster become UNHEALTHY again.  Restarting..."
+	    continue
+	fi
+
+	echo "Doing a sync..."
+	onnode -q 0 $CTDB sync
+
+	echo "ctdb is ready"
+	return 0
+    done
+
+    echo "Cluster UNHEALTHY...  too many attempts..."
+    echo "$debug_out"
+    # Try to make the calling test fail
+    status=1
+    return 1
+}
+
+ctdb_restart_when_done ()
+{
+    ctdb_test_restart_scheduled=true
+}
+
+#######################################
+
+install_eventscript ()
+{
+    local script_name="$1"
+    local script_contents="$2"
+
+    if [ -n "$CTDB_TEST_REAL_CLUSTER" ] ; then
+	# The quoting here is *very* fragile.  However, we do
+	# experience the joy of installing a short script using
+	# onnode, and without needing to know the IP addresses of the
+	# nodes.
+	onnode all "f=\"\${CTDB_BASE:-/etc/ctdb}/events.d/${script_name}\" ; echo \"Installing \$f\" ; echo '${script_contents}' > \"\$f\" ; chmod 755 \"\$f\""
+    else
+	f="${CTDB_DIR}/tests/events.d/${script_name}"
+	echo "$script_contents" >"$f"
+	chmod 755 "$f"
+    fi
+}
+
+uninstall_eventscript ()
+{
+    local script_name="$1"
+
+    if [ -n "$CTDB_TEST_REAL_CLUSTER" ] ; then
+	onnode all "rm -vf \"\${CTDB_BASE:-/etc/ctdb}/events.d/${script_name}\""
+    else
+	rm -vf "${CTDB_DIR}/tests/events.d/${script_name}"
+    fi
+}
+
+#######################################
+
+# This section deals with the 99.ctdb_test eventscript.
+
+# Metafunctions: Handle a ctdb-test file on a node.
+# given event.
+ctdb_test_eventscript_file_create ()
+{
+    local pnn="$1"
+    local type="$2"
+
+    try_command_on_node $pnn touch "/tmp/ctdb-test-${type}.${pnn}"
+}
+
+ctdb_test_eventscript_file_remove ()
+{
+    local pnn="$1"
+    local type="$2"
+
+    try_command_on_node $pnn rm -f "/tmp/ctdb-test-${type}.${pnn}"
+}
+
+ctdb_test_eventscript_file_exists ()
+{
+    local pnn="$1"
+    local type="$2"
+
+    try_command_on_node $pnn test -f "/tmp/ctdb-test-${type}.${pnn}" >/dev/null 2>&1
+}
+
+
+# Handle a flag file on a node that is removed by 99.ctdb_test on the
+# given event.
+ctdb_test_eventscript_flag ()
+{
+    local cmd="$1"
+    local pnn="$2"
+    local event="$3"
+
+    ctdb_test_eventscript_file_${cmd} "$pnn" "flag-${event}"
+}
+
+
+# Handle a trigger that causes 99.ctdb_test to fail it's monitor
+# event.
+ctdb_test_eventscript_unhealthy_trigger ()
+{
+    local cmd="$1"
+    local pnn="$2"
+
+    ctdb_test_eventscript_file_${cmd} "$pnn" "unhealthy-trigger"
+}
+
+# Handle the file that 99.ctdb_test created to show that it has marked
+# a node unhealthy because it detected the above trigger.
+ctdb_test_eventscript_unhealthy_detected ()
+{
+    local cmd="$1"
+    local pnn="$2"
+
+    ctdb_test_eventscript_file_${cmd} "$pnn" "unhealthy-detected"
+}
+
+# Handle a trigger that causes 99.ctdb_test to timeout it's monitor
+# event.  This should cause the node to be banned.
+ctdb_test_eventscript_timeout_trigger ()
+{
+    local cmd="$1"
+    local pnn="$2"
+    local event="$3"
+
+    ctdb_test_eventscript_file_${cmd} "$pnn" "${event}-timeout"
+}
+
+# Note that the eventscript can't use the above functions!
+ctdb_test_eventscript_install ()
+{
+
+    local script='#!/bin/sh
+out=$(ctdb pnn)
+pnn="${out#PNN:}"
+
+rm -vf "/tmp/ctdb-test-flag-${1}.${pnn}"
+
+trigger="/tmp/ctdb-test-unhealthy-trigger.${pnn}"
+detected="/tmp/ctdb-test-unhealthy-detected.${pnn}"
+timeout_trigger="/tmp/ctdb-test-${1}-timeout.${pnn}"
+case "$1" in
+    monitor)
+        if [ -e "$trigger" ] ; then
+            echo "${0}: Unhealthy because \"$trigger\" detected"
+            touch "$detected"
+            exit 1
+        elif [ -e "$detected" -a ! -e "$trigger" ] ; then
+            echo "${0}: Healthy again, \"$trigger\" no longer detected"
+            rm "$detected"
+        fi
+	
+	;;
+    *)
+        if [ -e "$timeout_trigger" ] ; then
+            echo "${0}: Sleeping for a long time because \"$timeout_trigger\" detected"
+            sleep 9999
+        fi
+	;;
+	*)
+	
+esac
+
+exit 0
+'
+    install_eventscript "99.ctdb_test" "$script"
+}
+
+ctdb_test_eventscript_uninstall ()
+{
+    uninstall_eventscript "99.ctdb_test"
+}
+
+# Note that this only works if you know all other monitor events will
+# succeed.  You also need to install the eventscript before using it.
+wait_for_monitor_event ()
+{
+    local pnn="$1"
+
+    echo "Waiting for a monitor event on node ${pnn}..."
+    ctdb_test_eventscript_flag create $pnn "monitor"
+
+    wait_until 120 ! ctdb_test_eventscript_flag exists $pnn "monitor"
+
+}
+
+# Make sure that $CTDB is set.
+: ${CTDB:=ctdb}

Added: branches/ctdb/squeeze-backports/tests/scripts/run_tests
===================================================================
--- branches/ctdb/squeeze-backports/tests/scripts/run_tests	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/scripts/run_tests	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+# The ability of ctdb_test_env to take tests on the command-line is
+# nice, but here we need to hack around it with that colon to reset
+# the arguments that it sees.
+. $(dirname $0)/ctdb_test_env :
+
+. ctdb_test_functions.bash
+
+usage() {
+    cat <<EOF
+Usage: run_tests [OPTIONS] [TESTS]
+
+EOF
+    exit 1
+}
+
+######################################################################
+
+with_summary=false
+with_desc=false
+quiet=false
+
+temp=$(getopt -n "$prog" -o "xdhqs" -l help -- "$@")
+
+[ $? != 0 ] && usage
+
+eval set -- "$temp"
+
+while true ; do
+    case "$1" in
+	-x) set -x; shift ;;
+	-d) with_desc=true ; shift ;;  # 4th line of output is description
+	-q) quiet=true ; shift ;;
+	-s) with_summary=true ; shift ;;
+	--) shift ; break ;;
+	*) usage ;;
+    esac
+done
+
+if $quiet ; then
+    show_progress() { cat >/dev/null ; }
+else
+    show_progress() { cat ; }
+fi
+
+######################################################################
+
+tests_total=0
+tests_passed=0
+summary=""
+
+rows=$(if tty -s ; then stty size ; else echo x 80 ; fi | sed -e 's at .* @@' -e 's@^0$@80@')
+ww=$((rows - 7))
+
+tf=$(mktemp)
+sf=$(mktemp)
+
+set -o pipefail
+
+for f; do
+    [ -x $f ] || fail "test \"$f\" is not executable"
+    tests_total=$(($tests_total + 1))
+    ctdb_test_run "$f" | tee "$tf" | show_progress
+    status=$?
+    if $with_summary ; then
+	if [ $status -eq 0 ] ; then
+	    tests_passed=$(($tests_passed + 1))
+	    t=" PASSED "
+	else
+	    t="*FAILED*"
+	fi
+	if $with_desc ; then
+	    desc=$(tail -n +4 $tf | head -n 1)
+	    f="$desc"
+	fi
+	echo "$t $f" >>"$sf"
+    fi
+done
+
+rm -f "$tf"
+
+if $with_summary ; then
+    echo
+    cat "$sf"
+    echo
+    echo "${tests_passed}/${tests_total} tests passed"
+fi
+
+rm -f "$sf"
+
+test_exit


Property changes on: branches/ctdb/squeeze-backports/tests/scripts/run_tests
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/scripts/test_wrap
===================================================================
--- branches/ctdb/squeeze-backports/tests/scripts/test_wrap	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/scripts/test_wrap	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# Execute the given command.  The intention is that it is a function
+# from ctdb_test_functions.bash.
+
+PATH="$(dirname $0):${PATH}"
+
+f="ctdb_bench"
+if [ ! $(which $f >/dev/null 2>&1) ] ; then
+    d=$(dirname $(dirname $0))/bin
+    [ -x "$d/$f" ] && PATH="$d:$PATH"
+fi
+
+. ctdb_test_functions.bash
+
+"$@"


Property changes on: branches/ctdb/squeeze-backports/tests/scripts/test_wrap
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/00_ctdb_init.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/00_ctdb_init.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/00_ctdb_init.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Restart the ctdbd daemons of a CTDB cluster.
+
+No error if ctdbd is not already running on the cluster.
+
+Prerequisites:
+
+* Nodes must be accessible via 'onnode'.
+
+Steps:
+
+1. Restart the ctdb daemons on all nodes using a method according to
+   the test environment and platform.
+
+Expected results:
+
+* The cluster is healthy within a reasonable timeframe.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+setup_ctdb
+restart_ctdb


Property changes on: branches/ctdb/squeeze-backports/tests/simple/00_ctdb_init.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/00_ctdb_onnode.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/00_ctdb_onnode.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/00_ctdb_onnode.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Use 'onnode' to confirm connectivity between all cluster nodes.
+
+Steps:
+
+1. Do a recursive "onnode all" to make sure all the nodes can connect
+   to each other.  On a cluster this ensures that SSH keys are known
+   between all hosts, which will stop output being corrupted with
+   messages about nodes being added to the list of known hosts.
+
+Expected results:
+
+* 'onnode' works between all nodes.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+
+# 
+
+echo "Checking connectivity between nodes..."
+onnode all onnode all true
+
+# We're seeing some weirdness with CTDB controls timing out.  We're
+# wondering if time is jumping forward, so this creates a time log on
+# each node that we can examine later if tests fail weirdly.
+if [ -n "$CTDB_TEST_REAL_CLUSTER" ] ; then
+    echo "Starting time logging on each node..."
+    f="/var/log/ctdb.test.time.log"
+    onnode -p all "[ -f $f ] || while : ; do date '+%s %N' ; sleep 1 ; done >$f 2>&1 </dev/null &"  &
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/00_ctdb_onnode.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/01_ctdb_version.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/01_ctdb_version.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/01_ctdb_version.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify the output of the 'ctdb version' command.
+
+This test assumes an RPM-based installation and needs to be skipped on
+non-RPM systems.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run the 'ctdb version' command on one of the cluster nodes.
+3. Compare the version displayed with that listed by the rpm command
+   for the ctdb package.
+
+Expected results:
+
+* The 'ctdb version' command displays the ctdb version number.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+if ! try_command_on_node -v 0 "rpm -q ctdb" ; then
+    echo "No useful output from rpm, SKIPPING rest of test".
+    exit 0
+fi
+rpm_ver="${out#ctdb-}"
+# Some version of RPM append the architecture to the version.
+arch=$(uname -m)
+rpm_ver="${rpm_ver%.${arch}}"
+
+try_command_on_node -v 0 "$CTDB version"
+ctdb_ver="${out#CTDB version: }"
+
+if [ "$ctdb_ver" = "$rpm_ver" ] ; then
+    echo "OK: CTDB version = RPM version"
+else
+    echo "BAD: CTDB version != RPM version"
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/01_ctdb_version.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/02_ctdb_listvars.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/02_ctdb_listvars.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/02_ctdb_listvars.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb listvars' shows a list of all tunable variables.
+
+This test simply checks that at least 5 sane looking lines are
+printed.  It does not check that the list is complete or that the
+values are sane.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb listvars' and verify that it shows a list of tunable
+   variables and their current values.
+
+Expected results:
+
+* 'ctdb listvars' works as expected.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node -v 0 "$CTDB listvars"
+
+sanity_check_output \
+    5 \
+    '^[[:alpha:]][[:alnum:]]+[[:space:]]*=[[:space:]]*[[:digit:]]+$' \
+    "$out"


Property changes on: branches/ctdb/squeeze-backports/tests/simple/02_ctdb_listvars.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/03_ctdb_getvar.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/03_ctdb_getvar.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/03_ctdb_getvar.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb getvar' works correctly.
+
+Expands on the steps below as it actually checks the values of all
+variables listed by 'ctdb listvars'.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb getvars <varname>' with a valid variable name (possibly
+   obtained via 'ctdb listvars'.
+3. Verify that the command displays the correct value of the variable
+   (corroborate with the value shown by 'ctdb listvars'.
+
+Expected results:
+
+* 'ctdb getvar' shows the correct value of the variable.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node -v 0 "$CTDB listvars"
+
+echo "Veryifying all variable values using \"ctdb getvar\"..."
+
+echo "$out" |
+while read var x val ; do
+    try_command_on_node 0 "$CTDB getvar $var"
+
+    val2="${out#*= }"
+
+    if [ "$val" != "$val2" ] ; then
+	echo "MISMATCH on $var: $val != $val2"
+	exit 1
+    fi
+done


Property changes on: branches/ctdb/squeeze-backports/tests/simple/03_ctdb_getvar.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/04_ctdb_setvar.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/04_ctdb_setvar.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/04_ctdb_setvar.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb setvar' works correctly.
+
+Doesn't strictly follow the procedure outlines below, since it doesn't
+pick a variable from the output of 'ctdb listvars'.  However, it
+verifies the value with 'ctdb getvar' in addition to 'ctdb listvars'.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Get a list of all the ctdb tunable variables, using the 'ctdb
+   listvars' command.
+3. Set the value of one of the variables using the 'setvar' control on
+   one of the nodes.  E.g. 'ctdb setvar DeterministicIPs 0'.
+4. Verify that the 'listvars' control now shows the new value for the
+   variable.
+
+Expected results:
+
+* After setting a value using 'ctdb setvar', 'ctdb listvars' shows the
+  modified value of the variable.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+var="RecoverTimeout"
+
+try_command_on_node -v 0 $CTDB getvar $var
+
+val="${out#*= }"
+
+echo "Going to try incrementing it..."
+
+incr=$(($val + 1))
+
+try_command_on_node 0 $CTDB setvar $var $incr
+
+echo "That seemed to work, let's check the value..."
+
+try_command_on_node -v 0 $CTDB getvar $var
+
+newval="${out#*= }"
+
+if [ "$incr" != "$newval" ] ; then
+    echo "Nope, that didn't work..."
+    exit 1
+fi
+
+echo "Look's good!  Now verifying with \"ctdb listvars\""
+try_command_on_node -v 0 "$CTDB listvars | grep '^$var'"
+
+check="${out#*= }"
+
+if [ "$incr" != "$check" ] ; then
+    echo "Nope, that didn't work..."
+    exit 1
+fi
+
+echo "Look's good!  Putting the old value back..."
+cmd="$CTDB setvar $var $val"
+try_command_on_node 0 $cmd


Property changes on: branches/ctdb/squeeze-backports/tests/simple/04_ctdb_setvar.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/05_ctdb_listnodes.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/05_ctdb_listnodes.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/05_ctdb_listnodes.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb listnodes' shows the list of nodes in a ctdb cluster.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb listnodes' on all the nodes of the cluster.
+3. Verify that one all the nodes the command displays a list of
+   current cluster nodes.
+
+Expected results:
+
+* 'ctdb listnodes' displays the correct information.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node -v 0 "$CTDB listnodes"
+
+num_nodes=$(echo "$out" | wc -l)
+
+# Each line should look like an IP address.
+sanity_check_output \
+    2 \
+    '^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$' \
+    "$out"
+
+out_0="$out"
+
+echo "Checking other nodes..."
+
+n=1
+while [ $n -lt $num_nodes ] ; do
+    echo -n "Node ${n}: "
+    try_command_on_node $n "$CTDB listnodes"
+    if [ "$out_0" = "$out" ] ; then
+	echo "OK"
+    else
+	echo "DIFFERs from node 0:"
+	echo "$out"
+	testfailures=1
+    fi
+    n=$(($n + 1))
+done


Property changes on: branches/ctdb/squeeze-backports/tests/simple/05_ctdb_listnodes.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/06_ctdb_getpid.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/06_ctdb_getpid.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/06_ctdb_getpid.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb getpid' works as expected.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb getpid -n <number>' on the nodes to check the PID of the
+   ctdbd process.
+3. Verify that the output is valid.
+4. Verify that with the '-n all' option the command shows the PIDs on
+   all the nodes
+
+Expected results:
+
+* 'ctdb getpid' shows valid output.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# This is an attempt at being independent of the number of nodes
+# reported by "ctdb getpid -n all".
+try_command_on_node 0 "$CTDB listnodes | wc -l"
+num_nodes="$out"
+echo "There are $num_nodes nodes..."
+
+# Call getpid a few different ways and make sure the answer is always the same.
+
+try_command_on_node -v 0 "onnode -q all $CTDB getpid"
+pids_onnode="$out"
+
+try_command_on_node -v 0 "$CTDB getpid -n all"
+pids_getpid_all="$out"
+
+cmd=""
+n=0
+while [ $n -lt $num_nodes ] ; do
+    cmd="${cmd}${cmd:+; }$CTDB getpid -n $n"
+    n=$(($n + 1))
+done
+try_command_on_node -v 0 "( $cmd )"
+pids_getpid_n="$out"
+
+if [ "$pids_onnode" = "$pids_getpid_all" -a \
+    "$pids_getpid_all" = "$pids_getpid_n" ] ; then
+    echo "They're the same... cool!"
+else
+    echo "Error: they differ."
+    testfailures=1
+fi
+
+echo "Checking each PID for validity"
+
+n=0
+while [ $n -lt $num_nodes ] ; do
+    read line
+    pid=${line#Pid:}
+    try_command_on_node $n "ls -l /proc/${pid}/exe | sed -e 's at .*/@@'"
+    echo -n "Node ${n}, PID ${pid} looks to be running \"$out\" - "
+    if [ "$out" = "ctdbd" ] ; then
+	echo "GOOD!"
+    elif [ -n "$VALGRIND" -a "$out" = "memcheck" ] ; then
+	# We could check cmdline too if this isn't good enough.
+	echo "GOOD enough!"
+    else
+	echo "BAD!"
+	testfailures=1
+    fi
+    n=$(($n + 1))
+done <<<"$pids_onnode"


Property changes on: branches/ctdb/squeeze-backports/tests/simple/06_ctdb_getpid.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/07_ctdb_process_exists.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/07_ctdb_process_exists.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/07_ctdb_process_exists.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb process-exists' shows correct information.
+
+The implementation is creative about how it gets PIDs for existing and
+non-existing processes.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. On one of the cluster nodes, get the PID of an existing process
+   (using ps wax).
+3. Run 'ctdb process-exists <pid>' on the node and verify that the
+   correct output is shown.
+4. Run 'ctdb process-exists <pid>' with a pid of a non-existent
+   process and verify that the correct output is shown.
+
+Expected results:
+
+* 'ctdb process-exists' shows the correct output.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+test_node=1
+
+# Create a background process on $test_node that will last for 60 seconds.
+# It should still be there when we check.
+try_command_on_node $test_node 'sleep 60 >/dev/null 2>&1 & echo $!'
+pid="$out"
+
+echo "Checking for PID $pid on node $test_node"
+# set -e is good, but avoid it here
+status=0
+onnode 0 "$CTDB process-exists ${test_node}:${pid}" || status=$?
+echo "$out"
+
+if [ $status -eq 0 ] ; then
+    echo "OK"
+else
+    echo "BAD"
+    testfailures=1
+fi
+
+# Now just echo the PID of the shell from the onnode process on node
+# 2.  This PID will disappear and PIDs shouldn't roll around fast
+# enough to trick the test...  but there is a chance that will happen!
+try_command_on_node $test_node 'echo $$'
+pid="$out"
+
+echo "Checking for PID $pid on node $test_node"
+try_command_on_node -v 0 "! $CTDB process-exists ${test_node}:${pid}"


Property changes on: branches/ctdb/squeeze-backports/tests/simple/07_ctdb_process_exists.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/08_ctdb_isnotrecmaster.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/08_ctdb_isnotrecmaster.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/08_ctdb_isnotrecmaster.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify the operation of 'ctdb isnotrecmaster'.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb isnotrecmaster' on each node.
+
+3. Verify that only 1 node shows the output 'This node is the
+   recmaster' and all the other nodes show the output 'This node is
+   not the recmaster'.
+
+Expected results:
+
+* 'ctdb isnotrecmaster' shows the correct output.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+cmd="$CTDB isnotrecmaster || true"
+try_command_on_node all "$cmd"
+echo "Output of \"$cmd\":"
+echo "$out"
+
+num_all_lines=$(echo "$out" |  wc -l)
+num_rm_lines=$(echo "$out" | fgrep -c 'this node is the recmaster') || true
+num_not_rm_lines=$(echo "$out" | fgrep -c 'this node is not the recmaster') || true
+
+if [ $num_rm_lines -eq 1 ] ; then
+    echo "OK, there is only 1 recmaster"
+else
+    echo "BAD, there are ${num_rm_lines} nodes claiming to be the recmaster"
+    testfailures=1
+fi
+
+if [ $(($num_all_lines - $num_not_rm_lines)) -eq 1 ] ; then
+    echo "OK, all the other nodes claim not to be the recmaster"
+else
+    echo "BAD, there are only ${num_not_rm_lines} nodes claiming not to be the recmaster"
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/08_ctdb_isnotrecmaster.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/09_ctdb_ping.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/09_ctdb_ping.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/09_ctdb_ping.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify the operation of the 'ctdb ping' command.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run the 'ctdb ping' command on one of the nodes and verify that it
+   shows valid and expected output. 
+3. Shutdown one of the cluster nodes, using the 'ctdb shutdown'
+   command. 
+4. Run the 'ctdb ping -n <node>' command from another node to this
+   node. 
+5. Verify that the command is not successful since th ctdb daemon is
+   not running on the node.
+
+Expected results:
+
+* The 'ctdb ping' command shows valid and expected output.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+try_command_on_node -v 0 "$CTDB ping -n 1"
+
+sanity_check_output \
+    1 \
+    '^response from 1 time=-?[.0-9]+ sec[[:space:]]+\([[:digit:]]+ clients\)$' \
+    "$out"
+
+try_command_on_node -v 0 "$CTDB shutdown -n 1"
+
+wait_until_node_has_status 1 disconnected 30 0
+
+try_command_on_node -v 0 "! $CTDB ping -n 1"
+
+sanity_check_output \
+    1 \
+    "(: ctdb_control error: ('ctdb_control to disconnected node'|'node is disconnected')|Unable to get ping response from node 1|Node 1 is DISCONNECTED|ctdb_control for getpnn failed|: Can not access node. Node is not operational\.)" \
+    "$out"


Property changes on: branches/ctdb/squeeze-backports/tests/simple/09_ctdb_ping.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/11_ctdb_ip.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/11_ctdb_ip.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/11_ctdb_ip.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb ip' shows the correct output.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb ip' on one of the nodes and verify the list of IP
+   addresses displayed (cross check the result with the output of
+   'ip addr show' on the node).
+3. Verify that colon-separated output is generated with the -Y option.
+
+Expected results:
+
+* 'ctdb ip' shows the list of public IPs being served by a node.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+echo "Getting list of public IPs..."
+try_command_on_node -v 1 "$CTDB ip -n all | tail -n +2"
+ips=$(echo "$out" | sed \
+	-e 's@ node\[@ @' \
+	-e 's@\].*$@@')
+machineout=$(echo "$out" | sed -r \
+	-e 's@^| |$@:@g' \
+	-e 's@[[:alpha:]]+\[@@g' \
+	-e 's@\]@@g')
+
+while read ip pnn ; do
+    try_command_on_node $pnn "ip addr show"
+    if [ "${out/inet ${ip}\/}" != "$out" ] ; then
+	echo "GOOD: node $pnn appears to have $ip assigned"
+    else
+	echo "BAD:  node $pnn does not appear to have $ip assigned"
+	testfailures=1
+    fi
+done <<<"$ips" # bashism to avoid problem setting variable in pipeline.
+
+[ "$testfailures" != 1 ] && echo "Looks good!"
+
+cmd="$CTDB -Y ip -n all | tail -n +2"
+echo "Checking that \"$cmd\" produces expected output..."
+
+try_command_on_node 1 "$cmd"
+if [ "$out" = "$machineout" ] ; then
+    echo "Yep, looks good!"
+else
+    echo "Nope, it looks like this:"
+    echo "$out"
+    echo "Should be like this:"
+    echo "$machineout"
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/11_ctdb_ip.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/12_ctdb_getdebug.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/12_ctdb_getdebug.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/12_ctdb_getdebug.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,82 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb getdebug' works as expected.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Get the current debug level on a node, using 'ctdb getdebug -n <node>'.
+3. Verify that colon-separated output is generated with the -Y option.
+4. Verify that the '-n all' option shows the debug level on all nodes.
+
+Expected results:
+
+* 'ctdb getdebug' shows the debug level on all the nodes.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node 0 "$CTDB listnodes | wc -l"
+num_nodes="$out"
+
+try_command_on_node -v 1 "onnode -q all $CTDB getdebug"
+getdebug_onnode="$out"
+
+sanity_check_output \
+    $num_nodes \
+    '^Node [[:digit:]]+ is at debug level [[:alpha:]]+ \([[:digit:]]+\)$' \
+    "$out"
+
+try_command_on_node -v 1 "$CTDB getdebug -n all"
+getdebug_all="$out"
+
+cmd=""
+n=0
+while [ $n -lt $num_nodes ] ; do
+    cmd="${cmd}${cmd:+; }$CTDB getdebug -n $n"
+    n=$(($n + 1))
+done
+try_command_on_node -v 1 "$cmd"
+getdebug_n="$out"
+
+if [ "$getdebug_onnode" = "$getdebug_all" -a \
+    "$getdebug_all" = "$getdebug_n" ] ; then
+    echo "They're the same... cool!"
+else
+    echo "Error: they differ."
+    testfailures=1
+fi
+
+colons=""
+nl="
+"
+while read line ; do
+    t=$(echo "$line" | sed -r -e 's at Node [[:digit:]]+ is at debug level ([[:alpha:]]+) \((-?[[:digit:]]+)\)$@:\1:\2:@')
+    colons="${colons}${colons:+${nl}}:Name:Level:${nl}${t}"
+done <<<"$getdebug_onnode"
+
+cmd="$CTDB -Y getdebug -n all"
+echo "Checking that \"$cmd\" produces expected output..."
+
+try_command_on_node 1 "$cmd"
+if [ "$out" = "$colons" ] ; then
+    echo "Yep, looks good!"
+else
+    echo "Nope, it looks like this:"
+    echo "$out"
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/12_ctdb_getdebug.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/13_ctdb_setdebug.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/13_ctdb_setdebug.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/13_ctdb_setdebug.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,83 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb setdebug' works as expected.
+
+This is a little superficial.  It checks that CTDB thinks the debug
+level has been changed but doesn't actually check that logging occurs
+at the new level.
+
+A test should also be added to see if setting the debug value via a
+numerical value works too.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Get the current debug level on a node, using 'ctdb getdebug'.
+3. Change the debug level to some other value (e.g. EMERG) using
+   'ctdb setdebug'.
+4. Verify that the new debug level is correctly set using 'ctdb getdebug'.
+
+Expected results:
+
+* 'ctdb setdebug' correctly sets the debug level on a node.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+get_debug ()
+{
+    # Sets; check_debug
+    local node="$1"
+
+    local out
+    
+    try_command_on_node -v $node "$CTDB getdebug"
+    check_debug=$(echo "$out" |
+	sed -r -e 's at Node [[:digit:]]+ is at debug level ([[:alpha:]]+) \(-?[[:digit:]]+\)$@\1@')
+}
+
+set_and_check_debug ()
+{
+    local node="$1"
+    local level="$2"
+
+    echo "Setting debug level on node ${node} to ${level}."
+    try_command_on_node $node "$CTDB setdebug ${level}"
+
+    local check_debug
+    get_debug $node
+
+    if [ "$level" = "$check_debug" ] ; then
+	echo "That seemed to work... cool!"
+    else
+	echo "BAD: Debug level should have changed to \"$level\" but it is \"$check_debug\"."
+	testfailures=1
+    fi
+}
+
+get_debug 1
+initial_debug="$check_debug"
+
+new_debug="EMERG"
+[ "$initial_debug" = "$new_debug" ] && new_debug="ALERT"
+
+set_and_check_debug 1 "$new_debug"
+
+if [ "$testfailures" != 1 ] ; then
+    echo "Returning the debug level to its initial value..."
+    set_and_check_debug 1 "$initial_debug"
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/13_ctdb_setdebug.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/14_ctdb_statistics.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/14_ctdb_statistics.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/14_ctdb_statistics.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb statistics' works as expected.
+
+This is pretty superficial and could do more validation.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb statistics' on a node, and verify that the output is
+   valid.
+3. Repeat the command with the '-n all' option and verify that the
+   output is valid.
+
+Expected results:
+
+* 'ctdb statistics' shows valid output on all the nodes.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+pattern='^(CTDB version 1|Current time of statistics[[:space:]]*:.*|Statistics collected since[[:space:]]*:.*|Gathered statistics for [[:digit:]]+ nodes|[[:space:]]+[[:alpha:]_]+[[:space:]]+[[:digit:]]+|[[:space:]]+(node|client|timeouts)|[[:space:]]+([[:alpha:]_]+_latency|max_reclock_[[:alpha:]]+)[[:space:]]+[[:digit:]-]+\.[[:digit:]]+[[:space:]]sec|[[:space:]]*(reclock_ctdbd|reclock_recd|call_latency|lockwait_latency|childwrite_latency)[[:space:]]+MIN/AVG/MAX[[:space:]]+[-.[:digit:]]+/[-.[:digit:]]+/[-.[:digit:]]+ sec out of [[:digit:]]+)$'
+
+try_command_on_node -v 1 "$CTDB statistics"
+
+sanity_check_output 40 "$pattern" "$out"
+
+try_command_on_node -v 1 "$CTDB statistics -n all"
+
+sanity_check_output 40 "$pattern" "$out"


Property changes on: branches/ctdb/squeeze-backports/tests/simple/14_ctdb_statistics.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/15_ctdb_statisticsreset.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/15_ctdb_statisticsreset.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/15_ctdb_statisticsreset.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,83 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb statisticsreset' works as expected.
+
+This is pretty superficial.  It just checks that a few particular
+items reduce.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb statisticsreset' on all nodes and verify that it executes
+   successfully.
+
+Expected results:
+
+* 'ctdb statisticsreset' executes successfully.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node 0 "$CTDB listnodes | wc -l"
+num_nodes="$out"
+
+get_stat ()
+{
+    local label="$1"
+    local out="$2"
+
+    echo "$out" | sed -rn -e "s@^[[:space:]]+${label}[[:space:]]+([[:digit:]])@\1 at p" | head -1
+}
+
+check_reduced ()
+{
+    local label="$1"
+    local before="$2"
+    local after="$3"
+
+    if [ $after -lt $before ] ; then
+	echo "GOOD: ${label} reduced from ${before} to ${after}"
+    else
+	echo "BAD: ${label} did not reduce from ${before} to ${after}"
+	testfailures=1
+    fi
+}
+
+n=0
+while [ $n -lt $num_nodes ] ; do
+    echo "Getting initial statistics for node ${n}..."
+    
+    try_command_on_node -v $n $CTDB statistics
+
+    before_req_control=$(get_stat "req_control" "$out")
+    before_reply_control=$(get_stat "reply_control" "$out")
+    before_node_packets_recv=$(get_stat "node_packets_recv" "$out")
+
+    try_command_on_node $n $CTDB statisticsreset
+
+    try_command_on_node -v $n $CTDB statistics
+
+    after_req_control=$(get_stat "req_control" "$out")
+    after_reply_control=$(get_stat "reply_control" "$out")
+    after_node_packets_recv=$(get_stat "node_packets_recv" "$out")
+
+    check_reduced "req_control" "$before_req_control" "$after_req_control"
+    check_reduced "reply_control" "$before_reply_control" "$after_reply_control"
+    check_reduced "node_packets_recv" "$before_node_packets_recv" "$after_node_packets_recv"
+
+    n=$(($n + 1))
+done


Property changes on: branches/ctdb/squeeze-backports/tests/simple/15_ctdb_statisticsreset.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/16_ctdb_config_add_ip.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/16_ctdb_config_add_ip.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/16_ctdb_config_add_ip.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,120 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that an IP address can be added to a node using 'ctdb addip'.
+
+This test goes to some trouble to figure out which IP address to add
+but assumes a 24-bit subnet mask.  It does not handle IPv6.  It does
+not do any network level checks that the new IP address is reachable
+but simply trusts 'ctdb ip' that the address has been added.  There is
+also an extra prerequisite that the node being added to already has
+public addresses - this is difficult to avoid if the extra address is
+to be sensibly chosen.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Use 'ctdb ip' on one of the nodes to list the IP addresses being
+   served.
+3. Add an additional public address to be served by the node, using
+   'ctdb addip'.
+4. Verify that this IP address has been added to the list of IP
+   addresses being served by the node, using the 'ctdb ip' command.
+
+Expected results:
+
+* 'ctdb ip' adds an IP address to the list of public IP addresses
+  being served by a node.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+echo "Getting list of public IPs..."
+all_ips_on_node 0
+
+# When selecting test_node we just want a node that has public IPs.
+# This will work and is economically semi-randomly.  :-)
+read x test_node <<<"$out"
+
+test_node_ips=""
+all_ips=""
+while read ip pnn ; do
+    all_ips="${all_ips}${all_ips:+ }${ip}"
+    [ "$pnn" = "$test_node" ] && \
+	test_node_ips="${test_node_ips}${test_node_ips:+ }${ip}"
+done <<<"$out"
+
+echo "Selected node ${test_node} with IPs: $test_node_ips"
+
+# Try to find a free IP adddress.  This is inefficient but should
+# succeed quickly.
+try_command_on_node $test_node "ip addr show"
+all_test_node_ips=$(echo "$out" | sed -rn -e 's@^[[:space:]]+inet[[:space:]]+([[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+/[[:digit:]]+).*[[:space:]]([^[:space:]]+)+$@\1:\2 at p')
+
+add_ip=""
+
+# Use an IP already on one of the nodes, remove the last octet and
+# loop through the possible IP addreses.
+for i in $test_node_ips ; do
+    prefix="${i%.*}"
+    for j in $(seq 101 199) ; do
+	try="${prefix}.${j}"
+	# Try to make sure it isn't used anywhere!
+
+	# First, make sure it isn't an existing public address on the
+	# cluster.
+	for k in $all_ips ; do
+	    [ "$try" = "$k" ] && continue 2
+	done
+
+	# Also make sure it isn't some other address in use on the
+	# node.
+	for k in $all_test_node_ips ; do
+	    [ "$try" = "${k%/*}" ] && continue 2
+	done
+
+	# Get the interface details for $i, which our address is a
+	# close relative of.  This should never fail but it can't hurt
+	# to be careful...
+	for k in $all_test_node_ips ; do
+	    if [ "$i" = "${k%/*}" ] ; then
+			# Found one!
+		add_ip="${try}/${k#*/}"
+		break 3
+	    fi
+	done
+    done
+done
+
+if [ -z "$add_ip" ] ; then
+    echo "BAD: Unable to find IP address to add."
+    exit 1
+fi
+
+echo "Adding IP: ${add_ip/:/ on interface }"
+try_command_on_node $test_node $CTDB addip ${add_ip/:/ }
+
+echo "Waiting for IP to be added..."
+if wait_until 60 ips_are_on_nodeglob $test_node ${add_ip%/*} ; then
+    echo "That worked!"
+else
+    echo "BAD: IP didn't get added."
+    try_command_on_node $test_node $CTDB ip -n all
+    exit 1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/16_ctdb_config_add_ip.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/17_ctdb_config_delete_ip.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/17_ctdb_config_delete_ip.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/17_ctdb_config_delete_ip.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that a node's public IP address can be deleted using 'ctdb deleteip'.
+
+This test does not do any network level checks that the IP address is
+no longer reachable but simply trusts 'ctdb ip' that the address has
+been deleted.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Use 'ctdb ip' on one of the nodes to list the IP addresses being
+   served.
+3. Delete one public IP address being be served by the node, using
+   'ctdb delip'.
+4. Verify that the delete IP address is no longer listed using the
+   all_ips_on_node helper function.
+
+Expected results:
+
+* 'ctdb delip' removes an IP address from the list of public IP
+  addresses being served by a node.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+echo "Getting list of public IPs..."
+all_ips_on_node -v 0
+
+# Select an IP/node to remove.
+num_ips=$(echo "$out" | wc -l)
+num_to_remove=$(($RANDOM % $num_ips))
+
+# Find the details in the list.
+i=0
+while [ $i -le $num_to_remove ] ; do
+    read ip_to_remove test_node
+    i=$(($i + 1))
+done <<<"$out"
+
+echo "Attempting to remove ${ip_to_remove} from node ${test_node}."
+try_command_on_node $test_node $CTDB delip $ip_to_remove
+
+echo "Sleeping..."
+sleep_for 1
+
+test_node_ips=""
+while read ip pnn ; do
+    [ "$pnn" = "$test_node" ] && \
+	test_node_ips="${test_node_ips}${test_node_ips:+ }${ip}"
+done <<<"$out" # bashism to avoid problem setting variable in pipeline.
+
+if [ "${test_node_ips/${ip_to_remove}}" = "$test_node_ips" ] ; then
+    echo "GOOD: That worked!"
+else
+    echo "BAD: The remove IP address is still there!"
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/17_ctdb_config_delete_ip.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/23_ctdb_moveip.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/23_ctdb_moveip.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/23_ctdb_moveip.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,101 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that  'ctdb moveip' allows movement of public IPs between cluster nodes.
+
+To work, this test unsets DeterministicIPs and sets NoIPFailback.
+
+This test does not do any network level checks that the IP address is
+no longer reachable but simply trusts 'ctdb ip' that the address has
+been deleted.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Use 'ctdb ip' on one of the nodes to list the IP addresses being
+   served.
+3. Use 'ctdb moveip' to move an address from one node to another.
+4. Verify that the IP is no longer being hosted by the first node and is now being hosted by the second node.
+
+Expected results:
+
+* 'ctdb moveip' allows an IP address to be moved between cluster nodes.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+try_command_on_node 0 "$CTDB listnodes | wc -l"
+num_nodes="$out"
+echo "There are $num_nodes nodes..."
+
+if [ $num_nodes -lt 2 ] ; then
+    echo "Less than 2 nodes!"
+    exit 1
+fi
+
+echo "Getting list of public IPs..."
+all_ips_on_node -v 0
+
+sanity_check_ips "$out"
+
+# Select an IP/node to move.
+num_ips=$(echo "$out" | wc -l)
+num_to_move=$(($RANDOM % $num_ips))
+
+# Find the details in the list.
+i=0
+while [ $i -le $num_to_move ] ; do
+    read ip_to_move test_node
+    i=$(($i + 1))
+done <<<"$out"
+
+# Can only move address to a node that is willing to host $ip_to_move.
+# This inefficient but shouldn't take long or get stuck.
+to_node=$test_node
+while [ $test_node -eq $to_node ] ; do
+    n=$(($RANDOM % $num_ips))
+    i=0
+    while [ $i -le $n ] ; do
+	read x to_node
+	i=$(($i + 1))
+    done <<<"$out"
+done
+
+echo "Turning off DeterministicIPs..."
+try_command_on_node 0 $CTDB setvar DeterministicIPs 0 -n all
+
+echo "Turning on NoIPFailback..."
+try_command_on_node 0 $CTDB setvar NoIPFailback 1 -n all
+
+echo "Attempting to move ${ip_to_move} from node ${test_node} to node ${to_node}."
+try_command_on_node $test_node $CTDB moveip $ip_to_move $to_node
+
+if wait_until_ips_are_on_nodeglob "[!${test_node}]" $ip_to_move ; then
+    echo "IP moved from ${test_node}."
+else
+    echo "BAD: IP didn't move from ${test_node}."
+    exit 1
+fi
+
+if wait_until_ips_are_on_nodeglob "$to_node" $ip_to_move ; then
+    echo "IP moved to ${to_node}."
+else
+    echo "BAD: IP didn't move to ${to_node}."
+    exit 1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/23_ctdb_moveip.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/24_ctdb_getdbmap.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/24_ctdb_getdbmap.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/24_ctdb_getdbmap.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that  'ctdb getdbmap' operates as expected.
+
+This test creates some test databases using 'ctdb attach'.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Get the database on using 'ctdb getdbmap'.
+3. Verify that the output is valid.
+
+Expected results:
+
+* 'ctdb getdbmap' shows a valid listing of databases.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+make_temp_db_filename ()
+{
+    dd if=/dev/urandom count=1 bs=512 2>/dev/null |
+    md5sum |
+    awk '{printf "%s.tdb\n", $1}'
+}
+
+try_command_on_node -v 0 "$CTDB getdbmap"
+
+db_map_pattern='^(Number of databases:[[:digit:]]+|dbid:0x[[:xdigit:]]+ name:[^[:space:]]+ path:[^[:space:]]+)$'
+
+sanity_check_output $(($num_db_init + 1)) "$dbmap_pattern" "$out"
+
+num_db_init=$(echo "$out" | sed -n -e '1s/.*://p')
+
+for i in $(seq 1 5) ; do
+    f=$(make_temp_db_filename)
+    echo "Creating test database: $f"
+    try_command_on_node 0 $CTDB attach "$f"
+    try_command_on_node 0 $CTDB getdbmap
+    sanity_check_output $(($num_db_init + 1)) "$dbmap_pattern" "$out"
+    num=$(echo "$out" | sed -n -e '1s/^.*://p')
+    if [ $num = $(($num_db_init + $i)) ] ; then
+	echo "OK: correct number of additional databases"
+    else
+	echo "BAD: no additional database"
+	exit 1
+    fi
+    if [ "${out/name:${f} /}" != "$out" ] ; then
+	echo "OK: getdbmap knows about \"$f\""
+    else
+	echo "BAD: getdbmap does not know about \"$f\""
+	exit 1
+    fi
+done


Property changes on: branches/ctdb/squeeze-backports/tests/simple/24_ctdb_getdbmap.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/25_dumpmemory.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/25_dumpmemory.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/25_dumpmemory.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb dumpmemory' shows expected output.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run 'ctdb dumpmemory' and verify that it shows expected output
+3. Verify that the command takes the '-n all' option and that it
+   causes output for all nodes to be displayed.
+
+Expected results:
+
+* 'ctdb dumpmemory' sows valid output.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node -v 0 "$CTDB dumpmemory"
+
+pat='^([[:space:]].+[[:space:]]+contains[[:space:]]+[[:digit:]]+ bytes in[[:space:]]+[[:digit:]]+ blocks \(ref [[:digit:]]+\)[[:space:]]+0x[[:xdigit:]]+|[[:space:]]+reference to: .+|full talloc report on .+ \(total[[:space:]]+[[:digit:]]+ bytes in [[:digit:]]+ blocks\))$'
+
+sanity_check_output 10 "$pat" "$out"
+
+echo "Checking output using '-n all'..."
+
+try_command_on_node 0 "$CTDB listnodes"
+num_nodes=$(echo "$out" | wc -l)
+
+try_command_on_node 0 "$CTDB dumpmemory" -n all
+sanity_check_output 10 "$pat" "$out"
+
+if [ $(fgrep -c 'full talloc report on' <<<"$out") -eq  $num_nodes ] ; then
+    echo "OK: there looks to be output for all $num_nodes nodes"
+else
+    echo "BAD: there not look to be output for all $num_nodes nodes"
+    exit 1
+fi    


Property changes on: branches/ctdb/squeeze-backports/tests/simple/25_dumpmemory.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/26_ctdb_config_check_error_on_unreachable_ctdb.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/26_ctdb_config_check_error_on_unreachable_ctdb.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/26_ctdb_config_check_error_on_unreachable_ctdb.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify an error occurs if a ctdb command is run against a node without a ctdbd.
+
+That is, check that an error message is printed if an attempt is made
+to execute a ctdb command against a node that is not running ctdbd.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Shutdown ctdb on a node using 'ctdb shutdown -n <node>'.
+3. Verify that the status of the node changes to 'DISCONNECTED'.
+4. Now run 'ctdb ip -n <node>' from another node.
+5. Verify that an error message is printed stating that the node is
+   disconnected.
+6. Execute some other commands against the shutdown node.  For example,
+   disable, enable, ban, unban, listvars.
+7. For each command, verify that an error message is printed stating
+   that the node is disconnected. 
+
+Expected results:
+
+* For a node on which ctdb is not running, all commands display an
+  error message stating that the node is disconnected.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+test_node=1
+
+try_command_on_node 0 "$CTDB listnodes"
+num_nodes=$(echo "$out" | wc -l)
+echo "There are $num_nodes nodes."
+
+echo "Shutting down node ${test_node}..."
+try_command_on_node $test_node $CTDB shutdown
+
+wait_until_node_has_status $test_node disconnected 30 0
+
+pat="ctdb_control error: 'ctdb_control to disconnected node'|ctdb_control error: 'node is disconnected'|Node $test_node is DISCONNECTED"
+
+for i in ip disable enable "ban 0" unban listvars ; do
+    try_command_on_node -v 0 ! $CTDB $i -n $test_node
+
+    if egrep -q "$pat" <<<"$out" ; then
+	echo "OK: \"ctdb ${i}\" fails with \"disconnected node\""
+    else
+	echo "BAD: \"ctdb ${i}\" does not fail with \"disconnected node\""
+	exit 1
+    fi
+done


Property changes on: branches/ctdb/squeeze-backports/tests/simple/26_ctdb_config_check_error_on_unreachable_ctdb.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/31_ctdb_disable.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/31_ctdb_disable.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/31_ctdb_disable.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify the operation of 'ctdb disable'.
+
+This is a superficial test of the 'ctdb disable' command.  It trusts
+information from CTDB that indicates that the IP failover has happened
+correctly.  Another test should check that the failover has actually
+happened at the networking level.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Disable one of the nodes using 'ctdb disable -n <node>'.
+3. Verify that the status of the node changes to 'disabled'.
+4. Verify that the IP addreses served by the disabled node are failed
+   over to other nodes.
+
+Expected results:
+
+* The status of the disabled node changes as expected and IP addresses
+  failover as expected.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+select_test_node_and_ips
+
+echo "Disabling node $test_node"
+
+try_command_on_node 1 $CTDB disable -n $test_node
+
+# Avoid a potential race condition...
+wait_until_node_has_status $test_node disabled
+
+if wait_until_ips_are_on_nodeglob "[!${test_node}]" $test_node_ips ; then
+    echo "All IPs moved."
+else
+    echo "Some IPs didn't move."
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/31_ctdb_disable.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/32_ctdb_enable.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/32_ctdb_enable.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/32_ctdb_enable.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify the operation of 'ctdb enable'.
+
+This is a superficial test of the 'ctdb enable' command.  It trusts
+information from CTDB that indicates that the IP failover has happened
+correctly.  Another test should check that the failover has actually
+happened at the networking level.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Disable one of the nodes using 'ctdb disable -n <node>'.
+3. Verify that the status of the node changes to 'disabled'.
+4. Verify that the public IP addreses served by the disabled node are
+   failed over to other nodes.
+5. Enable the disabled node using 'ctdb enable -n '<node>'.
+6. Verify that the status changes back to 'OK'.
+7. Verify that some public IP addreses are failed back to the node.
+
+
+Expected results:
+
+* The status of a re-enabled node changes as expected and IP addresses
+  fail back as expected.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+########################################
+
+set -e
+
+cluster_is_healthy
+
+select_test_node_and_ips
+
+echo "Disabling node $test_node"
+try_command_on_node 1 $CTDB disable -n $test_node
+
+wait_until_node_has_status $test_node disabled
+
+if wait_until_ips_are_on_nodeglob "[!${test_node}]" $test_node_ips ; then
+    echo "All IPs moved."
+else
+    echo "Some IPs didn't move."
+    testfailures=1
+fi
+
+echo "Reenabling node $test_node"
+try_command_on_node 1 $CTDB enable -n $test_node
+
+wait_until_node_has_status $test_node enabled
+
+wait_until_node_has_some_ips "$test_node"


Property changes on: branches/ctdb/squeeze-backports/tests/simple/32_ctdb_enable.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/41_ctdb_stop.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/41_ctdb_stop.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/41_ctdb_stop.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify the operation of the 'ctdb stop' command.
+
+This is a superficial test of the 'ctdb stop' command.  It trusts
+information from CTDB that indicates that the IP failover has
+happened correctly.  Another test should check that the failover
+has actually happened at the networking level.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Stop one of the nodes using the 'ctdb stop' command.
+3. Verify that the status of the node changes to 'stopped'.
+4. Verify that the public IP addresses that were being served by
+   the node are failed over to one of the other nodes.
+
+Expected results:
+
+* The status of the stopped nodes changes as expected and IP addresses
+  failover as expected.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+select_test_node_and_ips
+
+echo "Stopping node ${test_node}..."
+try_command_on_node 1 $CTDB stop -n $test_node
+
+wait_until_node_has_status $test_node stopped
+
+if wait_until_ips_are_on_nodeglob "[!${test_node}]" $ips ; then
+    echo "All IPs moved."
+else
+    echo "Some IPs didn't move."
+    testfailures=1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/41_ctdb_stop.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/42_ctdb_continue.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/42_ctdb_continue.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/42_ctdb_continue.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify the operation of the 'ctdb continue' command.
+
+This is a superficial test of the 'ctdb continue' command.  It trusts
+information from CTDB that indicates that the IP failover and failback
+has happened correctly.  Another test should check that the failover
+and failback has actually happened at the networking level.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Stop one of the nodes using the 'ctdb stop' command.
+3. Verify that the status of the node changes to 'stopped'.
+4. Verify that the public IP addresses that were being served by
+   the node are failed over to one of the other nodes.
+5. Use 'ctdb continue' to bring the node back online.
+6. Verify that the status of the node changes back to 'OK' and that
+   some public IP addresses move back to the node.
+
+Expected results:
+
+* The 'ctdb continue' command successfully brings a stopped node online.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+select_test_node_and_ips
+
+echo "Stopping node ${test_node}..."
+try_command_on_node 1 $CTDB stop -n $test_node
+
+wait_until_node_has_status $test_node stopped
+
+if wait_until_ips_are_on_nodeglob "[!${test_node}]" $ips ; then
+    echo "All IPs moved."
+else
+    echo "Some IPs didn't move."
+    testfailures=1
+fi
+
+echo "Continuing node $test_node"
+try_command_on_node 1 $CTDB continue -n $test_node
+
+wait_until_node_has_status $test_node notstopped
+
+wait_until_node_has_some_ips "$test_node"


Property changes on: branches/ctdb/squeeze-backports/tests/simple/42_ctdb_continue.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/43_stop_recmaster_yield.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/43_stop_recmaster_yield.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/43_stop_recmaster_yield.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that 'ctdb stop' causes a node to yield the recovery master role.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Determine which node is the recmaster.
+2. Stop this node using the 'ctdb stop' command.
+3. Verify that the status of the node changes to 'stopped'.
+4. Verify that this node no longer has the recovery master role.
+
+Expected results:
+
+* The 'ctdb stop' command causes a node to yield the recmaster role.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+echo "Finding out which node is the recovery master..."
+try_command_on_node -v 0 "$CTDB recmaster"
+test_node=$out
+
+echo "Stopping node ${test_node} - it is the current recmaster..."
+try_command_on_node 1 $CTDB stop -n $test_node
+
+wait_until_node_has_status $test_node stopped
+
+echo "Checking which node is the recovery master now..."
+try_command_on_node -v 0 "$CTDB recmaster"
+recmaster=$out
+
+if [ "$recmaster" != "$test_node" ] ; then
+    echo "OK: recmaster moved to node $recmaster"
+else
+    echo "BAD: recmaster did not move"
+    exit 1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/43_stop_recmaster_yield.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/51_ctdb_bench.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/51_ctdb_bench.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/51_ctdb_bench.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Run the ctdb_bench test and sanity check the output.
+
+This doesn't test for performance regressions or similarly anything
+useful.  Only vague sanity checking of results is done.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run ctdb_bench on all nodes with default options.
+3. Ensure that the number of +ve and -ive messages are within 1% of
+   each other.
+4. Ensure that the number of messages per second is greater than 10.
+
+Expected results:
+
+* ctdb_bench runs without error and prints reasonable results.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node 0 "$CTDB listnodes"
+num_nodes=$(echo "$out" | wc -l)
+
+echo "Running ctdb_bench on all $num_nodes nodes."
+try_command_on_node -v -pq all $CTDB_TEST_WRAPPER $VALGRIND ctdb_bench -n $num_nodes
+
+# Get the last line of output.
+while read line ; do
+    prev=$line
+done <<<"$out"
+
+pat='^(Ring: [[:digit:]]+(\.[[:digit:]]+)? msgs/sec \(\+ve=[[:digit:]]+ -ve=[[:digit:]]+\)[[:space:]]?|Waiting for cluster[[:space:]]?)+$'
+sanity_check_output 1 "$pat" "$out"
+
+# $prev should look like this:
+#    Ring: 10670.93 msgs/sec (+ve=53391 -ve=53373)
+stuff="${prev##*Ring: }"
+mps="${stuff% msgs/sec*}"
+
+if [ ${mps%.*} -ge 10 ] ; then
+    echo "OK: $mps msgs/sec >= 10 msgs/sec"
+else
+    echo "BAD: $mps msgs/sec < 10 msgs/sec"
+    exit 1
+fi
+
+stuff="${stuff#*msgs/sec (+ve=}"
+positive="${stuff%% *}"
+
+if [ $positive -gt 0 ] ; then
+    echo "OK: +ive ($positive) > 0"
+else
+    echo "BAD: +ive ($positive) = 0"
+    exit 1
+fi
+
+stuff="${stuff#*-ve=}"
+negative="${stuff%)}"
+
+if [ $negative -gt 0 ] ; then
+    echo "OK: -ive ($negative) > 0"
+else
+    echo "BAD: -ive ($negative) = 0"
+    exit 1
+fi
+
+perc_diff=$(( ($positive - $negative) * 100 / $positive ))
+perc_diff=${perc_diff#-}
+
+check_percent=5
+if [ $perc_diff -le $check_percent ] ; then
+    echo "OK: percentage difference between +ive and -ive ($perc_diff%) <= $check_percent%"
+else
+    echo "BAD: percentage difference between +ive and -ive ($perc_diff%) > $check_percent%"
+    exit 1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/51_ctdb_bench.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/52_ctdb_fetch.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/52_ctdb_fetch.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/52_ctdb_fetch.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Run the ctdb_fetch test and sanity check the output.
+
+This doesn't test for performance regressions or similarly anything
+useful.  Only vague sanity checking of results is done.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run ctdb_fetch on all nodes with default options.
+3. Ensure that the number of +ve and -ive messages are within 1% of
+   each other.
+4. Ensure that the number of messages per second is greater than 10.
+
+Expected results:
+
+* ctdb_fetch runs without error and prints reasonable results.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node 0 "$CTDB listnodes"
+num_nodes=$(echo "$out" | wc -l)
+
+echo "Running ctdb_fetch on all $num_nodes nodes."
+try_command_on_node -v -pq all $CTDB_TEST_WRAPPER $VALGRIND ctdb_fetch -n $num_nodes
+
+pat='^(Fetch: [[:digit:]]+(\.[[:digit:]]+)? msgs/sec[[:space:]]?|msg_count=[[:digit:]]+ on node [[:digit:]]|Fetching final record|DATA:|Test data|Waiting for cluster[[:space:]]?|.*: Reqid wrap!|)+$'
+sanity_check_output 1 "$pat" "$out"
+
+# Filter out the performance figures:
+out_fetch=$(echo "$out" | egrep '^(Fetch: .*)+$')
+
+# Get the last line of output.
+while read line ; do
+    prev=$line
+done <<<"$out_fetch"
+
+# $prev should look like this:
+#    Fetch: 10670.93 msgs/sec
+stuff="${prev##*Fetch: }"
+mps="${stuff% msgs/sec*}"
+
+if [ ${mps%.*} -ge 10 ] ; then
+    echo "OK: $mps msgs/sec >= 10 msgs/sec"
+else
+    echo "BAD: $mps msgs/sec < 10 msgs/sec"
+    exit 1
+fi


Property changes on: branches/ctdb/squeeze-backports/tests/simple/52_ctdb_fetch.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/53_ctdb_transaction.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/53_ctdb_transaction.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/53_ctdb_transaction.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that the ctdb_transaction test succeeds.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run two copies of ctdb_transaction on each node with a 30 second
+   timeout.
+3. Ensure that all ctdb_transaction processes complete successfully.
+
+Expected results:
+
+* ctdb_transaction runs without error.
+EOF
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node 0 "$CTDB listnodes"
+num_nodes=$(echo "$out" | wc -l)
+
+if test "x${CTDB_TEST_TIMELIMIT}" == "x" ; then
+	CTDB_TEST_TIMELIMIT=30
+fi
+
+t="$CTDB_TEST_WRAPPER $VALGRIND ctdb_transaction --timelimit=${CTDB_TEST_TIMELIMIT}"
+
+echo "Running ctdb_transaction on all $num_nodes nodes."
+try_command_on_node -v -pq all "$t & $t"


Property changes on: branches/ctdb/squeeze-backports/tests/simple/53_ctdb_transaction.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/simple/54_ctdb_transaction_recovery.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/simple/54_ctdb_transaction_recovery.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/simple/54_ctdb_transaction_recovery.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that the ctdb_transaction test succeeds.
+
+Prerequisites:
+
+* An active CTDB cluster with at least 2 active nodes.
+
+Steps:
+
+1. Verify that the status on all of the ctdb nodes is 'OK'.
+2. Run two copies of ctdb_transaction on each node with a 30 second
+   timeout.
+3. Ensure that all ctdb_transaction processes complete successfully.
+
+Expected results:
+
+* ctdb_transaction runs without error.
+EOF
+}
+
+recovery_loop()
+{
+	local COUNT=1
+
+	while true ; do
+		echo Recovery $COUNT
+		ctdb recover
+		sleep 2
+		COUNT=$((COUNT + 1))
+	done
+}
+
+recovery_loop_start()
+{
+	recovery_loop > /tmp/recloop.out &
+	RECLOOP_PID=$!
+	ctdb_test_exit_hook_add "kill $RECLOOP_PID >/dev/null 2>&1"
+}
+
+. ctdb_test_functions.bash
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+try_command_on_node 0 "$CTDB listnodes"
+num_nodes=$(echo "$out" | wc -l)
+
+if test "x${CTDB_TEST_TIMELIMIT}" == "x" ; then
+	CTDB_TEST_TIMELIMIT=30
+fi
+
+t="$CTDB_TEST_WRAPPER $VALGRIND ctdb_transaction --timelimit=${CTDB_TEST_TIMELIMIT}"
+
+echo "Starting recovery loop"
+recovery_loop_start
+
+echo "Running ctdb_transaction on all $num_nodes nodes."
+try_command_on_node -v -pq all "$t & $t"
+


Property changes on: branches/ctdb/squeeze-backports/tests/simple/54_ctdb_transaction_recovery.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_bench.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_bench.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_bench.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,254 @@
+/* 
+   simple ctdb benchmark
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+#include "ctdb_client.h"
+#include "ctdb_private.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+
+static int timelimit = 10;
+static int num_records = 10;
+static int num_nodes;
+
+enum my_functions {FUNC_INCR=1, FUNC_FETCH=2};
+
+/*
+  ctdb call function to increment an integer
+*/
+static int incr_func(struct ctdb_call_info *call)
+{
+	if (call->record_data.dsize == 0) {
+		call->new_data = talloc(call, TDB_DATA);
+		if (call->new_data == NULL) {
+			return CTDB_ERR_NOMEM;
+		}
+		call->new_data->dptr = talloc_size(call, 4);
+		call->new_data->dsize = 4;
+		*(uint32_t *)call->new_data->dptr = 0;
+	} else {
+		call->new_data = &call->record_data;
+	}
+	(*(uint32_t *)call->new_data->dptr)++;
+	return 0;
+}
+
+/*
+  ctdb call function to fetch a record
+*/
+static int fetch_func(struct ctdb_call_info *call)
+{
+	call->reply_data = &call->record_data;
+	return 0;
+}
+
+
+static int msg_count;
+static int msg_plus, msg_minus;
+
+/*
+  handler for messages in bench_ring()
+*/
+static void ring_message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+				 TDB_DATA data, void *private_data)
+{
+	int incr = *(int *)data.dptr;
+	int *count = (int *)private_data;
+	int dest;
+
+	(*count)++;
+	dest = (ctdb_get_pnn(ctdb) + num_nodes + incr) % num_nodes;
+	ctdb_client_send_message(ctdb, dest, srvid, data);
+	if (incr == 1) {
+		msg_plus++;
+	} else {
+		msg_minus++;
+	}
+}
+
+
+static void send_start_messages(struct ctdb_context *ctdb, int incr)
+{
+	/* two messages are injected into the ring, moving
+	   in opposite directions */
+	int dest;
+	TDB_DATA data;
+		
+	data.dptr = (uint8_t *)&incr;
+	data.dsize = sizeof(incr);
+
+	dest = (ctdb_get_pnn(ctdb) + num_nodes + incr) % num_nodes;
+	ctdb_client_send_message(ctdb, dest, 0, data);
+}
+
+static void each_second(struct event_context *ev, struct timed_event *te, 
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+
+	/* we kickstart the ring into action by inserting messages from node
+	   with pnn 0.
+	   it may happen that some other node does not yet have ctdb_bench
+	   running in which case the ring is broken and the messages are lost.
+	   if so, once every second try again to restart the ring
+	*/
+	if (msg_plus == 0) {
+//		printf("no messages recevied, try again to kickstart the ring in forward direction...\n");
+		send_start_messages(ctdb, 1);
+	}
+	if (msg_minus == 0) {
+//		printf("no messages recevied, try again to kickstart the ring in reverse direction...\n");
+		send_start_messages(ctdb, -1);
+	}
+	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+}
+
+static void dummy_event(struct event_context *ev, struct timed_event *te, 
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), dummy_event, ctdb);
+}
+
+/*
+  benchmark sending messages in a ring around the nodes
+*/
+static void bench_ring(struct ctdb_context *ctdb, struct event_context *ev)
+{
+	int pnn=ctdb_get_pnn(ctdb);
+
+	if (pnn == 0) {
+		event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+	} else {
+		event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), dummy_event, ctdb);
+	}
+
+	start_timer();
+	while (end_timer() < timelimit) {
+		if (pnn == 0 && msg_count % 10000 == 0 && end_timer() > 0) {
+			printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\r", 
+			       msg_count/end_timer(), msg_plus, msg_minus);
+			fflush(stdout);
+		}
+		event_loop_once(ev);
+	}
+
+	printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\n", 
+	       msg_count/end_timer(), msg_plus, msg_minus);
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" },
+		{ "num-records", 'r', POPT_ARG_INT, &num_records, 0, "num_records", "integer" },
+		{ NULL, 'n', POPT_ARG_INT, &num_nodes, 0, "num_nodes", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	int ret;
+	poptContext pc;
+	struct event_context *ev;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	if (num_nodes == 0) {
+		printf("You must specify the number of nodes\n");
+		exit(1);
+	}
+
+	ev = event_context_init(NULL);
+
+	/* initialise ctdb */
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), "test.tdb",
+			      false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	/* setup a ctdb call function */
+	ret = ctdb_set_call(ctdb_db, incr_func,  FUNC_INCR);
+	ret = ctdb_set_call(ctdb_db, fetch_func, FUNC_FETCH);
+
+	if (ctdb_client_set_message_handler(ctdb, 0, ring_message_handler,&msg_count))
+		goto error;
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+	bench_ring(ctdb, ev);
+       
+error:
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_fetch.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_fetch.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_fetch.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,256 @@
+/* 
+   simple ctdb benchmark
+
+   Copyright (C) Andrew Tridgell  2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+
+static int timelimit = 10;
+static int num_records = 10;
+static int num_nodes;
+static int msg_count;
+
+#define TESTKEY "testkey"
+
+/*
+  fetch a record
+  store a expanded record
+  send a message to next node to tell it to do the same
+*/
+static void bench_fetch_1node(struct ctdb_context *ctdb)
+{
+	TDB_DATA key, data, nulldata;
+	struct ctdb_db_context *ctdb_db;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	int dest, ret;
+	struct ctdb_record_handle *h;
+
+	key.dptr = discard_const(TESTKEY);
+	key.dsize = strlen(TESTKEY);
+
+	ctdb_db = ctdb_db_handle(ctdb, "test.tdb");
+
+	h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data);
+	if (h == NULL) {
+		printf("Failed to fetch record '%s' on node %d\n", 
+		       (const char *)key.dptr, ctdb_get_pnn(ctdb));
+		talloc_free(tmp_ctx);
+		return;
+	}
+
+	if (data.dsize > 1000) {
+		data.dsize = 0;
+	}
+
+	if (data.dsize == 0) {
+		data.dptr = (uint8_t *)talloc_asprintf(tmp_ctx, "Test data\n");
+	}
+	data.dptr = (uint8_t *)talloc_asprintf_append((char *)data.dptr, 
+						      "msg_count=%d on node %d\n",
+						      msg_count, ctdb_get_pnn(ctdb));
+	data.dsize = strlen((const char *)data.dptr)+1;
+
+	ret = ctdb_record_store(h, data);
+	talloc_free(h);
+	if (ret != 0) {
+		printf("Failed to store record\n");
+	}
+
+	talloc_free(tmp_ctx);
+
+	/* tell the next node to do the same */
+	nulldata.dptr = NULL;
+	nulldata.dsize = 0;
+
+	dest = (ctdb_get_pnn(ctdb) + 1) % num_nodes;
+	ctdb_client_send_message(ctdb, dest, 0, nulldata);
+}
+
+/*
+  handler for messages in bench_ring()
+*/
+static void message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			    TDB_DATA data, void *private_data)
+{
+	msg_count++;
+	bench_fetch_1node(ctdb);
+}
+
+
+/*
+  benchmark the following:
+
+  fetch a record
+  store a expanded record
+  send a message to next node to tell it to do the same
+
+*/
+static void bench_fetch(struct ctdb_context *ctdb, struct event_context *ev)
+{
+	int pnn=ctdb_get_pnn(ctdb);
+
+	if (pnn == num_nodes - 1) {
+		bench_fetch_1node(ctdb);
+	}
+	
+	start_timer();
+
+	while (end_timer() < timelimit) {
+		if (pnn == 0 && msg_count % 100 == 0 && end_timer() > 0) {
+			printf("Fetch: %.2f msgs/sec\r", msg_count/end_timer());
+			fflush(stdout);
+		}
+		if (event_loop_once(ev) != 0) {
+			printf("Event loop failed!\n");
+			break;
+		}
+	}
+
+	printf("Fetch: %.2f msgs/sec\n", msg_count/end_timer());
+}
+
+/*
+  handler for reconfigure message
+*/
+static void reconfigure_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+				TDB_DATA data, void *private_data)
+{
+	int *ready = (int *)private_data;
+	*ready = 1;
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" },
+		{ "num-records", 'r', POPT_ARG_INT, &num_records, 0, "num_records", "integer" },
+		{ NULL, 'n', POPT_ARG_INT, &num_nodes, 0, "num_nodes", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+	TDB_DATA key, data;
+	struct ctdb_record_handle *h;
+	int cluster_ready=0;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* talloc_enable_leak_report_full(); */
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	if (num_nodes == 0) {
+		printf("You must specify the number of nodes\n");
+		exit(1);
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
+
+	if (ctdb == NULL) {
+		printf("failed to connect to ctdb daemon.\n");
+		exit(1);
+	}
+
+	ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RECONFIGURE, reconfigure_handler, 
+				 &cluster_ready);
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), "test.tdb",
+			      false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	ctdb_client_set_message_handler(ctdb, 0, message_handler, &msg_count);
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+	bench_fetch(ctdb, ev);
+
+	key.dptr = discard_const(TESTKEY);
+	key.dsize = strlen(TESTKEY);
+
+	printf("Fetching final record\n");
+
+	h = ctdb_fetch_lock(ctdb_db, ctdb, key, &data);
+
+	if (h == NULL) {
+		printf("Failed to fetch record '%s' on node %d\n", 
+		       (const char *)key.dptr, ctdb_get_pnn(ctdb));
+		exit(1);
+	}
+
+	printf("DATA:\n%s\n", (char *)data.dptr);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_lock_once.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_lock_once.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_lock_once.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,144 @@
+/* 
+   simple ctdb test tool
+   This test just fetch_locks a record and releases it once.
+
+   Copyright (C) Ronnie Sahlberg 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include <poll.h>
+#include <err.h>
+#include "ctdb.h"
+
+#define TESTKEY "testkey"
+
+static void rrl_cb(struct ctdb_db *ctdb_db,
+		   struct ctdb_lock *lock, TDB_DATA outdata, void *private)
+{
+	bool *rrl_cb_called = private;
+
+	printf("Record fetchlocked.\n");
+	printf("Press enter to release the record ...\n");
+	(void)getchar();
+	printf("Record released.\n");
+
+	*rrl_cb_called = true;
+	return;
+}
+
+/*
+	Just try locking/unlocking a single record once
+*/
+static void fetch_lock_once(struct ctdb_connection *ctdb, struct ctdb_db *ctdb_db)
+{
+	TDB_DATA key;
+	bool rrl_cb_finished = false;
+
+	key.dptr = discard_const(TESTKEY);
+	key.dsize = strlen(TESTKEY);
+
+	printf("Trying to fetch lock the record ...\n");
+
+	/* In the non-contended case the callback might be invoked
+	 * immediately, before ctdb_readrecordlock_async() returns.
+	 * In the contended case the callback will be invoked later.
+	 *
+	 * Normally an application would not care whether the callback
+	 * has already been invoked here or not, but if the application
+	 * needs to know, it can use the *private_data pointer
+	 * to pass data through to the callback and back.
+	 */
+	if (!ctdb_readrecordlock_async(ctdb_db, key,
+				       rrl_cb, &rrl_cb_finished)) {
+		printf("Failed to send READRECORDLOCK\n");
+		exit(10);
+	}
+	while (!rrl_cb_finished) {
+		struct pollfd pfd;
+
+		pfd.fd = ctdb_get_fd(ctdb);
+		pfd.events = ctdb_which_events(ctdb);
+		if (poll(&pfd, 1, -1) < 0) {
+			printf("Poll failed");
+			exit(10);
+		}
+		if (ctdb_service(ctdb, pfd.revents) < 0) {
+			err(1, "Failed to service");
+		}
+	}
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_connection *ctdb;
+	struct ctdb_db *ctdb_db;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ctdb = ctdb_connect("/tmp/ctdb.socket",
+				       ctdb_log_file, stderr);
+	if (!ctdb)
+		err(1, "Connecting to /tmp/ctdb.socket");
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attachdb(ctdb, "test.tdb", false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attachdb failed\n");
+		exit(1);
+	}
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_getrecmode(ctdb, CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		sleep(1);
+	}
+
+	fetch_lock_once(ctdb, ctdb_db);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_one.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_one.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_one.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,146 @@
+/* 
+   simple ctdb benchmark
+   This test just fetch_locks a record and releases it in a loop.
+
+   Copyright (C) Ronnie Sahlberg 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+static int timelimit = 10;
+static int lock_count = 0;
+
+static struct ctdb_db_context *ctdb_db;
+
+#define TESTKEY "testkey"
+
+
+static void alarm_handler(int sig)
+{
+	printf("Locks:%d\n", lock_count);
+	lock_count=0;
+
+	timelimit--;
+	if (timelimit <= 0) {
+		exit(0);
+	}
+	alarm(1);
+}
+
+/*
+	Just try locking/unlocking the same record over and over
+*/
+static void bench_fetch_one_loop(struct ctdb_context *ctdb, struct event_context *ev)
+{
+	TDB_DATA key, data;
+
+	key.dptr = discard_const(TESTKEY);
+	key.dsize = strlen(TESTKEY);
+
+
+	while (1) {
+		TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+		struct ctdb_record_handle *h;
+
+		h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data);
+		if (h == NULL) {
+			printf("Failed to fetch record '%s' on node %d\n", 
+		       		(const char *)key.dptr, ctdb_get_pnn(ctdb));
+			talloc_free(tmp_ctx);
+			continue;
+		}
+
+		talloc_free(tmp_ctx);
+		lock_count++;
+	}
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
+
+	if (ctdb == NULL) {
+		printf("failed to connect to ctdb daemon.\n");
+		exit(1);
+	}
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), "test.tdb",
+			      false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+	signal(SIGALRM, alarm_handler);
+	alarm(1);
+
+	bench_fetch_one_loop(ctdb, ev);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_readonly_loop.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_readonly_loop.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_readonly_loop.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,134 @@
+/* 
+   simple ctdb test tool
+   This test just fetch_locks a record and releases it in a loop.
+
+   Copyright (C) Ronnie Sahlberg 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+#include "ctdb_private.h"
+
+static struct ctdb_db_context *ctdb_db;
+
+const char *TESTKEY = "testkey";
+static int count;
+
+/*
+	Just try locking/unlocking a single record once
+*/
+static void fetch_lock_once(struct ctdb_context *ctdb, struct event_context *ev)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA key, data;
+	struct ctdb_record_handle *h;
+
+	key.dptr = discard_const(TESTKEY);
+	key.dsize = strlen(TESTKEY);
+
+//	printf("Trying to fetch lock the record ...\n");
+
+	h = ctdb_fetch_readonly_lock(ctdb_db, tmp_ctx, key, &data, true);
+	if (h == NULL) {
+		printf("Failed to fetch record '%s' on node %d\n", 
+	       		(const char *)key.dptr, ctdb_get_pnn(ctdb));
+		talloc_free(tmp_ctx);
+		exit(10);
+	}
+
+	count++;
+	printf("%d   data:%.*s\n", (int)count, (int)data.dsize, data.dptr);
+	talloc_free(tmp_ctx);
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	TDB_DATA key;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "record",      'r', POPT_ARG_STRING, &TESTKEY, 0, "record", "string" },
+		POPT_TABLEEND
+	};
+	int opt, ret;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(5, 0));
+
+	key.dptr  = discard_const(TESTKEY);
+	key.dsize = strlen(TESTKEY);
+
+	ret = ctdb_ctrl_getvnnmap(ctdb, timeval_zero(), CTDB_CURRENT_NODE, ctdb, &ctdb->vnn_map);
+	if (ret != 0) {
+		printf("failed to get vnnmap\n");
+		exit(10);
+	}
+	printf("Record:%s\n", TESTKEY);
+	printf("Lmaster : %d\n", ctdb_lmaster(ctdb, &key)); 
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(5, 0), "test.tdb", false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+	while (1) {
+		fetch_lock_once(ctdb, ev);
+		usleep(10000);
+	}
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_readonly_once.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_readonly_once.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_fetch_readonly_once.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,142 @@
+/* 
+   simple ctdb test tool
+   This test just fetch_locks a record and releases it once.
+
+   Copyright (C) Ronnie Sahlberg 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include <poll.h>
+#include "ctdb.h"
+
+const char *TESTKEY = "testkey";
+
+static void rorl_cb(struct ctdb_db *ctdb_db,
+		   struct ctdb_lock *lock, TDB_DATA outdata, void *private)
+{
+	int *finished = private;
+
+	printf("Record fetchlocked.\n");
+	printf("Press enter to release the record ...\n");
+	(void)getchar();
+
+	*finished = 1;
+}
+
+/*
+	Just try locking/unlocking a single record once
+*/
+static void fetch_readonly_once(struct ctdb_connection *ctdb, struct ctdb_db *ctdb_db, TDB_DATA key)
+{
+	int finished;
+
+	printf("Trying to fetch lock the record ...\n");
+
+	finished = 0;
+	if (!ctdb_readonlyrecordlock_async(ctdb_db, key,
+				       rorl_cb, &finished)) {
+		printf("Failed to send READONLYRECORDLOCK\n");
+		exit(10);
+	}
+
+	while (!finished) {
+		struct pollfd pfd;
+
+		pfd.fd = ctdb_get_fd(ctdb);
+		pfd.events = ctdb_which_events(ctdb);
+		if (poll(&pfd, 1, -1) < 0) {
+			fprintf(stderr, "Poll failed");
+			exit(10);
+		}
+		if (ctdb_service(ctdb, pfd.revents) < 0) {
+			fprintf(stderr, "Failed to service");
+			exit(10);
+		}
+	}
+
+	printf("Record released.\n");
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_connection *ctdb;
+	struct ctdb_db *ctdb_db;
+
+	TDB_DATA key;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		{ "record",      'r', POPT_ARG_STRING, &TESTKEY, 0, "record", "string" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ctdb = ctdb_connect("/tmp/ctdb.socket",
+			    ctdb_log_file, stderr);
+
+	if (!ctdb) {
+		fprintf(stderr, "Connecting to /tmp/ctdb.socket");
+		exit(10);
+	}
+
+	key.dptr  = discard_const(TESTKEY);
+	key.dsize = strlen(TESTKEY);
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attachdb(ctdb, "test.tdb", false, 0);
+	if (!ctdb_db) {
+		fprintf(stderr, "ctdb_attachdb failed\n");
+		exit(10);
+	}
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_getrecmode(ctdb, CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		sleep(1);
+	}
+
+	fetch_readonly_once(ctdb, ctdb_db, key);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_persistent.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_persistent.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_persistent.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,269 @@
+/* 
+   simple tool to test persistent databases
+
+   Copyright (C) Andrew Tridgell  2006-2007
+   Copyright (c) Ronnie sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+static int timelimit = 10;
+
+static unsigned int pnn;
+
+static TDB_DATA old_data;
+
+static int success = true;
+
+static void each_second(struct event_context *ev, struct timed_event *te, 
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+	int i;
+	uint32_t *old_counters;
+
+
+	printf("[%4u] Counters: ", getpid());
+	old_counters = (uint32_t *)old_data.dptr;
+	for (i=0;i<old_data.dsize/sizeof(uint32_t); i++) {
+		printf("%6u ", old_counters[i]);
+	}
+	printf("\n"); 
+
+	event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+}
+
+static void check_counters(struct ctdb_context *ctdb, TDB_DATA data)
+{
+	int i;
+	uint32_t *counters, *old_counters;
+	unsigned char *tmp_dptr;
+
+	counters     = (uint32_t *)data.dptr;
+	old_counters = (uint32_t *)old_data.dptr;
+
+	/* check that all the counters are monotonic increasing */
+	for (i=0; i<old_data.dsize/sizeof(uint32_t); i++) {
+		if (counters[i]<old_counters[i]) {
+			printf("[%4u] ERROR: counters has decreased for node %u  From %u to %u\n", 
+			       getpid(), i, old_counters[i], counters[i]);
+			success = false;
+		}
+	}
+
+	if (old_data.dsize != data.dsize) {
+		old_data.dsize = data.dsize;
+		tmp_dptr = talloc_realloc_size(ctdb, old_data.dptr, old_data.dsize);
+		if (tmp_dptr == NULL) {
+			printf("[%4u] ERROR: talloc_realloc_size failed.\n", getpid());
+			success = false;
+			return;
+		} else {
+			old_data.dptr = tmp_dptr;
+		}
+	}
+
+	memcpy(old_data.dptr, data.dptr, data.dsize);
+}
+
+
+
+static void test_store_records(struct ctdb_context *ctdb, struct event_context *ev)
+{
+	TDB_DATA key;
+	struct ctdb_db_context *ctdb_db;
+
+	ctdb_db = ctdb_db_handle(ctdb, "persistent.tdb");
+
+	key.dptr = discard_const("testkey");
+	key.dsize = strlen((const char *)key.dptr)+1;
+
+	start_timer();
+	while (end_timer() < timelimit) {
+		TDB_DATA data;
+		TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+		struct ctdb_transaction_handle *h;
+		int ret;
+		uint32_t *counters;
+
+		h = ctdb_transaction_start(ctdb_db, tmp_ctx);
+		if (h == NULL) {
+			printf("Failed to start transaction on node %d\n",
+			       ctdb_get_pnn(ctdb));
+			talloc_free(tmp_ctx);
+			return;
+		}
+
+		ret = ctdb_transaction_fetch(h, tmp_ctx, key, &data);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to fetch record\n"));
+			exit(1);
+		}
+
+		if (data.dsize < sizeof(uint32_t) * (pnn+1)) {
+			unsigned char *ptr = data.dptr;
+			
+			data.dptr = talloc_zero_size(tmp_ctx, sizeof(uint32_t) * (pnn+1));
+			memcpy(data.dptr, ptr, data.dsize);
+			talloc_free(ptr);
+
+			data.dsize = sizeof(uint32_t) * (pnn+1);
+		}
+
+		if (data.dptr == NULL) {
+			printf("Failed to realloc array\n");
+			talloc_free(tmp_ctx);
+			return;
+		}
+
+		counters = (uint32_t *)data.dptr;
+
+		/* bump our counter */
+		counters[pnn]++;
+
+		ret = ctdb_transaction_store(h, key, data);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to store record\n"));
+			exit(1);
+		}
+
+		ret = ctdb_transaction_commit(h);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to commit transaction\n"));
+			//exit(1);
+		}
+
+		/* store the counters and verify that they are sane */
+		if (pnn == 0) {
+			check_counters(ctdb, data);
+		}
+
+		talloc_free(tmp_ctx);
+	}
+
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	int unsafe_writes = 0;
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" },
+		{ "unsafe-writes", 'u', POPT_ARG_NONE, &unsafe_writes, 0, "do not use tdb transactions when writing", NULL },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	setlinebuf(stdout);
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
+	if (ctdb == NULL) {
+		printf("Could not attach to daemon\n");
+		return 1;
+	}
+
+	/* attach to a specific database */
+	if (unsafe_writes == 1) {
+		ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0),
+				      "persistent.tdb", true, TDB_NOSYNC);
+	} else {
+		ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0),
+				      "persistent.tdb", true, 0);
+	}
+
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+	pnn = ctdb_get_pnn(ctdb);
+	printf("Starting test on node %u. running for %u seconds\n", pnn, timelimit);
+
+	if (pnn == 0) {
+		event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+	}
+
+	test_store_records(ctdb, ev);
+
+	if (pnn == 0) {
+		if (success != true) {
+			printf("The test FAILED\n");
+			return 1;
+		} else {
+			printf("SUCCESS!\n");
+		}
+	}
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_randrec.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_randrec.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_randrec.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,202 @@
+/* 
+   create a lot of random records, both current records and deleted records
+
+   Copyright (C) Andrew Tridgell  2008
+	Ronnie sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+#include "ctdb_private.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+static int num_records = 10;
+static int delete_pct = 75;
+static int base_rec;
+
+static void store_records(struct ctdb_context *ctdb, struct event_context *ev)
+{
+	TDB_DATA key, data;
+	struct ctdb_db_context *ctdb_db;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	int ret;
+	struct ctdb_record_handle *h;
+	uint32_t i=0;
+	
+	ctdb_db = ctdb_db_handle(ctdb, "test.tdb");
+
+	srandom(time(NULL) ^ getpid());
+
+	start_timer();
+
+	printf("working with %d records\n", num_records);
+	while (1) {
+		unsigned r = random() % num_records;
+		key.dptr = (uint8_t *)&r;
+		key.dsize = sizeof(r); 
+
+		h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data);
+		if (h == NULL) {
+			printf("Failed to fetch record '%s' on node %d\n", 
+			       (const char *)key.dptr, ctdb_get_pnn(ctdb));
+			talloc_free(tmp_ctx);
+			return;
+		}
+
+		if (random() % 100 < delete_pct) {
+			data.dptr = NULL;
+			data.dsize = 0;
+		} else {
+			data.dptr = talloc_zero_size(h, data.dsize + sizeof(r));
+			data.dsize += sizeof(r);
+		}
+
+		ret = ctdb_record_store(h, data);
+		if (ret != 0) {
+			printf("Failed to store record\n");
+		}
+
+		if (data.dptr == NULL && data.dsize == 0) {
+			struct ctdb_control_schedule_for_deletion *dd;
+			TDB_DATA indata;
+			int32_t status;
+
+			indata.dsize = offsetof(struct ctdb_control_schedule_for_deletion, key) + key.dsize;
+			indata.dptr = talloc_zero_array(ctdb, uint8_t, indata.dsize);
+			if (indata.dptr == NULL) {
+				printf("out of memory\n");
+				exit(1);
+			}
+			dd = (struct ctdb_control_schedule_for_deletion *)(void *)indata.dptr;
+			dd->db_id = ctdb_db->db_id;
+			dd->hdr = *ctdb_header_from_record_handle(h);
+			dd->keylen = key.dsize;
+			memcpy(dd->key, key.dptr, key.dsize);
+
+			ret = ctdb_control(ctdb,
+					   CTDB_CURRENT_NODE,
+					   ctdb_db->db_id,
+					   CTDB_CONTROL_SCHEDULE_FOR_DELETION,
+					   0, /* flags */
+					   indata,
+					   NULL, /* mem_ctx */
+					   NULL, /* outdata */
+					   &status,
+					   NULL, /* timeout : NULL == wait forever */
+					   NULL); /* error message */
+
+			talloc_free(indata.dptr);
+
+			if (ret != 0 || status != 0) {
+				DEBUG(DEBUG_ERR, (__location__ " Error sending "
+						  "SCHEDULE_FOR_DELETION "
+						  "control.\n"));
+			}
+		}
+
+		talloc_free(h);
+
+		if (i % 1000 == 0) {
+			printf("%7.0f recs/second   %u total\r", 1000.0 / end_timer(), i);
+			fflush(stdout);
+			start_timer();
+		}
+		i++;
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "num-records", 'r', POPT_ARG_INT, &num_records, 0, "num_records", "integer" },
+		{ "base-rec", 'b', POPT_ARG_INT, &base_rec, 0, "base_rec", "integer" },
+		{ "delete-pct", 'p', POPT_ARG_INT, &delete_pct, 0, "delete_pct", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
+
+	if (ctdb == NULL) {
+		printf("failed to connect to daemon\n");
+		exit(1);
+	}
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), "test.tdb",
+			      false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	store_records(ctdb, ev);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_store.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_store.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_store.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,164 @@
+/* 
+   simple tool to create a lot of records on a tdb and to read them out
+
+   Copyright (C) Andrew Tridgell  2006
+	Ronnie sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+static int num_records = 10;
+static int base_rec;
+
+static void store_records(struct ctdb_context *ctdb, struct event_context *ev)
+{
+	TDB_DATA key, data;
+	struct ctdb_db_context *ctdb_db;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	int ret;
+	struct ctdb_record_handle *h;
+	uint32_t i;
+	
+	ctdb_db = ctdb_db_handle(ctdb, "test.tdb");
+
+	printf("creating %d records\n", num_records);
+	for (i=0;i<num_records;i++) {
+		int r = base_rec + i;
+		key.dptr = (uint8_t *)&r;
+		key.dsize = sizeof(uint32_t); 
+
+		h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data);
+		if (h == NULL) {
+			printf("Failed to fetch record '%s' on node %d\n", 
+			       (const char *)key.dptr, ctdb_get_pnn(ctdb));
+			talloc_free(tmp_ctx);
+			return;
+		}
+
+		data.dptr = (uint8_t *)&i;
+		data.dsize = sizeof(uint32_t);
+
+		ret = ctdb_record_store(h, data);
+		talloc_free(h);
+		if (ret != 0) {
+			printf("Failed to store record\n");
+		}
+		if (i % 1000 == 0) {
+			printf("%u\r", i);
+			fflush(stdout);
+		}
+	}
+
+	printf("fetching all %d records\n", num_records);
+	while (1) {
+		for (i=0;i<num_records;i++) {
+			int r = base_rec + i;
+			key.dptr = (uint8_t *)&r;
+			key.dsize = sizeof(uint32_t); 
+
+			h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data);
+			if (h == NULL) {
+				printf("Failed to fetch record '%s' on node %d\n", 
+				       (const char *)key.dptr, ctdb_get_pnn(ctdb));
+				talloc_free(tmp_ctx);
+				return;
+			}
+			talloc_free(h);
+		}
+		sleep(1);
+		printf(".");
+		fflush(stdout);
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "num-records", 'r', POPT_ARG_INT, &num_records, 0, "num_records", "integer" },
+		{ "base-rec", 'b', POPT_ARG_INT, &base_rec, 0, "base_rec", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* talloc_enable_leak_report_full(); */
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
+
+	if (ctdb == NULL) {
+		printf("failed to connect to ctdb daemon.\n");
+		exit(1);
+	}
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), "test.tdb", false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+	store_records(ctdb, ev);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_takeover_tests.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_takeover_tests.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_takeover_tests.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,383 @@
+/* 
+   Tests for ctdb_takeover.c
+
+   Copyright (C) Martin Schwenke 2011
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../include/ctdb_private.h"
+
+/*
+ * Need these, since they're defined in ctdbd.c but we can't link
+ * that.
+ */
+int script_log_level;
+bool fast_start;
+void ctdb_load_nodes_file(struct ctdb_context *ctdb) {}
+
+/* Format of each line is "IP pnn" - the separator has to be at least
+ * 1 space (not a tab or whatever - a space!).
+ */
+static struct ctdb_public_ip_list *
+read_ctdb_public_ip_list(TALLOC_CTX *ctx)
+{
+	char line[1024];
+	ctdb_sock_addr addr;
+	char *t;
+	int pnn;
+	struct ctdb_public_ip_list *last = NULL;
+
+	struct ctdb_public_ip_list *ret = NULL;
+
+	while (fgets(line, sizeof(line), stdin) != NULL) {
+		
+		if ((t = strchr(line, ' ')) != NULL) {
+			/* Make line contain just the address */
+			*t = '\0';
+			/* Point to PNN or leading whitespace...  */
+			t++;
+			pnn = (int) strtol(t, (char **) NULL, 10);
+		} else {
+			/* Assume just an IP address, default to PNN -1 */
+			if ((t = strchr(line, '\n')) != NULL) {
+				*t = '\0';
+			}
+			pnn = -1;
+		}
+	       
+		if (parse_ip(line, NULL, 0, &addr)) {
+			if (last == NULL) {
+				last = talloc(ctx, struct ctdb_public_ip_list);
+			} else {
+				last->next = talloc(ctx, struct ctdb_public_ip_list);
+				last = last->next;
+			}
+			last->next = NULL;
+			last->pnn = pnn;
+			memcpy(&(last->addr), &addr, sizeof(addr));
+			if (ret == NULL) {
+				ret = last;
+			}
+		} else {
+			DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", line));
+		}
+	}
+			
+	return ret;
+}
+
+void print_ctdb_public_ip_list(struct ctdb_public_ip_list * ips)
+{
+	while (ips) {
+		printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
+		ips = ips->next;
+	}
+}
+
+/* Read some IPs from stdin, 1 per line, parse them and then print
+ * them back out. */
+void ctdb_test_read_ctdb_public_ip_list(void)
+{
+	struct ctdb_public_ip_list *l;
+
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+	l = read_ctdb_public_ip_list(tmp_ctx);
+
+	print_ctdb_public_ip_list(l);
+
+	talloc_free(tmp_ctx);
+}
+
+/* Read 2 IPs from stdin, calculate the IP distance and print it. */
+void ctdb_test_ip_distance(void)
+{
+	struct ctdb_public_ip_list *l;
+	uint32_t distance;
+
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+	l = read_ctdb_public_ip_list(tmp_ctx);
+
+	if (l && l->next) {
+		distance = ip_distance(&(l->addr), &(l->next->addr));
+		printf ("%lu\n", (unsigned long) distance);
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+/* Read some IPs from stdin, calculate the sum of the squares of the
+ * IP distances between the 1st argument and those read that are on
+ * the given node. The given IP must one of the ones in the list.  */
+void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
+{
+	struct ctdb_public_ip_list *l;
+	struct ctdb_public_ip_list *t;
+	ctdb_sock_addr addr;
+	uint32_t distance;
+
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+	
+	l = read_ctdb_public_ip_list(tmp_ctx);
+
+	if (l && parse_ip(ip, NULL, 0, &addr)) {
+		/* find the entry for the specified IP */
+		for (t=l; t!=NULL; t=t->next) {
+			if (ctdb_same_ip(&(t->addr), &addr)) {
+				break;
+			}
+		}
+
+		if (t == NULL) {
+			fprintf(stderr, "IP NOT PRESENT IN LIST");
+			exit(1);
+		}
+
+		distance = ip_distance_2_sum(&(t->addr), l, pnn);
+		printf ("%lu\n", (unsigned long) distance);
+	} else {
+		fprintf(stderr, "BAD INPUT");
+		exit(1);
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+/* Read some IPs from stdin, calculate the sume of the squares of the
+ * IP distances between the first and the rest, and print it. */
+void ctdb_test_lcp2_imbalance(int pnn)
+{
+	struct ctdb_public_ip_list *l;
+	uint32_t imbalance;
+
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+	l = read_ctdb_public_ip_list(tmp_ctx);
+
+	imbalance = lcp2_imbalance(l, pnn);
+	printf ("%lu\n", (unsigned long) imbalance);
+
+	talloc_free(tmp_ctx);
+}
+
+void ctdb_test_init(const char nodestates[],
+		    struct ctdb_context **ctdb,
+		    struct ctdb_public_ip_list **all_ips,
+		    struct ctdb_node_map **nodemap)
+{
+	struct ctdb_public_ip_list *t;
+	struct ctdb_all_public_ips *available_public_ips;
+	int i, numips, numnodes;
+	/* This is test code and this is unreasonably big... :-) */
+	uint32_t nodeflags[256];
+	char *tok, *ns;
+
+	*ctdb = talloc_zero(NULL, struct ctdb_context);
+
+	/* Avoid that const */
+	ns = talloc_strdup(*ctdb, nodestates);
+
+	numnodes = 0;
+	tok = strtok(ns, ",");
+	while (tok != NULL) {
+		nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 16);
+		numnodes++;
+		tok = strtok(NULL, ",");
+	}
+	
+	/* Fake things up... */
+	(*ctdb)->num_nodes = numnodes;
+
+	(*ctdb)->tunable.deterministic_public_ips = 0;
+	(*ctdb)->tunable.disable_ip_failover = 0;
+	(*ctdb)->tunable.no_ip_failback = 0;
+
+	if (getenv("CTDB_LCP2")) {
+		if (strcmp(getenv("CTDB_LCP2"), "yes") == 0) {
+			(*ctdb)->tunable.lcp2_public_ip_assignment = 1;
+		} else {
+			(*ctdb)->tunable.lcp2_public_ip_assignment = 0;
+		}
+	}
+
+	*nodemap =  talloc_array(*ctdb, struct ctdb_node_map, numnodes);
+	(*nodemap)->num = numnodes;
+
+	*all_ips = read_ctdb_public_ip_list(*ctdb);
+	numips = 0;
+	for (t = *all_ips; t != NULL; t = t->next) {
+		numips++;
+	}
+
+	available_public_ips = talloc_array(*ctdb, struct ctdb_all_public_ips, numips); // FIXME: bogus size, overkill
+	available_public_ips->num = numips;
+	for (t = *all_ips, i=0; t != NULL && i < numips ; t = t->next, i++) {
+		available_public_ips->ips[i].pnn = t->pnn;
+		memcpy(&(available_public_ips->ips[i].addr), &(t->addr), sizeof(t->addr));
+	}
+
+	(*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
+
+	/* Setup both nodemap and ctdb->nodes.  Mark all nodes as
+	 * healthy - change this later. */
+	for (i=0; i < numnodes; i++) {
+		(*nodemap)->nodes[i].pnn = i;
+		(*nodemap)->nodes[i].flags = nodeflags[i];
+		/* nodemap->nodes[i].sockaddr is uninitialised */
+
+		(*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
+		(*ctdb)->nodes[i]->pnn = i;
+		(*ctdb)->nodes[i]->flags = nodeflags[i];
+		(*ctdb)->nodes[i]->available_public_ips = available_public_ips;
+		(*ctdb)->nodes[i]->known_public_ips = available_public_ips;
+	}
+}
+
+/* IP layout is read from stdin. */
+void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_public_ip_list *all_ips;
+	struct ctdb_node_map *nodemap;
+
+	uint32_t *lcp2_imbalances;
+	bool *newly_healthy;
+
+	ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
+
+	lcp2_init(ctdb, nodemap,
+		  NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
+		  all_ips, &lcp2_imbalances, &newly_healthy);
+
+	lcp2_allocate_unassigned(ctdb, nodemap,
+				 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
+				 all_ips, lcp2_imbalances);
+
+	print_ctdb_public_ip_list(all_ips);
+
+	talloc_free(ctdb);
+}
+
+/* IP layout is read from stdin. */
+void ctdb_test_lcp2_failback(const char nodestates[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_public_ip_list *all_ips;
+	struct ctdb_node_map *nodemap;
+
+	uint32_t *lcp2_imbalances;
+	bool *newly_healthy;
+
+	ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
+
+	lcp2_init(ctdb, nodemap,
+		  NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
+		  all_ips, &lcp2_imbalances, &newly_healthy);
+
+	lcp2_failback(ctdb, nodemap,
+				 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
+		      all_ips, lcp2_imbalances, newly_healthy);
+
+	print_ctdb_public_ip_list(all_ips);
+
+	talloc_free(ctdb);
+}
+
+/* IP layout is read from stdin. */
+void ctdb_test_lcp2_failback_loop(const char nodestates[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_public_ip_list *all_ips;
+	struct ctdb_node_map *nodemap;
+
+	uint32_t *lcp2_imbalances;
+	bool *newly_healthy;
+
+	ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
+
+	lcp2_init(ctdb, nodemap,
+		  NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
+		  all_ips, &lcp2_imbalances, &newly_healthy);
+
+try_again:
+	if (lcp2_failback(ctdb, nodemap,
+			  NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
+			  all_ips, lcp2_imbalances, newly_healthy)) {
+		goto try_again;
+	}
+
+	print_ctdb_public_ip_list(all_ips);
+
+	talloc_free(ctdb);
+}
+
+/* IP layout is read from stdin. */
+void ctdb_test_ctdb_takeover_run_core(const char nodestates[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_public_ip_list *all_ips;
+	struct ctdb_node_map *nodemap;
+
+	ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
+
+	ctdb_takeover_run_core(ctdb, nodemap, &all_ips);
+
+	print_ctdb_public_ip_list(all_ips);
+
+	talloc_free(ctdb);
+}
+
+void usage(void)
+{
+	fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
+	exit(1);
+}
+
+int main(int argc, const char *argv[])
+{
+	LogLevel = DEBUG_DEBUG;
+	if (getenv("CTDB_TEST_LOGLEVEL")) {
+		LogLevel = atoi(getenv("CTDB_TEST_LOGLEVEL"));
+	}
+
+	if (argc < 2) {
+		usage();
+	}
+
+	if (strcmp(argv[1], "ip_list") == 0) {
+		ctdb_test_read_ctdb_public_ip_list();
+	} else if (strcmp(argv[1], "ip_distance") == 0) {
+		ctdb_test_ip_distance();
+	} else if (argc == 4 && strcmp(argv[1], "ip_distance_2_sum") == 0) {
+		ctdb_test_ip_distance_2_sum(argv[2], atoi(argv[3]));
+	} else if (argc >= 3 && strcmp(argv[1], "lcp2_imbalance") == 0) {
+		ctdb_test_lcp2_imbalance(atoi(argv[2]));
+	} else if (argc == 3 && strcmp(argv[1], "lcp2_allocate_unassigned") == 0) {
+		ctdb_test_lcp2_allocate_unassigned(argv[2]);
+	} else if (argc == 3 && strcmp(argv[1], "lcp2_failback") == 0) {
+		ctdb_test_lcp2_failback(argv[2]);
+	} else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
+		ctdb_test_lcp2_failback_loop(argv[2]);
+	} else if (argc == 3 && strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
+		ctdb_test_ctdb_takeover_run_core(argv[2]);
+	} else {
+		usage();
+	}
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_trackingdb_test.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_trackingdb_test.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_trackingdb_test.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,134 @@
+/* 
+   simple trackingdb test tool
+
+   This program is used to test the funcitons to manipulate and enumerate
+   the trackingdb records :
+	ctdb_trackingdb_add_pnn()
+	ctdb_trackingdb_traverse()
+
+   Copyright (C) Ronnie Sahlberg 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <time.h>
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+#include "ctdb_private.h"
+#include "db_wrap.h"
+
+#define MAXINDEX 64
+char indices[MAXINDEX];
+
+void vn_cb(struct ctdb_context *ctdb, uint32_t pnn, void *private_data)
+{
+	char *ind = private_data;
+
+	printf("Callback for node %d\n", pnn);
+	if (ind[pnn] == 0) {
+		printf("ERROR, node %d from callback was never added\n", pnn);
+		exit(10);
+	}
+	ind[pnn] = 0;
+}
+
+void verify_nodes(struct ctdb_context *ctdb, TDB_DATA data)
+{
+	int i;
+
+	printf("Verify the nodes\n");
+	ctdb_trackingdb_traverse(ctdb, data, vn_cb, indices);
+	for(i = 0; i < MAXINDEX; i++) {
+		if (indices[i] != 0) {
+			printf("Callback for %d was never invoked\n", i);
+			exit(0);
+		}
+	}
+}
+
+	
+	
+void add_node(struct ctdb_context *ctdb, TDB_DATA *data, int pnn)
+{
+	printf("Add node %d\n", pnn);
+	if (ctdb_trackingdb_add_pnn(ctdb, data, pnn)) {
+		printf("Failed to add tracking db data\n");
+		exit(10);
+	}
+	indices[pnn] = 1;
+}
+
+static void trackdb_test(struct ctdb_context *ctdb)
+{
+	TDB_DATA data = {NULL,0};
+	int i;
+
+	printf("Add 10 nodes\n");
+	srandom(time(NULL));
+	for(i=0; i<10; i++) {
+		add_node(ctdb, &data, random()%MAXINDEX);
+	}
+
+	verify_nodes(ctdb, data);
+	printf("OK all seems well\n");
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(5, 0));
+
+	trackdb_test(ctdb);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_transaction.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_transaction.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_transaction.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,301 @@
+/* 
+   simple tool to test persistent databases
+
+   Copyright (C) Andrew Tridgell  2006-2007
+   Copyright (c) Ronnie sahlberg  2007
+   Copyright (C) Michael Adam     2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+static int timelimit = 10;
+static int delay = 0;
+static int verbose = 0;
+
+static unsigned int pnn;
+
+static TDB_DATA old_data;
+
+static int success = true;
+
+static void print_counters(void)
+{
+	int i;
+	uint32_t *old_counters;
+
+	printf("[%4u] Counters: ", getpid());
+	old_counters = (uint32_t *)old_data.dptr;
+	for (i=0;i<old_data.dsize/sizeof(uint32_t); i++) {
+		printf("%6u ", old_counters[i]);
+	}
+	printf("\n");
+}
+
+static void each_second(struct event_context *ev, struct timed_event *te,
+					 struct timeval t, void *private_data)
+{
+	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
+
+	print_counters();
+
+	event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+}
+
+static void check_counters(struct ctdb_context *ctdb, TDB_DATA data)
+{
+	int i;
+	uint32_t *counters, *old_counters;
+
+	counters     = (uint32_t *)data.dptr;
+	old_counters = (uint32_t *)old_data.dptr;
+
+	/* check that all the counters are monotonic increasing */
+	for (i=0; i<old_data.dsize/sizeof(uint32_t); i++) {
+		if (counters[i]<old_counters[i]) {
+			printf("[%4u] ERROR: counters has decreased for node %u  From %u to %u\n", 
+			       getpid(), i, old_counters[i], counters[i]);
+			success = false;
+		}
+	}
+
+	if (old_data.dsize != data.dsize) {
+		old_data.dsize = data.dsize;
+		old_data.dptr = talloc_realloc_size(ctdb, old_data.dptr, old_data.dsize);
+	}
+
+	memcpy(old_data.dptr, data.dptr, data.dsize);
+	if (verbose) print_counters();
+}
+
+
+static void do_sleep(unsigned int sec)
+{
+	unsigned int i;
+	for (i=0; i<sec; i++) {
+		if (verbose) printf(".");
+		sleep(1);
+	}
+	if (verbose) printf("\n");
+}
+
+static void test_store_records(struct ctdb_context *ctdb, struct event_context *ev)
+{
+	TDB_DATA key;
+	struct ctdb_db_context *ctdb_db;
+	int ret;
+	uint32_t *counters;
+	ctdb_db = ctdb_db_handle(ctdb, "transaction.tdb");
+
+	key.dptr = discard_const("testkey");
+	key.dsize = strlen((const char *)key.dptr)+1;
+
+	start_timer();
+	while ((timelimit == 0) || (end_timer() < timelimit)) {
+		TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+		TDB_DATA data;
+		struct ctdb_transaction_handle *h;
+
+		if (verbose) DEBUG(DEBUG_ERR, ("starting transaction\n"));
+		h = ctdb_transaction_start(ctdb_db, tmp_ctx);
+		if (h == NULL) {
+			DEBUG(DEBUG_ERR, ("Failed to start transaction on node %d\n",
+			       ctdb_get_pnn(ctdb)));
+			talloc_free(tmp_ctx);
+			return;
+		}
+		if (verbose) DEBUG(DEBUG_ERR, ("transaction started\n"));
+		do_sleep(delay);
+
+		if (verbose) DEBUG(DEBUG_ERR, ("calling transaction_fetch\n"));
+		ret = ctdb_transaction_fetch(h, tmp_ctx, key, &data);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to fetch record\n"));
+			exit(1);
+		}
+		if (verbose) DEBUG(DEBUG_ERR, ("fetched data ok\n"));
+		do_sleep(delay);
+
+		if (data.dsize < sizeof(uint32_t) * (pnn+1)) {
+			unsigned char *ptr = data.dptr;
+
+			data.dptr = talloc_zero_size(tmp_ctx, sizeof(uint32_t) * (pnn+1));
+			memcpy(data.dptr, ptr, data.dsize);
+			talloc_free(ptr);
+
+			data.dsize = sizeof(uint32_t) * (pnn+1);
+		}
+
+		if (data.dptr == NULL) {
+			DEBUG(DEBUG_ERR, ("Failed to realloc array\n"));
+			talloc_free(tmp_ctx);
+			return;
+		}
+
+		counters = (uint32_t *)data.dptr;
+
+		/* bump our counter */
+		counters[pnn]++;
+
+		if (verbose) DEBUG(DEBUG_ERR, ("calling transaction_store\n"));
+		ret = ctdb_transaction_store(h, key, data);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to store record\n"));
+			exit(1);
+		}
+		if (verbose) DEBUG(DEBUG_ERR, ("stored data ok\n"));
+		do_sleep(delay);
+
+		if (verbose) DEBUG(DEBUG_ERR, ("calling transaction_commit\n"));
+		ret = ctdb_transaction_commit(h);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to commit transaction\n"));
+			check_counters(ctdb, data);
+			exit(1);
+		}
+		if (verbose) DEBUG(DEBUG_ERR, ("transaction committed\n"));
+
+		/* store the counters and verify that they are sane */
+		if (verbose || (pnn == 0)) {
+			check_counters(ctdb, data);
+		}
+
+		do_sleep(delay);
+
+		talloc_free(tmp_ctx);
+	}
+
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	int unsafe_writes = 0;
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" },
+		{ "delay", 'D', POPT_ARG_INT, &delay, 0, "delay (in seconds) between operations", "integer" },
+		{ "verbose", 'v', POPT_ARG_NONE,  &verbose, 0, "switch on verbose mode", NULL },
+		{ "unsafe-writes", 'u', POPT_ARG_NONE, &unsafe_writes, 0, "do not use tdb transactions when writing", NULL },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	printf("SUCCESS (transaction test disabled while transactions are being rewritten)\n");
+	exit(0);
+
+	if (verbose) {
+		setbuf(stdout, (char *)NULL); /* don't buffer */
+	} else {
+		setlinebuf(stdout);
+	}
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
+	if (ctdb == NULL) {
+		DEBUG(DEBUG_ERR, ("Could not attach to daemon\n"));
+		return 1;
+	}
+
+	/* attach to a specific database */
+	if (unsafe_writes == 1) {
+		ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0),
+				      "transaction.tdb", true, TDB_NOSYNC);
+	} else {
+		ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0),
+				      "transaction.tdb", true, 0);
+	}
+
+	if (!ctdb_db) {
+		DEBUG(DEBUG_ERR, ("ctdb_attach failed - %s\n", ctdb_errstr(ctdb)));
+		exit(1);
+	}
+
+	DEBUG(DEBUG_ERR, ("Waiting for cluster\n"));
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+	pnn = ctdb_get_pnn(ctdb);
+	printf("Starting test on node %u. running for %u seconds. sleep delay: %u seconds.\n", pnn, timelimit, delay);
+
+	if (!verbose && (pnn == 0)) {
+		event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb);
+	}
+
+	test_store_records(ctdb, ev);
+
+	if (verbose || (pnn == 0)) {
+		if (success != true) {
+			printf("The test FAILED\n");
+			return 1;
+		} else {
+			printf("SUCCESS!\n");
+		}
+	}
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_traverse.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_traverse.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_traverse.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,114 @@
+/* 
+   simple tool to traverse a ctdb database over and over and over
+
+   Copyright (C) Andrew Tridgell  2006
+	Ronnie sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+static const char *dbname = "test.tdb";
+
+static int traverse_callback(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *private_data)
+{
+	uint32_t *count = private_data;
+	
+	(*count)++;
+	return 0;
+}
+
+static void traverse_loop(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, struct event_context *ev)
+{
+	uint32_t count;
+
+	printf("traversing database\n");
+	count = 0;
+	ctdb_traverse(ctdb_db, traverse_callback, &count);
+	printf("traversed %d records\n", count);
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "database", 0, POPT_ARG_STRING, &dbname, 0, "database to traverse", "name" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* talloc_enable_leak_report_full(); */
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0));
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), dbname, false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+	while (1) {
+		traverse_loop(ctdb, ctdb_db, ev);
+	}
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/ctdb_update_record.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/ctdb_update_record.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/ctdb_update_record.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,158 @@
+/* 
+   simple ctdb test tool
+   This test just fetch_locks a record bumps the RSN and then writes new content
+
+   Copyright (C) Ronnie Sahlberg 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+#include "ctdb_private.h"
+
+static struct ctdb_db_context *ctdb_db;
+
+#define TESTKEY "testkey"
+
+
+/*
+	Just try locking/unlocking a single record once
+*/
+static void fetch_lock_once(struct ctdb_context *ctdb, struct event_context *ev, uint32_t generation)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA key, data;
+	struct ctdb_record_handle *h;
+	struct ctdb_ltdb_header *header;
+	int ret;
+
+	key.dptr = discard_const(TESTKEY);
+	key.dsize = strlen(TESTKEY);
+
+	printf("Trying to fetch lock the record ...\n");
+
+	h = ctdb_fetch_readonly_lock(ctdb_db, tmp_ctx, key, &data, false);
+	if (h == NULL) {
+		printf("Failed to fetch record '%s' on node %d\n", 
+	       		(const char *)key.dptr, ctdb_get_pnn(ctdb));
+		talloc_free(tmp_ctx);
+		exit(10);
+	}
+
+	printf("Record fetchlocked.\n");
+	header = talloc_memdup(tmp_ctx, ctdb_header_from_record_handle(h), sizeof(*header));
+       	printf("RSN:%d\n", (int)header->rsn);
+	talloc_free(h);
+	printf("Record released.\n");
+
+	printf("Write new record with RSN+10\n");
+	header->rsn += 10;
+	data.dptr = (void *)talloc_asprintf(tmp_ctx, "%d", (int)header->rsn);
+	data.dsize = strlen((char *)data.dptr);
+
+	ret = ctdb_ctrl_updaterecord(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, ctdb_db, key, header, data);
+	if (ret != 0) {
+		printf("Failed to writerecord,  ret==%d\n", ret);	
+		exit(1);
+	}
+
+	printf("re-fetch the record\n");
+	h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data);
+	if (h == NULL) {
+		printf("Failed to fetch record '%s' on node %d\n", 
+	       		(const char *)key.dptr, ctdb_get_pnn(ctdb));
+		talloc_free(tmp_ctx);
+		exit(10);
+	}
+
+	printf("Record fetchlocked.\n");
+	header = talloc_memdup(tmp_ctx, ctdb_header_from_record_handle(h), sizeof(*header));
+       	printf("RSN:%d\n", (int)header->rsn);
+	talloc_free(h);
+	printf("Record released.\n");
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+	struct ctdb_vnn_map *vnnmap=NULL;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+	ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(5, 0));
+
+	/* attach to a specific database */
+	ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(5, 0), "test.tdb", false, 0);
+	if (!ctdb_db) {
+		printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
+		exit(1);
+	}
+
+	printf("Waiting for cluster\n");
+	while (1) {
+		uint32_t recmode=1;
+		ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode);
+		if (recmode == 0) break;
+		event_loop_once(ev);
+	}
+
+
+	if (ctdb_ctrl_getvnnmap(ctdb, timeval_zero(), CTDB_CURRENT_NODE, ctdb, &vnnmap) != 0) {
+		printf("Unable to get vnnmap from local node\n");
+		exit(1);
+	}
+	printf("Current Generation %d\n", (int)vnnmap->generation);
+
+	fetch_lock_once(ctdb, ev, vnnmap->generation);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/rb_perftest.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/rb_perftest.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/rb_perftest.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,123 @@
+/* 
+   simple rb vs dlist benchmark
+
+   Copyright (C) Ronnie Sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "lib/util/dlinklist.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+#include <sys/time.h>
+#include <time.h>
+#include "common/rb_tree.h"
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+
+static int num_records = 1000;
+
+
+struct list_node {
+	struct list_node *prev, *next;
+};
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "num-records", 'r', POPT_ARG_INT, &num_records, 0, "num_records", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	int ret;
+	poptContext pc;
+	struct event_context *ev;
+	double elapsed;
+	int i;
+	trbt_tree_t *tree;
+	struct list_node *list, *list_new, *list_head=NULL;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+
+	printf("testing tree insert for %d records\n", num_records);
+	tree = trbt_create(NULL);
+	start_timer();
+	for (i=0;i<num_records;i++) {
+		trbt_insert32(tree, i, NULL);
+	}
+	elapsed=end_timer();
+	printf("%f seconds\n",(float)elapsed);
+
+
+	printf("testing dlist (worst case) add to tail for %d records\n", num_records);
+	list_new=talloc(NULL, struct list_node);
+	DLIST_ADD(list_head, list_new);
+	start_timer();
+	for (i=0;i<num_records;i++) {
+		for(list=list_head;list->next;list=list->next) {
+			/* the events code does a timeval_compare */
+			timeval_compare(&tp1, &tp2);
+		}
+
+		list_new=talloc(NULL, struct list_node);
+		DLIST_ADD_AFTER(list_head, list_new, list);
+	}
+	elapsed=end_timer();
+	printf("%f seconds\n",(float)elapsed);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/src/rb_test.c
===================================================================
--- branches/ctdb/squeeze-backports/tests/src/rb_test.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/src/rb_test.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,323 @@
+/* 
+   simple rb test tool
+
+   Copyright (C) Ronnie Sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "lib/util/dlinklist.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+
+#include <sys/time.h>
+#include <time.h>
+#include "common/rb_tree.h"
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+int num_records=5;
+
+void *callback(void *p, void *d)
+{
+	uint32_t *data = (uint32_t *)d;
+
+	if (d==NULL) {
+		data = (uint32_t *)p;
+	}
+
+	(*data)++;
+
+	return data;
+}
+
+void *random_add(void *p, void *d)
+{
+	return p;
+}
+
+void traverse(void *p, void *d)
+{
+	uint32_t *data = (uint32_t *)d;
+
+	printf("traverse data:%d\n",*data);
+}
+
+void random_traverse(void *p, void *d)
+{
+	printf("%s   ",(char *)d);
+}
+
+static uint32_t calc_checksum = 0;	
+void traverse_checksum(void *p, void *d)
+{
+	int i,j,k;
+
+	sscanf(d, "%d.%d.%d", &i, &j, &k);
+	calc_checksum += i*100+j*10+k;
+}
+				
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "num-records", 'r', POPT_ARG_INT, &num_records, 0, "num_records", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	poptContext pc;
+	struct event_context *ev;
+	int i,j,k;
+	trbt_tree_t *tree;
+	uint32_t *data;
+	uint32_t key[3];
+	uint32_t key1[3] = {0,10,20};
+	uint32_t key2[3] = {0,10,21};
+	uint32_t key3[3] = {0,11,20};
+	uint32_t key4[3] = {2,10,20};
+	TALLOC_CTX *memctx;
+	uint32_t **u32array;
+	uint32_t checksum;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	ev = event_context_init(NULL);
+
+
+	printf("testing trbt_insert32_callback for %d records\n", num_records);
+	memctx   = talloc_new(NULL);
+	u32array = talloc_array(memctx, uint32_t *, num_records);
+	tree = trbt_create(memctx, 0);
+	for (i=0; i<num_records; i++) {
+		u32array[i]  = talloc(u32array, uint32_t);
+		*u32array[i] = 0;
+		trbt_insert32_callback(tree, i, callback, u32array[i]);
+	}
+	for (i=3; i<num_records; i++) {
+		trbt_insert32_callback(tree, i, callback, NULL);
+	}
+
+	printf("first 3 keys should have data==1\n");
+	printf("the rest of the keys should have data==2\n");
+	for (i=0; i<num_records; i++) {
+		data = trbt_lookup32(tree, i);
+		printf("key:%d data:%d\n", i, *data);
+	}
+//	talloc_report_full(tree, stdout);
+//	talloc_report_full(memctx, stdout);
+//	print_tree(tree);
+
+	printf("deleting key 2\n");
+	talloc_free(u32array[2]);
+//	talloc_report_full(tree, stdout);
+//	talloc_report_full(memctx, stdout);
+//	print_tree(tree);
+
+	printf("deleting key 1\n");
+	talloc_free(u32array[1]);
+//	talloc_report_full(tree, stdout);
+//	talloc_report_full(memctx, stdout);
+//	print_tree(tree);
+
+	printf("freeing tree\n");
+	talloc_report_full(memctx, stdout);
+	talloc_free(memctx);
+
+
+	printf("testing trbt_insertarray32_callback\n");
+	memctx   = talloc_new(NULL);
+	tree = trbt_create(memctx, 0);
+	u32array = talloc_array(memctx, uint32_t *, 4);
+	for (i=0;i<4;i++) {
+		u32array[i]  = talloc(u32array, uint32_t);
+		*u32array[i] = 0;
+	}
+	trbt_insertarray32_callback(tree, 3, key1, callback, u32array[0]);
+	trbt_insertarray32_callback(tree, 3, key1, callback, u32array[0]);
+	trbt_insertarray32_callback(tree, 3, key2, callback, u32array[1]);
+	trbt_insertarray32_callback(tree, 3, key3, callback, u32array[2]);
+	trbt_insertarray32_callback(tree, 3, key2, callback, u32array[1]);
+	trbt_insertarray32_callback(tree, 3, key1, callback, u32array[0]);
+
+	data = trbt_lookuparray32(tree, 3, key1);
+	printf("key1 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key2);
+	printf("key2 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key3);
+	printf("key3 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key4);
+	printf("key4 dataptr:%p == %d\n",data,data?*data:-1);
+	trbt_traversearray32(tree, 3, traverse, NULL);
+
+	printf("\ndeleting key4\n");
+	talloc_free(trbt_lookuparray32(tree, 3, key4));
+	data = trbt_lookuparray32(tree, 3, key1);
+	printf("key1 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key2);
+	printf("key2 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key3);
+	printf("key3 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key4);
+	printf("key4 dataptr:%p == %d\n",data,data?*data:-1);
+	trbt_traversearray32(tree, 3, traverse, NULL);
+
+	printf("\ndeleting key2\n");
+	talloc_free(trbt_lookuparray32(tree, 3, key2));
+	data = trbt_lookuparray32(tree, 3, key1);
+	printf("key1 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key2);
+	printf("key2 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key3);
+	printf("key3 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key4);
+	printf("key4 dataptr:%p == %d\n",data,data?*data:-1);
+	trbt_traversearray32(tree, 3, traverse, NULL);
+	
+	printf("\ndeleting key3\n");
+	talloc_free(trbt_lookuparray32(tree, 3, key3));
+	data = trbt_lookuparray32(tree, 3, key1);
+	printf("key1 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key2);
+	printf("key2 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key3);
+	printf("key3 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key4);
+	printf("key4 dataptr:%p == %d\n",data,data?*data:-1);
+	trbt_traversearray32(tree, 3, traverse, NULL);
+	
+	printf("\ndeleting key1\n");
+	talloc_free(trbt_lookuparray32(tree, 3, key1));
+	data = trbt_lookuparray32(tree, 3, key1);
+	printf("key1 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key2);
+	printf("key2 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key3);
+	printf("key3 dataptr:%p == %d\n",data,data?*data:-1);
+	data = trbt_lookuparray32(tree, 3, key4);
+	printf("key4 dataptr:%p == %d\n",data,data?*data:-1);
+	trbt_traversearray32(tree, 3, traverse, NULL);
+
+	talloc_free(tree);
+	talloc_free(memctx);
+	
+
+	printf("\nrun random insert and delete for 60 seconds\n");
+	memctx   = talloc_new(NULL);
+	tree = trbt_create(memctx, 0);
+	i=0;
+	start_timer();
+	checksum = 0;
+	/* add and delete nodes from a 3 level tree fro 60 seconds.
+	   each time a node is added or deleted, traverse the tree and
+	   compute a checksum over the data stored in the tree and compare this
+	   with a checksum we keep which contains what the checksum should be
+	 */
+	while(end_timer() < 60.0){
+		char *str;
+
+		i++;
+		key[0]=random()%10;
+		key[1]=random()%10;
+		key[2]=random()%10;
+		if (random()%2) {
+			if (trbt_lookuparray32(tree, 3, key) == NULL) {
+				/* this node does not yet exist, add it to the
+				   tree and update the checksum
+				 */
+				str=talloc_asprintf(memctx, "%d.%d.%d", key[0],key[1],key[2]);
+				trbt_insertarray32_callback(tree, 3, key, random_add, str);
+				checksum += key[0]*100+key[1]*10+key[2];
+			}
+		} else {
+			if ((str=trbt_lookuparray32(tree, 3, key)) != NULL) {
+				/* this node does exist in  the tree, delete 
+				   it and update the checksum accordingly
+				 */
+				talloc_free(str);
+				checksum -= key[0]*100+key[1]*10+key[2];
+			}
+		}
+		/* traverse all nodes in the tree and calculate the checksum
+		   it better match the one we keep track of in
+		   'checksum'
+		*/
+		calc_checksum = 0;
+		trbt_traversearray32(tree, 3, traverse_checksum, NULL);
+		if(checksum != calc_checksum) {
+			printf("Wrong checksum  %d!=%d\n",checksum, calc_checksum);
+			exit(10);
+		}
+
+		if(i%1000==999)printf(".");fflush(stdout);
+	}
+	printf("\niterations passed:%d\n", i);
+	trbt_traversearray32(tree, 3, random_traverse, NULL);
+	printf("\n");
+	printf("first node: %s\n", (char *)trbt_findfirstarray32(tree, 3));
+
+
+	printf("\ndeleting all entries\n");
+	for(i=0;i<10;i++){
+	for(j=0;j<10;j++){
+	for(k=0;k<10;k++){
+		key[0]=i;
+		key[1]=j;
+		key[2]=k;
+		talloc_free(trbt_lookuparray32(tree, 3, key));
+	}
+	}
+	}
+	trbt_traversearray32(tree, 3, random_traverse, NULL);
+	printf("\n");
+	talloc_report_full(tree, stdout);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tests/takeover/README
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,6 @@
+This contains a Python simulation of CTDB's IP reallocation algorithm.
+
+It is useful for experimenting with improvements.
+
+To use this on RHEL5 you'll need python2.6 from EPEL
+<http://fedoraproject.org/wiki/EPEL>.

Added: branches/ctdb/squeeze-backports/tests/takeover/common.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/common.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/common.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,70 @@
+# Hey Emacs, this is a -*- shell-script -*- !!!  :-)
+
+# Print a message and exit.
+die () { echo "$@" >&2 ; exit 1 ; }
+
+test_prog="$(dirname ${TAKEOVER_TESTS_DIR})/bin/ctdb_takeover_tests ctdb_takeover_run_core"
+
+define_test ()
+{
+    _f="$0"
+    _f="${_f#./}"  # strip leading ./
+    _f="${_f#testcases/}"  # strip leading testcases/
+    _f="${_f%.sh}" # strip off .sh suffix if any
+
+    case "$_f" in
+	nondet.*)
+	    algorithm="nondet"
+	    CTDB_LCP2="no"
+	    ;;
+	lcp2.*)
+	    algorithm="lcp2"
+	    export CTDB_LCP2="yes"
+	    ;;
+	*)
+	    die "Unknown algorithm for testcase \"$_f\""
+    esac
+
+    printf "%-12s - %s\n" "$_f" "$1"
+}
+
+required_result ()
+{
+    required_rc="${1:-0}"
+    required_output=$(cat)
+}
+
+simple_test ()
+{
+    _states="$1"
+    _out=$($test_prog $_states 2>&1)
+    _rc=$?
+
+    if [ "$algorithm" = "lcp2" -a -n "$CTDB_TEST_LOGLEVEL" ] ; then
+	OUT_FILTER='s@^.*:@DATE TIME \[PID\]:@'
+    fi
+
+    if [ -n "$OUT_FILTER" ] ; then
+	_fout=$(echo "$_out" | sed -r "$OUT_FILTER")
+    else
+	_fout="$_out"
+    fi
+
+    if [ "$_fout" = "$required_output" -a $_rc = $required_rc ] ; then
+	echo "PASSED"
+    else
+	cat <<EOF
+Algorithm: $algorithm
+
+##################################################
+Required output (Exit status: ${required_rc}):
+##################################################
+$required_output
+##################################################
+Actual output (Exit status: ${_rc}):
+##################################################
+$_out
+EOF
+	return 1
+    fi
+}

Added: branches/ctdb/squeeze-backports/tests/takeover/ctdb_takeover.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/ctdb_takeover.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/ctdb_takeover.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,812 @@
+#!/usr/bin/env python
+
+# ctdb ip takeover code
+
+# Copyright (C) Martin Schwenke, Ronnie Sahlberg 2010, 2011
+
+# Based on original CTDB C code:
+#
+# Copyright (C) Ronnie Sahlberg  2007
+# Copyright (C) Andrew Tridgell  2007
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+
+import os
+import sys
+# Use optparse since newer argparse not available in RHEL5/EPEL.
+from optparse import OptionParser
+import copy
+import random
+import itertools
+
+# For parsing IP addresses
+import socket
+import struct
+
+options = None
+
+def process_args(extra_options=[]):
+    global options
+
+    parser = OptionParser(option_list=extra_options)
+
+    parser.add_option("--nd",
+                      action="store_false", dest="deterministic_public_ips",
+                      default=True,
+                      help="turn off deterministic_public_ips")
+    parser.add_option("--ni",
+                      action="store_true", dest="no_ip_failback", default=False,
+                      help="turn on no_ip_failback")
+    parser.add_option("-L", "--lcp2",
+                      action="store_true", dest="lcp2", default=False,
+                      help="use LCP2 IP rebalancing algorithm [default: %default]")
+    parser.add_option("-b", "--balance",
+                      action="store_true", dest="balance", default=False,
+                      help="show (im)balance information after each event")
+    parser.add_option("-d", "--diff",
+                      action="store_true", dest="diff", default=False,
+                      help="show IP address movements for each event")
+    parser.add_option("-n", "--no-print",
+                      action="store_false", dest="show", default=True,
+                      help="don't show IP address layout after each event")
+    parser.add_option("-v", "--verbose",
+                      action="count", dest="verbose", default=0,
+                      help="print information and actions taken to stdout")
+    parser.add_option("-r", "--retries",
+                      action="store", type="int", dest="retries", default=5,
+                      help="number of retry loops for rebalancing non-deterministic failback [default: %default]")
+    parser.add_option("-i", "--iterations",
+                      action="store", type="int", dest="iterations",
+                      default=1000,
+                      help="number of iterations to run in test [default: %default]")
+    parser.add_option("-o", "--odds",
+                      action="store", type="int", dest="odds", default=4,
+                      help="make the chances of a failover 1 in ODDS [default: %default]")
+    parser.add_option("-A", "--aggressive",
+                      action="store_true", dest="aggressive", default=False,
+                      help="apply ODDS to try to flip each node [default: %default]")
+
+    def seed_callback(option, opt, value, parser):
+        random.seed(value)
+    parser.add_option("-s", "--seed",
+                      action="callback", type="int", callback=seed_callback,
+                      help="initial random number seed for random events")
+
+    parser.add_option("-x", "--exit",
+                      action="store_true", dest="exit", default=False,
+                      help="exit on the 1st gratuitous IP move or IP imbalance")
+    parser.add_option("-H", "--hard-imbalance-limit",
+                      action="store", type="int", dest="hard_limit", default=1,
+                      help="exceeding this limit causes termination  [default: %default]")
+    parser.add_option("-S", "--soft-imbalance-limit",
+                      action="store", type="int", dest="soft_limit", default=1,
+                      help="exceeding this limit increments a counter [default: %default]")
+
+    (options, args) = parser.parse_args()
+
+    if len(args) != 0:
+        parser.error("too many argumentss")
+
+def print_begin(t, delim='='):
+    print delim * 40
+    print "%s:" % (t)
+
+def print_end():
+    print "-" * 40
+
+def verbose_begin(t):
+    if options.verbose > 0:
+        print_begin(t)
+
+def verbose_end():
+    if options.verbose > 0:
+        print_end()
+
+def verbose_print(t):
+    if options.verbose > 0:
+        if not type(t) == list:
+            t = [t]
+        if t != []:
+            print "\n".join([str(i) for i in t])
+
+# more than this and we switch to the logging module...  :-)
+def debug_begin(t):
+    if options.verbose > 1:
+        print_begin(t, '-')
+
+def debug_end():
+    if options.verbose > 1:
+        print_end()
+
+def debug_print(t):
+    if options.verbose > 1:
+        if not type(t) == list:
+            t = [t]
+        if t != []:
+            print "\n".join([str(i) for i in t])
+
+def ip_to_list_of_ints(ip):
+    # Be lazy... but only expose errors in IPv4 addresses, since
+    # they'll be more commonly used.  :-)
+    try:
+        l = socket.inet_pton(socket.AF_INET6, ip)
+    except:
+        # Pad with leading 0s.  This makes IPv4 addresses comparable
+        # with IPv6 but reduces the overall effectiveness of the
+        # algorithm.  The alternative would be to treat these
+        # addresses separately while trying to keep all the IPs in
+        # overall balance.
+        l = "".join(itertools.repeat("\0", 12)) + \
+            socket.inet_pton(socket.AF_INET, ip)
+
+    return map(lambda x: struct.unpack('B', x)[0], l)
+
+def ip_distance(ip1, ip2):
+    """Calculate the distance between 2 IPs.
+
+    This is the length of the longtest common prefix between the IPs.
+    It is calculated by XOR-ing the 2 IPs together and counting the
+    number of leading zeroes."""
+
+    distance = 0
+    for (o1, o2) in zip(ip_to_list_of_ints(ip1), ip_to_list_of_ints(ip2)):
+        # XOR this pair of octets
+        x = o1 ^ o2
+        # count number leading zeroes
+        if x == 0:
+            distance += 8
+        else:
+            # bin() gives minimal length '0bNNN' string
+            distance += (8 - (len(bin(x)) - 2))
+            break
+
+    return distance
+
+def ip_distance_2_sum(ip, ips):
+    """Calculate the IP distance for the given IP relative to IPs.
+
+    This could be made more efficient by insering ip_distance_2 into
+    the loop in this function.  However, that would result in some
+    loss of clarity and also will not be necessary in a C
+    implemntation."""
+
+    sum = 0
+    for i in ips:
+        sum += ip_distance(ip, i) ** 2
+
+    return sum
+
+def imbalance_metric(ips):
+    """Return the imbalance metric for a group of IPs.
+
+    This is the sum of squares of the IP distances between each pair of IPs."""
+    if len(ips) > 1:
+        (h, t) = (ips[0], ips[1:])
+        return ip_distance_2_sum(h, t) + imbalance_metric(t)
+    else:
+        return 0
+
+def mean(l):
+    return float(sum(l))/len(l)
+
+class Node(object):
+    def __init__(self, public_addresses):
+        # List of list allows groups of IPs to be passed in.  They're
+        # not actually used in the algorithm but are just used by
+        # calculate_imbalance() for checking the simulation.  Note
+        # that people can pass in garbage and make this code
+        # fail... but we're all friends here in simulation world...
+        # :-)
+        if type(public_addresses[0]) is str:
+            self.public_addresses = set(public_addresses)
+            self.ip_groups = []
+        else:
+            # flatten
+            self.public_addresses = set([i for s in public_addresses for i in s])
+            self.ip_groups = public_addresses
+
+        self.current_addresses = set()
+        self.healthy = True
+        self.imbalance = -1
+
+    def __str__(self):
+        return "%s %s%s" % \
+            ("*" if len(self.public_addresses) == 0 else \
+                 (" " if self.healthy else "#"),
+             sorted(list(self.current_addresses)),
+             " %d" % self.imbalance if options.lcp2 else "")
+
+    def can_node_serve_ip(self, ip):
+        return ip in self.public_addresses
+
+    def node_ip_coverage(self, ips=None):
+        return len([a for a in self.current_addresses if ips == None or a in ips])
+
+    def set_imbalance(self, imbalance=-1):
+        """Set the imbalance metric to the given value.  If none given
+        then calculate it."""
+
+        if imbalance != -1:
+            self.imbalance = imbalance
+        else:
+            self.imbalance = imbalance_metric(list(self.current_addresses))
+
+    def get_imbalance(self):
+        return self.imbalance
+
+class Cluster(object):
+    def __init__(self):
+        self.nodes = []
+        self.deterministic_public_ips = options.deterministic_public_ips
+        self.no_ip_failback = options.no_ip_failback
+        self.all_public_ips = set()
+
+        # Statistics
+        self.ip_moves = []
+        self.grat_ip_moves = []
+        self.imbalance = []
+        self.imbalance_groups = []
+        self.imbalance_count = 0
+        self.imbalance_groups_count = itertools.repeat(0)
+        self.imbalance_metric = []
+        self.events = -1
+        self.num_unhealthy = []
+
+        self.prev = None
+
+    def __str__(self):
+        return "\n".join(["%2d %s" % (i, n) \
+                              for (i, n) in enumerate(self.nodes)])
+
+    # This is naive.  It assumes that IP groups are indicated by the
+    # 1st node having IP groups.
+    def have_ip_groups(self):
+        return (len(self.nodes[0].ip_groups) > 0)
+
+    def print_statistics(self):
+        print_begin("STATISTICS")
+        print "Events:                      %6d" % self.events
+        print "Total IP moves:              %6d" % sum(self.ip_moves)
+        print "Gratuitous IP moves:         %6d" % sum(self.grat_ip_moves)
+        print "Max imbalance:               %6d" % max(self.imbalance)
+        if self.have_ip_groups():
+            print "Max group imbalance counts:    ", map(max, zip(*self.imbalance_groups))
+        print "Mean imbalance:              %f" % mean(self.imbalance)
+        if self.have_ip_groups():
+            print "Mean group imbalances counts:   ", map(mean, zip(*self.imbalance_groups))
+        print "Final imbalance:             %6d" % self.imbalance[-1]
+        if self.have_ip_groups():
+            print "Final group imbalances:         ", self.imbalance_groups[-1]
+        if options.lcp2:
+            print "Max LCP2 imbalance  :        %6d" % max(self.imbalance_metric)
+        print "Soft imbalance count:        %6d" % self.imbalance_count
+        if self.have_ip_groups():
+            print "Soft imbalance group counts:    ", self.imbalance_groups_count
+        if options.lcp2:
+            print "Final LCP2 imbalance  :      %6d" % self.imbalance_metric[-1]
+        print "Maximum unhealthy:           %6d" % max(self.num_unhealthy)
+        print_end()
+
+    def find_pnn_with_ip(self, ip):
+        for (i, n) in enumerate(self.nodes):
+            if ip in n.current_addresses:
+                return i
+        return -1
+
+    def quietly_remove_ip(self, ip):
+        # Remove address from old node.
+        old = self.find_pnn_with_ip(ip)
+        if old != -1:
+            self.nodes[old].current_addresses.remove(ip)
+
+    def add_node(self, node):
+        self.nodes.append(node)
+        self.all_public_ips |= node.public_addresses
+
+    def healthy(self, *pnns):
+        verbose_begin("HEALTHY")
+
+        for pnn in pnns:
+            self.nodes[pnn].healthy = True
+            verbose_print(pnn)
+
+        verbose_end()
+
+    def unhealthy(self, *pnns):
+
+        verbose_begin("UNHEALTHY")
+
+        for pnn in pnns:
+            self.nodes[pnn].healthy = False
+            verbose_print(pnn)
+
+        verbose_end()
+
+    def do_something_random(self):
+
+        """Make random node(s) healthy or unhealthy.
+
+        If options.aggressive is False then: If all nodes are healthy
+        or unhealthy, then invert one of them; otherwise, there's a 1
+        in options.odds chance of making another node unhealthy.
+
+        If options.aggressive is True then: For each node there is a 1
+        in options.odds chance of flipping the state of that node
+        between healthy and unhealthy."""
+
+        if not options.aggressive:
+            num_nodes = len(self.nodes)
+            healthy_pnns = [i for (i,n) in enumerate(self.nodes) if n.healthy]
+            num_healthy = len(healthy_pnns)
+
+            if num_nodes == num_healthy:
+                self.unhealthy(random.randint(0, num_nodes-1))
+            elif num_healthy == 0:
+                self.healthy(random.randint(0, num_nodes-1))
+            elif random.randint(1, options.odds) == 1:
+                self.unhealthy(random.choice(healthy_pnns))
+            else:
+                all_pnns = range(num_nodes)
+                unhealthy_pnns = sorted(list(set(all_pnns) - set(healthy_pnns)))
+                self.healthy(random.choice(unhealthy_pnns))
+        else:
+            # We need to make at least one change or we retry...x
+            changed = False
+            while not changed:
+                for (pnn, n) in enumerate(self.nodes):
+                    if random.randint(1, options.odds) == 1:
+                        changed = True
+                        if n.healthy:
+                            self.unhealthy(pnn)
+                        else:
+                            self.healthy(pnn)
+
+    def random_iterations(self):
+        i = 1
+        while i <= options.iterations:
+            verbose_begin("EVENT %d" % i)
+            verbose_end()
+            self.do_something_random()
+            if self.recover() and options.exit:
+                break
+            i += 1
+
+        self.print_statistics()
+
+    def imbalance_for_ips(self, ips):
+
+        imbalance = 0
+
+        maxnode = -1
+        minnode = -1
+
+        for ip in ips:
+            for (i, n) in enumerate(self.nodes):
+
+                if not n.healthy or not n.can_node_serve_ip(ip):
+                    continue
+
+                num = n.node_ip_coverage(ips)
+
+                if maxnode == -1 or num > maxnum:
+                    maxnode = i
+                    maxnum = num
+
+                if minnode == -1 or num < minnum:
+                    minnode = i
+                    minnum = num
+
+            if maxnode == -1 or minnode == -1:
+                continue
+
+            i = maxnum - minnum
+            #if i < 2:
+            #    i = 0
+            imbalance = max([imbalance, i])
+
+        return imbalance
+
+
+    def calculate_imbalance(self):
+
+        # First, do all the assigned IPs.
+        assigned = sorted([ip
+                           for n in self.nodes
+                           for ip in n.current_addresses])
+
+        i = self.imbalance_for_ips(assigned)
+
+        ig = []
+        # FIXME?  If dealing with IP groups, assume the nodes are all
+        # the same.
+        for ips in self.nodes[0].ip_groups:
+            gi = self.imbalance_for_ips(ips)
+            ig.append(gi)
+
+        return (i, ig)
+
+
+    def diff(self):
+        """Calculate differences in IP assignments between self and prev.
+
+        Gratuitous IP moves (from a healthy node to a healthy node)
+        are prefixed by !!."""
+
+        ip_moves = 0
+        grat_ip_moves = 0
+        details = []
+
+        for (new, n) in enumerate(self.nodes):
+            for ip in n.current_addresses:
+                old = self.prev.find_pnn_with_ip(ip)
+                if old != new:
+                    ip_moves += 1
+                    if old != -1 and \
+                            self.prev.nodes[new].healthy and \
+                            self.nodes[new].healthy and \
+                            self.nodes[old].healthy and \
+                            self.prev.nodes[old].healthy:
+                        prefix = "!!"
+                        grat_ip_moves += 1
+                    else:
+                        prefix = "  "
+                    details.append("%s %s: %d -> %d" %
+                                   (prefix, ip, old, new))
+
+        return (ip_moves, grat_ip_moves, details)
+
+    def find_takeover_node(self, ip):
+
+        pnn = -1
+        min = 0
+        for (i, n) in enumerate(self.nodes):
+            if not n.healthy:
+                continue
+
+            if not n.can_node_serve_ip(ip):
+                continue
+
+            num = n.node_ip_coverage()
+
+            if (pnn == -1):
+                pnn = i
+                min = num
+            else:
+                if num < min:
+                    pnn = i
+                    min = num
+
+        if pnn == -1:
+            verbose_print("Could not find node to take over public address %s" % ip)
+            return False
+
+        self.nodes[pnn].current_addresses.add(ip)
+
+        verbose_print("%s -> %d" % (ip, pnn))
+        return True
+
+    def basic_allocate_unassigned(self):
+
+        assigned = set([ip for n in self.nodes for ip in n.current_addresses])
+        unassigned = sorted(list(self.all_public_ips - assigned))
+
+        for ip in unassigned:
+            self.find_takeover_node(ip)
+
+    def basic_failback(self, retries_l):
+
+        assigned = sorted([ip
+                           for n in self.nodes
+                           for ip in n.current_addresses])
+        for ip in assigned:
+
+            maxnode = -1
+            minnode = -1
+            for (i, n) in enumerate(self.nodes):
+                if not n.healthy:
+                    continue
+
+                if not n.can_node_serve_ip(ip):
+                    continue
+
+                num = n.node_ip_coverage()
+
+                if maxnode == -1:
+                    maxnode = i
+                    maxnum = num
+                else:
+                    if num > maxnum:
+                        maxnode = i
+                        maxnum = num
+                if minnode == -1:
+                    minnode = i
+                    minnum = num
+                else:
+                    if num < minnum:
+                        minnode = i
+                        minnum = num
+
+            if maxnode == -1:
+                print "Could not find maxnode. May not be able to serve ip", ip
+                continue
+
+            #if self.deterministic_public_ips:
+            #    continue
+
+            if maxnum > minnum + 1 and retries_l[0] < options.retries:
+                # Remove the 1st ip from maxnode
+                t = sorted(list(self.nodes[maxnode].current_addresses))
+                realloc = t[0]
+                verbose_print("%s <- %d" % (realloc, maxnode))
+                self.nodes[maxnode].current_addresses.remove(realloc)
+                # Redo the outer loop.
+                retries_l[0] += 1
+                return True
+
+        return False
+
+
+    def lcp2_allocate_unassigned(self):
+
+        # Assign as many unassigned addresses as possible.  Keep
+        # selecting the optimal assignment until we don't manage to
+        # assign anything.
+        assigned = set([ip for n in self.nodes for ip in n.current_addresses])
+        unassigned = sorted(list(self.all_public_ips - assigned))
+
+        should_loop = True
+        while len(unassigned) > 0 and should_loop:
+            should_loop = False
+
+            debug_begin(" CONSIDERING MOVES (UNASSIGNED)")
+
+            minnode = -1
+            mindsum = 0
+            minip = None
+
+            for ip in unassigned:
+                for dstnode in range(len(self.nodes)):
+                    if self.nodes[dstnode].can_node_serve_ip(ip) and \
+                            self.nodes[dstnode].healthy:
+                        dstdsum = ip_distance_2_sum(ip, self.nodes[dstnode].current_addresses)
+                        dstimbl = self.nodes[dstnode].get_imbalance() + dstdsum
+                        debug_print(" %s -> %d [+%d]" % \
+                                        (ip,
+                                         dstnode,
+                                         dstimbl - self.nodes[dstnode].get_imbalance()))
+
+                        if (minnode == -1) or (dstdsum < mindsum):
+                            minnode = dstnode
+                            minimbl = dstimbl
+                            mindsum = dstdsum
+                            minip = ip
+                            should_loop = True
+            debug_end()
+
+            if minnode != -1:
+                self.nodes[minnode].current_addresses.add(minip)
+                self.nodes[minnode].set_imbalance(self.nodes[minnode].get_imbalance() + mindsum)
+                verbose_print("%s -> %d [+%d]" % (minip, minnode, mindsum))
+                unassigned.remove(minip)
+
+        for ip in unassigned:
+            verbose_print("Could not find node to take over public address %s" % ip)
+
+    def lcp2_failback(self, targets):
+
+        # Get the node with the highest imbalance metric.
+        srcnode = -1
+        maximbl = 0
+        for (pnn, n) in enumerate(self.nodes):
+            b = n.get_imbalance()
+            if (srcnode == -1) or (b > maximbl):
+                srcnode = pnn
+                maximbl = b
+
+        # This means that all nodes had 0 or 1 addresses, so can't
+        # be imbalanced.
+        if maximbl == 0:
+            return False
+
+        # We'll need this a few times...
+        ips = self.nodes[srcnode].current_addresses
+
+        # Find an IP and destination node that best reduces imbalance.
+        optimum = None
+        debug_begin(" CONSIDERING MOVES FROM %d [%d]" % (srcnode, maximbl))
+        for ip in ips:
+            # What is this IP address costing the source node?
+            srcdsum = ip_distance_2_sum(ip, ips - set([ip]))
+            srcimbl = maximbl - srcdsum
+
+            # Consider this IP address would cost each potential
+            # destination node.  Destination nodes are limited to
+            # those that are newly healthy, since we don't want to
+            # do gratuitous failover of IPs just to make minor
+            # balance improvements.
+            for dstnode in targets:
+                if self.nodes[dstnode].can_node_serve_ip(ip) and \
+                        self.nodes[dstnode].healthy:
+                    dstdsum = ip_distance_2_sum(ip, self.nodes[dstnode].current_addresses)
+                    dstimbl = self.nodes[dstnode].get_imbalance() + dstdsum
+                    debug_print(" %d [%d] -> %s -> %d [+%d]" % \
+                                    (srcnode,
+                                     srcimbl - self.nodes[srcnode].get_imbalance(),
+                                     ip,
+                                     dstnode,
+                                     dstimbl - self.nodes[dstnode].get_imbalance()))
+
+                    if (dstimbl < maximbl) and (dstdsum < srcdsum):
+                        if optimum is None:
+                            optimum = (ip, srcnode, srcimbl, dstnode, dstimbl)
+                        else:
+                            (x, sn, si, dn, di) = optimum
+                            if (srcimbl + dstimbl) < (si + di):
+                                optimum = (ip, srcnode, srcimbl, dstnode, dstimbl)
+        debug_end()
+
+        if optimum is not None:
+            # We found a move that makes things better...
+            (ip, srcnode, srcimbl, dstnode, dstimbl) = optimum
+            ini_srcimbl = self.nodes[srcnode].get_imbalance()
+            ini_dstimbl = self.nodes[dstnode].get_imbalance()
+
+            self.nodes[srcnode].current_addresses.remove(ip)
+            self.nodes[srcnode].set_imbalance(srcimbl)
+
+            self.nodes[dstnode].current_addresses.add(ip)
+            self.nodes[dstnode].set_imbalance(dstimbl)
+
+            verbose_print("%d [%d] -> %s -> %d [+%d]" % \
+                              (srcnode,
+                               srcimbl - ini_srcimbl,
+                               ip,
+                               dstnode,
+                               dstimbl - ini_dstimbl))
+
+            return True
+
+        return False
+
+
+    def ctdb_takeover_run(self):
+
+        self.events += 1
+
+        # Don't bother with the num_healthy stuff.  It is an
+        # irrelevant detail.
+
+        # We just keep the allocate IPs in the current_addresses field
+        # of the node.  This needs to readable, not efficient!
+
+        if self.deterministic_public_ips:
+            # Remap everything.
+            addr_list = sorted(list(self.all_public_ips))
+            for (i, ip) in enumerate(addr_list):
+                self.quietly_remove_ip(ip)
+                # Add addresses to new node.
+                pnn = i % len(self.nodes)
+                self.nodes[pnn].current_addresses.add(ip)
+                verbose_print("%s -> %d" % (ip, pnn))
+
+        # Remove public addresses from unhealthy nodes.
+        for (pnn, n) in enumerate(self.nodes):
+            if not n.healthy:
+                verbose_print(["%s <- %d" % (ip, pnn)
+                               for ip in n.current_addresses])
+                n.current_addresses = set()
+
+        # If a node can't serve an assigned address then remove it.
+        for n in self.nodes:
+            verbose_print(["%s <- %d" % (ip, pnn)
+                           for ip in n.current_addresses - n.public_addresses])
+            n.current_addresses &= n.public_addresses
+
+        if options.lcp2:
+            newly_healthy = [pnn for (pnn, n) in enumerate(self.nodes)
+                             if len(n.current_addresses) == 0 and n.healthy]
+            for n in self.nodes:
+                n.set_imbalance()
+
+        # We'll only retry the balancing act up to options.retries
+        # times (for the basic non-deterministic algorithm).  This
+        # nonsense gives us a reference on the retries count in
+        # Python.  It will be easier in C.  :-)
+        # For LCP2 we reassignas many IPs from heavily "loaded" nodes
+        # to nodes that are newly healthy, looping until we fail to
+        # reassign an IP.
+        retries_l = [0]
+        should_loop = True
+        while should_loop:
+            should_loop = False
+
+            if options.lcp2:
+                self.lcp2_allocate_unassigned()
+            else:
+                self.basic_allocate_unassigned()
+
+            if self.no_ip_failback or self.deterministic_public_ips:
+                break
+
+            if options.lcp2:
+                if len(newly_healthy) == 0:
+                    break
+                should_loop = self.lcp2_failback(newly_healthy)
+            else:
+                should_loop = self.basic_failback(retries_l)
+
+
+    def recover(self):
+        verbose_begin("TAKEOVER")
+
+        self.ctdb_takeover_run()
+
+        verbose_end()
+
+        grat_ip_moves = 0
+
+        if self.prev is not None:
+            (ip_moves, grat_ip_moves, details) = self.diff()
+            self.ip_moves.append(ip_moves)
+            self.grat_ip_moves.append(grat_ip_moves)
+
+            if options.diff:
+                print_begin("DIFF")
+                print "\n".join(details)
+                print_end()
+
+        (imbalance, imbalance_groups) = self.calculate_imbalance()
+        self.imbalance.append(imbalance)
+        self.imbalance_groups.append(imbalance_groups)
+
+        if imbalance > options.soft_limit:
+            self.imbalance_count += 1
+
+        # There must be a cleaner way...
+        t = []
+        for (c, i) in zip(self.imbalance_groups_count, imbalance_groups):
+            if i > options.soft_limit:
+                t.append(c + i)
+            else:
+                t.append(c)
+        self.imbalance_groups_count = t
+
+        imbalance_metric = max([n.get_imbalance() for n in self.nodes])
+        self.imbalance_metric.append(imbalance_metric)
+        if options.balance:
+            print_begin("IMBALANCE")
+            print "ALL IPS:", imbalance
+            if self.have_ip_groups():
+                print "IP GROUPS:", imbalance_groups
+            if options.lcp2:
+                print "LCP2 IMBALANCE:", imbalance_metric
+            print_end()
+
+        num_unhealthy = len(self.nodes) - \
+            len([n for n in self.nodes if n.healthy])
+        self.num_unhealthy.append(num_unhealthy)
+
+        if options.show:
+            print_begin("STATE")
+            print self
+            print_end()
+
+        self.prev = None
+        self.prev = copy.deepcopy(self)
+
+        # True is bad!
+        return (grat_ip_moves > 0) or \
+            (not self.have_ip_groups() and imbalance > options.hard_limit) or \
+            (self.have_ip_groups() and (max(imbalance_groups) > options.hard_limit))


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/ctdb_takeover.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/ip_groups1.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/ip_groups1.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/ip_groups1.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# 2 IP groups, both on the same 5 nodes, with each group on different
+# interfaces/VLANs.  One group has many more addresses to test how
+# well an "imbalanced" configuration will balance...
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses20 = ['192.168.20.%d' % n for n in range(1, 13)]
+addresses128 = ['192.168.128.%d' % n for n in range(1, 5)]
+
+c = Cluster()
+
+for i in range(5):
+    c.add_node(Node([addresses20, addresses128]))
+
+#for i in range(3):
+#    c.add_node(Node([addresses20]))
+
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/ip_groups1.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/ip_groups2.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/ip_groups2.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/ip_groups2.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# 2 groups of addresses, combined into 1 pool so the checking
+# algorithm doesn't know about the groups, across 2 nodes.
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses20 = ['192.168.20.%d' % n for n in range(1, 13)]
+addresses21 = ['192.168.21.%d' % n for n in range(1, 5)]
+
+c = Cluster()
+
+for i in range(2):
+    c.add_node(Node(addresses20 + addresses21))
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/ip_groups2.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/ip_groups3.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/ip_groups3.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/ip_groups3.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# 4 IP groups, across 10 nodes, with each group on different
+# interfaces/VLANs.  80 addresses in total but not evenly balanced, to
+# help check some of the more extreme behaviour.
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses1 = ['192.168.1.%d' % n for n in range(1, 41)]
+addresses2 = ['192.168.2.%d' % n for n in range(1, 21)]
+addresses3 = ['192.168.3.%d' % n for n in range(1, 11)]
+addresses4 = ['192.168.4.%d' % n for n in range(1, 11)]
+
+# Try detecting imbalance with square root of number of nodes?  Or
+# just with a parameter indicating how unbalanced you're willing to
+# accept...
+
+c = Cluster()
+
+for i in range(10):
+    c.add_node(Node([addresses1, addresses2, addresses3, addresses4]))
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/ip_groups3.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/ip_groups4.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/ip_groups4.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/ip_groups4.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# 2 IP groups, across 2 nodes, with each group on different
+# interfaces.  4 addresses per group.  A nice little canonical 2 node
+# configuration.
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses1 = ['192.168.1.%d' % n for n in range(1, 5)]
+addresses2 = ['192.168.2.%d' % n for n in range(1, 5)]
+
+# Try detecting imbalance with square root of number of nodes?  Or
+# just with a parameter indicating how unbalanced you're willing to
+# accept...
+
+c = Cluster()
+
+for i in range(2):
+    c.add_node(Node([addresses1, addresses2]))
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/ip_groups4.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/ip_groups5.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/ip_groups5.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/ip_groups5.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# 1 IP group, to test backward compatibility of LCP2 algorithm.  16
+# addresses across 4 nodes.
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses1 = ['192.168.1.%d' % n for n in range(1, 17)]
+
+# Try detecting imbalance with square root of number of nodes?  Or
+# just with a parameter indicating how unbalanced you're willing to
+# accept...
+
+c = Cluster()
+
+for i in range(4):
+    c.add_node(Node(addresses1))
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/ip_groups5.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/mgmt_simple.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/mgmt_simple.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/mgmt_simple.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# This is an example showing a current SONAS configuration with 3
+# interface node and a management node.  When run with deterministic
+# IPs there are gratuitous IP reassignments.
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
+
+c = Cluster()
+
+for i in range(3):
+    c.add_node(Node(addresses))
+
+c.add_node(Node([]))
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/mgmt_simple.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/node_group.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/node_group.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/node_group.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# This demonstrates a node group configurations.
+#
+# Node groups can be defined with the syntax "-g N at IP0,IP1-IP2,IP3".
+# This says to create a group of N nodes with IPs IP0, IP1, ..., IP2,
+# IP3.  Run it with deterministic IPs causes lots of gratuitous IP
+# reassignments.  Running with --nd fixes this.
+
+import ctdb_takeover
+import sys
+from optparse import make_option
+import string
+
+ctdb_takeover.process_args([
+        make_option("-g", "--group",
+                    action="append", type="string", dest="groups",
+                    help="define a node group using N at IPs syntax"),
+        ])
+
+def expand_range(r):
+    sr = r.split("-", 1)
+    if len(sr) == 2:
+        all = string.ascii_uppercase + string.ascii_lowercase
+        sr = list(all[all.index(sr[0]):all.index(sr[1])+1])
+    return sr
+            
+def add_node_group(s):
+    (count, ips_str) = s.split("@", 1)
+    ips = [i for r in ips_str.split(",") \
+               for i in expand_range(r) if r != ""]
+    for i in range(int(count)):
+        c.add_node(ctdb_takeover.Node(ips))
+
+c = ctdb_takeover.Cluster()
+
+if ctdb_takeover.options.groups is None:
+    print "Error: no node groups defined."
+    sys.exit(1)
+
+for g in ctdb_takeover.options.groups:
+    add_node_group(g)
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/node_group.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/node_group_extra.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/node_group_extra.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/node_group_extra.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# This example demonstrates a node group configuration.  Is it meant
+# to be the same as node_group_simple.py, but with a couple of nodes
+# added later, so they are listed after the management node.
+
+# When run with deterministic IPs (use "-d" to show the problem) it
+# does many gratuitous IP reassignments.
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses1 = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] + ['P', 'Q', 'R', 'S', 'T', 'U']
+addresses2 = ['I', 'J', 'K', 'L']
+
+c = Cluster()
+
+for i in range(4):
+    c.add_node(Node(addresses1))
+
+for i in range(3):
+    c.add_node(Node(addresses2))
+
+c.add_node(Node([]))
+c.add_node(Node(addresses1))
+c.add_node(Node(addresses2))
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/node_group_extra.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/node_group_simple.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/node_group_simple.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/node_group_simple.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# This example demonstrates a simple, sensible node group
+# configuration.  When run with deterministic IPs (use "-d" to show
+# the problem) it does many gratuitous IP reassignments.
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses1 = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
+addresses2 = ['I', 'J', 'K']
+
+c = Cluster()
+
+for i in range(4):
+    c.add_node(Node(addresses1))
+
+for i in range(3):
+    c.add_node(Node(addresses2))
+
+c.add_node(Node([]))
+
+c.recover()
+
+c.random_iterations()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/node_group_simple.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/nondet_path_01.py
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/nondet_path_01.py	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/nondet_path_01.py	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# This is a contrived example that makes the balancing algorithm fail
+# for nondeterministic IPs (run with "-dv --nd" to see the failure).
+
+from ctdb_takeover import Cluster, Node, process_args
+
+process_args()
+
+addresses1 = ['A', 'B', 'C', 'D']
+addresses2 = ['B', 'E', 'F']
+
+c = Cluster()
+
+for i in range(2):
+    c.add_node(Node(addresses1))
+
+c.add_node(Node(addresses2))
+
+c.recover()
+
+c.unhealthy(1)
+c.recover()
+c.healthy(1)
+c.recover()


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/nondet_path_01.py
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/run_tests.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/run_tests.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/run_tests.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# Run some IP allocation unit tests.
+
+cd $(dirname "$0")
+export TAKEOVER_TESTS_DIR=$(pwd)
+
+test_dir=$(dirname "$TAKEOVER_TESTS_DIR")
+
+opts="-d"
+
+for i ; do
+    case "$i" in
+	-*)
+	    opts="$opts $i"
+	    shift
+	    ;;
+	*)
+	    break
+    esac
+done
+
+tests=""
+if [ -z "$*" ] ; then
+    tests=$(ls testcases/*.[0-9][0-9][0-9].sh 2>/dev/null)
+fi
+
+"$test_dir/scripts/run_tests" $opts "$@" $tests || exit 1
+
+echo "All OK"
+exit 0


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/run_tests.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 3 -> 1 healthy"
+
+export CTDB_TEST_LOGLEVEL=0
+
+required_result <<EOF
+192.168.21.254 2
+192.168.21.253 2
+192.168.21.252 2
+192.168.20.254 2
+192.168.20.253 2
+192.168.20.252 2
+192.168.20.251 2
+192.168.20.250 2
+192.168.20.249 2
+EOF
+
+simple_test 2,2,0 <<EOF
+192.168.20.249 0
+192.168.20.250 1
+192.168.20.251 2
+192.168.20.252 0
+192.168.20.253 1
+192.168.20.254 2
+192.168.21.252 0
+192.168.21.253 1
+192.168.21.254 2
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 3 -> 2 healthy"
+
+export CTDB_TEST_LOGLEVEL=0
+
+required_result <<EOF
+192.168.21.254 2
+192.168.21.253 2
+192.168.21.252 0
+192.168.20.254 2
+192.168.20.253 2
+192.168.20.252 0
+192.168.20.251 2
+192.168.20.250 0
+192.168.20.249 0
+EOF
+
+simple_test 0,2,0 <<EOF
+192.168.20.249 0
+192.168.20.250 1
+192.168.20.251 2
+192.168.20.252 0
+192.168.20.253 1
+192.168.20.254 2
+192.168.21.252 0
+192.168.21.253 1
+192.168.21.254 2
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.003.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.003.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.003.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 1 -> all healthy"
+
+export CTDB_TEST_LOGLEVEL=0
+
+required_result <<EOF
+192.168.21.254 2
+192.168.21.253 0
+192.168.21.252 1
+192.168.20.254 2
+192.168.20.253 0
+192.168.20.252 1
+192.168.20.251 2
+192.168.20.250 0
+192.168.20.249 1
+EOF
+
+simple_test 0,0,0 <<EOF
+192.168.20.249 1
+192.168.20.250 1
+192.168.20.251 1
+192.168.20.252 1
+192.168.20.253 1
+192.168.20.254 1
+192.168.21.252 1
+192.168.21.253 1
+192.168.21.254 1
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.003.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.004.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.004.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.004.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 1 -> all healthy, info logging"
+
+export CTDB_TEST_LOGLEVEL=3
+
+required_result <<EOF
+DATE TIME [PID]: 1 [-121363] -> 192.168.20.253 -> 0 [+0]
+DATE TIME [PID]: 1 [-105738] -> 192.168.20.251 -> 2 [+0]
+DATE TIME [PID]: 1 [-88649] -> 192.168.21.253 -> 0 [+14161]
+DATE TIME [PID]: 1 [-75448] -> 192.168.20.254 -> 2 [+15625]
+DATE TIME [PID]: 1 [-59823] -> 192.168.20.250 -> 0 [+29786]
+DATE TIME [PID]: 1 [-44198] -> 192.168.21.254 -> 2 [+28322]
+192.168.21.254 2
+192.168.21.253 0
+192.168.21.252 1
+192.168.20.254 2
+192.168.20.253 0
+192.168.20.252 1
+192.168.20.251 2
+192.168.20.250 0
+192.168.20.249 1
+EOF
+
+simple_test 0,0,0 <<EOF
+192.168.20.249 1
+192.168.20.250 1
+192.168.20.251 1
+192.168.20.252 1
+192.168.20.253 1
+192.168.20.254 1
+192.168.21.252 1
+192.168.21.253 1
+192.168.21.254 1
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.004.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.005.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.005.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.005.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,163 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 1 -> all healthy, debug logging"
+
+export CTDB_TEST_LOGLEVEL=4
+
+required_result <<EOF
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES (UNASSIGNED)
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES FROM 1 [539166]
+DATE TIME [PID]:  1 [-116718] -> 192.168.21.254 -> 0 [+0]
+DATE TIME [PID]:  1 [-116718] -> 192.168.21.254 -> 2 [+0]
+DATE TIME [PID]:  1 [-116971] -> 192.168.21.253 -> 0 [+0]
+DATE TIME [PID]:  1 [-116971] -> 192.168.21.253 -> 2 [+0]
+DATE TIME [PID]:  1 [-116971] -> 192.168.21.252 -> 0 [+0]
+DATE TIME [PID]:  1 [-116971] -> 192.168.21.252 -> 2 [+0]
+DATE TIME [PID]:  1 [-121110] -> 192.168.20.254 -> 0 [+0]
+DATE TIME [PID]:  1 [-121110] -> 192.168.20.254 -> 2 [+0]
+DATE TIME [PID]:  1 [-121363] -> 192.168.20.253 -> 0 [+0]
+DATE TIME [PID]:  1 [-121363] -> 192.168.20.253 -> 2 [+0]
+DATE TIME [PID]:  1 [-121363] -> 192.168.20.252 -> 0 [+0]
+DATE TIME [PID]:  1 [-121363] -> 192.168.20.252 -> 2 [+0]
+DATE TIME [PID]:  1 [-121363] -> 192.168.20.251 -> 0 [+0]
+DATE TIME [PID]:  1 [-121363] -> 192.168.20.251 -> 2 [+0]
+DATE TIME [PID]:  1 [-121363] -> 192.168.20.250 -> 0 [+0]
+DATE TIME [PID]:  1 [-121363] -> 192.168.20.250 -> 2 [+0]
+DATE TIME [PID]:  1 [-121110] -> 192.168.20.249 -> 0 [+0]
+DATE TIME [PID]:  1 [-121110] -> 192.168.20.249 -> 2 [+0]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]: 1 [-121363] -> 192.168.20.253 -> 0 [+0]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES (UNASSIGNED)
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES FROM 1 [418056]
+DATE TIME [PID]:  1 [-102557] -> 192.168.21.254 -> 0 [+14161]
+DATE TIME [PID]:  1 [-102557] -> 192.168.21.254 -> 2 [+0]
+DATE TIME [PID]:  1 [-102810] -> 192.168.21.253 -> 0 [+14161]
+DATE TIME [PID]:  1 [-102810] -> 192.168.21.253 -> 2 [+0]
+DATE TIME [PID]:  1 [-102810] -> 192.168.21.252 -> 0 [+14161]
+DATE TIME [PID]:  1 [-102810] -> 192.168.21.252 -> 2 [+0]
+DATE TIME [PID]:  1 [-105234] -> 192.168.20.254 -> 0 [+15876]
+DATE TIME [PID]:  1 [-105234] -> 192.168.20.254 -> 2 [+0]
+DATE TIME [PID]:  1 [-105234] -> 192.168.20.252 -> 0 [+16129]
+DATE TIME [PID]:  1 [-105234] -> 192.168.20.252 -> 2 [+0]
+DATE TIME [PID]:  1 [-105738] -> 192.168.20.251 -> 0 [+15625]
+DATE TIME [PID]:  1 [-105738] -> 192.168.20.251 -> 2 [+0]
+DATE TIME [PID]:  1 [-105738] -> 192.168.20.250 -> 0 [+15625]
+DATE TIME [PID]:  1 [-105738] -> 192.168.20.250 -> 2 [+0]
+DATE TIME [PID]:  1 [-105485] -> 192.168.20.249 -> 0 [+15625]
+DATE TIME [PID]:  1 [-105485] -> 192.168.20.249 -> 2 [+0]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]: 1 [-105738] -> 192.168.20.251 -> 2 [+0]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES (UNASSIGNED)
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES FROM 1 [312571]
+DATE TIME [PID]:  1 [-88396] -> 192.168.21.254 -> 0 [+14161]
+DATE TIME [PID]:  1 [-88396] -> 192.168.21.254 -> 2 [+14161]
+DATE TIME [PID]:  1 [-88649] -> 192.168.21.253 -> 0 [+14161]
+DATE TIME [PID]:  1 [-88649] -> 192.168.21.253 -> 2 [+14161]
+DATE TIME [PID]:  1 [-88649] -> 192.168.21.252 -> 0 [+14161]
+DATE TIME [PID]:  1 [-88649] -> 192.168.21.252 -> 2 [+14161]
+DATE TIME [PID]:  1 [-89609] -> 192.168.20.254 -> 0 [+15876]
+DATE TIME [PID]:  1 [-89609] -> 192.168.20.254 -> 2 [+15625]
+DATE TIME [PID]:  1 [-89609] -> 192.168.20.252 -> 0 [+16129]
+DATE TIME [PID]:  1 [-89609] -> 192.168.20.252 -> 2 [+15625]
+DATE TIME [PID]:  1 [-89609] -> 192.168.20.250 -> 0 [+15625]
+DATE TIME [PID]:  1 [-89609] -> 192.168.20.250 -> 2 [+16129]
+DATE TIME [PID]:  1 [-89609] -> 192.168.20.249 -> 0 [+15625]
+DATE TIME [PID]:  1 [-89609] -> 192.168.20.249 -> 2 [+15876]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]: 1 [-88649] -> 192.168.21.253 -> 0 [+14161]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES (UNASSIGNED)
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES FROM 1 [222962]
+DATE TIME [PID]:  1 [-72520] -> 192.168.21.254 -> 0 [+30037]
+DATE TIME [PID]:  1 [-72520] -> 192.168.21.254 -> 2 [+14161]
+DATE TIME [PID]:  1 [-72520] -> 192.168.21.252 -> 0 [+30290]
+DATE TIME [PID]:  1 [-72520] -> 192.168.21.252 -> 2 [+14161]
+DATE TIME [PID]:  1 [-75448] -> 192.168.20.254 -> 0 [+30037]
+DATE TIME [PID]:  1 [-75448] -> 192.168.20.254 -> 2 [+15625]
+DATE TIME [PID]:  1 [-75448] -> 192.168.20.252 -> 0 [+30290]
+DATE TIME [PID]:  1 [-75448] -> 192.168.20.252 -> 2 [+15625]
+DATE TIME [PID]:  1 [-75448] -> 192.168.20.250 -> 0 [+29786]
+DATE TIME [PID]:  1 [-75448] -> 192.168.20.250 -> 2 [+16129]
+DATE TIME [PID]:  1 [-75448] -> 192.168.20.249 -> 0 [+29786]
+DATE TIME [PID]:  1 [-75448] -> 192.168.20.249 -> 2 [+15876]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]: 1 [-75448] -> 192.168.20.254 -> 2 [+15625]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES (UNASSIGNED)
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES FROM 1 [147514]
+DATE TIME [PID]:  1 [-58359] -> 192.168.21.254 -> 0 [+30037]
+DATE TIME [PID]:  1 [-58359] -> 192.168.21.254 -> 2 [+28322]
+DATE TIME [PID]:  1 [-58359] -> 192.168.21.252 -> 0 [+30290]
+DATE TIME [PID]:  1 [-58359] -> 192.168.21.252 -> 2 [+28322]
+DATE TIME [PID]:  1 [-59572] -> 192.168.20.252 -> 0 [+30290]
+DATE TIME [PID]:  1 [-59572] -> 192.168.20.252 -> 2 [+31501]
+DATE TIME [PID]:  1 [-59823] -> 192.168.20.250 -> 0 [+29786]
+DATE TIME [PID]:  1 [-59823] -> 192.168.20.250 -> 2 [+31754]
+DATE TIME [PID]:  1 [-59823] -> 192.168.20.249 -> 0 [+29786]
+DATE TIME [PID]:  1 [-59823] -> 192.168.20.249 -> 2 [+31501]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]: 1 [-59823] -> 192.168.20.250 -> 0 [+29786]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES (UNASSIGNED)
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES FROM 1 [87691]
+DATE TIME [PID]:  1 [-44198] -> 192.168.21.254 -> 0 [+44198]
+DATE TIME [PID]:  1 [-44198] -> 192.168.21.254 -> 2 [+28322]
+DATE TIME [PID]:  1 [-44198] -> 192.168.21.252 -> 0 [+44451]
+DATE TIME [PID]:  1 [-44198] -> 192.168.21.252 -> 2 [+28322]
+DATE TIME [PID]:  1 [-43947] -> 192.168.20.252 -> 0 [+45915]
+DATE TIME [PID]:  1 [-43947] -> 192.168.20.252 -> 2 [+31501]
+DATE TIME [PID]:  1 [-43947] -> 192.168.20.249 -> 0 [+45662]
+DATE TIME [PID]:  1 [-43947] -> 192.168.20.249 -> 2 [+31501]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]: 1 [-44198] -> 192.168.21.254 -> 2 [+28322]
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES (UNASSIGNED)
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  ----------------------------------------
+DATE TIME [PID]:  CONSIDERING MOVES FROM 0 [43947]
+DATE TIME [PID]:  0 [-28322] -> 192.168.21.253 -> 0 [+28322]
+DATE TIME [PID]:  0 [-28322] -> 192.168.21.253 -> 2 [+44198]
+DATE TIME [PID]:  0 [-29786] -> 192.168.20.253 -> 0 [+29786]
+DATE TIME [PID]:  0 [-29786] -> 192.168.20.253 -> 2 [+45662]
+DATE TIME [PID]:  0 [-29786] -> 192.168.20.250 -> 0 [+29786]
+DATE TIME [PID]:  0 [-29786] -> 192.168.20.250 -> 2 [+45915]
+DATE TIME [PID]:  ----------------------------------------
+192.168.21.254 2
+192.168.21.253 0
+192.168.21.252 1
+192.168.20.254 2
+192.168.20.253 0
+192.168.20.252 1
+192.168.20.251 2
+192.168.20.250 0
+192.168.20.249 1
+EOF
+
+simple_test 0,0,0 <<EOF
+192.168.20.249 1
+192.168.20.250 1
+192.168.20.251 1
+192.168.20.252 1
+192.168.20.253 1
+192.168.20.254 1
+192.168.21.252 1
+192.168.21.253 1
+192.168.21.254 1
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.005.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.006.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.006.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.006.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 0 -> 1 healthy"
+
+export CTDB_TEST_LOGLEVEL=0
+
+required_result <<EOF
+192.168.21.254 1
+192.168.21.253 1
+192.168.21.252 1
+192.168.20.254 1
+192.168.20.253 1
+192.168.20.252 1
+192.168.20.251 1
+192.168.20.250 1
+192.168.20.249 1
+EOF
+
+simple_test 2,0,2 <<EOF
+192.168.20.249 -1
+192.168.20.250 -1
+192.168.20.251 -1
+192.168.20.252 -1
+192.168.20.253 -1
+192.168.20.254 -1
+192.168.21.252 -1
+192.168.21.253 -1
+192.168.21.254 -1
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.006.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.007.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.007.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.007.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 0 -> 2 healthy"
+
+export CTDB_TEST_LOGLEVEL=0
+
+required_result <<EOF
+192.168.21.254 1
+192.168.21.253 2
+192.168.21.252 1
+192.168.20.254 1
+192.168.20.253 2
+192.168.20.252 1
+192.168.20.251 1
+192.168.20.250 2
+192.168.20.249 2
+EOF
+
+simple_test 2,0,0 <<EOF
+192.168.20.249 -1
+192.168.20.250 -1
+192.168.20.251 -1
+192.168.20.252 -1
+192.168.20.253 -1
+192.168.20.254 -1
+192.168.21.252 -1
+192.168.21.253 -1
+192.168.21.254 -1
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.007.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.008.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.008.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.008.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 0 -> all healthy"
+
+export CTDB_TEST_LOGLEVEL=0
+
+required_result <<EOF
+192.168.21.254 0
+192.168.21.253 1
+192.168.21.252 2
+192.168.20.254 0
+192.168.20.253 1
+192.168.20.252 2
+192.168.20.251 0
+192.168.20.250 1
+192.168.20.249 2
+EOF
+
+simple_test 0,0,0 <<EOF
+192.168.20.249 -1
+192.168.20.250 -1
+192.168.20.251 -1
+192.168.20.252 -1
+192.168.20.253 -1
+192.168.20.254 -1
+192.168.21.252 -1
+192.168.21.253 -1
+192.168.21.254 -1
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.008.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.009.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.009.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.009.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 3 healthy -> all disconnected"
+
+export CTDB_TEST_LOGLEVEL=0
+
+required_result <<EOF
+192.168.21.254 -1
+192.168.21.253 -1
+192.168.21.252 -1
+192.168.20.254 -1
+192.168.20.253 -1
+192.168.20.252 -1
+192.168.20.251 -1
+192.168.20.250 -1
+192.168.20.249 -1
+EOF
+
+simple_test 1,1,1 <<EOF
+192.168.20.249 0
+192.168.20.250 1
+192.168.20.251 2
+192.168.20.252 0
+192.168.20.253 1
+192.168.20.254 2
+192.168.21.252 0
+192.168.21.253 1
+192.168.21.254 2
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/lcp2.009.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.001.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.001.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.001.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 1 healthy"
+
+required_result <<EOF
+192.168.21.254 2
+192.168.21.253 2
+192.168.21.252 2
+192.168.20.254 2
+192.168.20.253 2
+192.168.20.252 2
+192.168.20.251 2
+192.168.20.250 2
+192.168.20.249 2
+EOF
+
+simple_test 2,2,0 <<EOF
+192.168.20.249 0
+192.168.20.250 1
+192.168.20.251 2
+192.168.20.252 0
+192.168.20.253 1
+192.168.20.254 2
+192.168.21.252 0
+192.168.21.253 1
+192.168.21.254 2
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.001.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.002.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.002.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.002.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 2 healthy"
+
+required_result <<EOF
+192.168.21.254 2
+192.168.21.253 0
+192.168.21.252 0
+192.168.20.254 2
+192.168.20.253 2
+192.168.20.252 0
+192.168.20.251 2
+192.168.20.250 0
+192.168.20.249 0
+EOF
+
+simple_test 0,2,0 <<EOF
+192.168.20.249 0
+192.168.20.250 1
+192.168.20.251 2
+192.168.20.252 0
+192.168.20.253 1
+192.168.20.254 2
+192.168.21.252 0
+192.168.21.253 1
+192.168.21.254 2
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.002.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.003.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.003.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.003.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. "${TAKEOVER_TESTS_DIR}/common.sh"
+
+define_test "3 nodes, 1 -> all healthy"
+
+required_result <<EOF
+192.168.21.254 0
+192.168.21.253 2
+192.168.21.252 0
+192.168.20.254 2
+192.168.20.253 0
+192.168.20.252 2
+192.168.20.251 1
+192.168.20.250 1
+192.168.20.249 1
+EOF
+
+simple_test 0,0,0 <<EOF
+192.168.20.249 1
+192.168.20.250 1
+192.168.20.251 1
+192.168.20.252 1
+192.168.20.253 1
+192.168.20.254 1
+192.168.21.252 1
+192.168.21.253 1
+192.168.21.254 1
+EOF


Property changes on: branches/ctdb/squeeze-backports/tests/takeover/testcases/nondet.003.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tests/test_check_tcp_ports.sh
===================================================================
--- branches/ctdb/squeeze-backports/tests/test_check_tcp_ports.sh	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tests/test_check_tcp_ports.sh	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+DIRNAME=$(dirname $0)
+
+. ${DIRNAME}/../config/functions
+
+SERVICE="test-service"
+
+PORTS="$@"
+
+if [ "x${PORTS}" = "x" ] ; then
+	PORTS=139
+fi
+
+ctdb_check_tcp_ports ${SERVICE} ${PORTS}
+
+echo "Test for service '${SERVICE}' on tcp ports ${PORTS} succeeded!"


Property changes on: branches/ctdb/squeeze-backports/tests/test_check_tcp_ports.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tools/ctdb.c
===================================================================
--- branches/ctdb/squeeze-backports/tools/ctdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tools/ctdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,5286 @@
+/* 
+   ctdb control tool
+
+   Copyright (C) Andrew Tridgell  2007
+   Copyright (C) Ronnie Sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "system/locale.h"
+#include "popt.h"
+#include "cmdline.h"
+#include "../include/ctdb.h"
+#include "../include/ctdb_client.h"
+#include "../include/ctdb_private.h"
+#include "../common/rb_tree.h"
+#include "db_wrap.h"
+
+#define ERR_TIMEOUT	20	/* timed out trying to reach node */
+#define ERR_NONODE	21	/* node does not exist */
+#define ERR_DISNODE	22	/* node is disconnected */
+
+struct ctdb_connection *ctdb_connection;
+
+static void usage(void);
+
+static struct {
+	int timelimit;
+	uint32_t pnn;
+	int machinereadable;
+	int verbose;
+	int maxruntime;
+} options;
+
+#define TIMELIMIT() timeval_current_ofs(options.timelimit, 0)
+#define LONGTIMELIMIT() timeval_current_ofs(options.timelimit*10, 0)
+
+#ifdef CTDB_VERS
+static int control_version(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+#define STR(x) #x
+#define XSTR(x) STR(x)
+	printf("CTDB version: %s\n", XSTR(CTDB_VERS));
+	return 0;
+}
+#endif
+
+
+/*
+  verify that a node exists and is reachable
+ */
+static void verify_node(struct ctdb_context *ctdb)
+{
+	int ret;
+	struct ctdb_node_map *nodemap=NULL;
+
+	if (options.pnn == CTDB_CURRENT_NODE) {
+		return;
+	}
+	if (options.pnn == CTDB_BROADCAST_ALL) {
+		return;
+	}
+
+	/* verify the node exists */
+	if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		exit(10);
+	}
+	if (options.pnn >= nodemap->num) {
+		DEBUG(DEBUG_ERR, ("Node %u does not exist\n", options.pnn));
+		exit(ERR_NONODE);
+	}
+	if (nodemap->nodes[options.pnn].flags & NODE_FLAGS_DELETED) {
+		DEBUG(DEBUG_ERR, ("Node %u is DELETED\n", options.pnn));
+		exit(ERR_DISNODE);
+	}
+	if (nodemap->nodes[options.pnn].flags & NODE_FLAGS_DISCONNECTED) {
+		DEBUG(DEBUG_ERR, ("Node %u is DISCONNECTED\n", options.pnn));
+		exit(ERR_DISNODE);
+	}
+
+	/* verify we can access the node */
+	ret = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), options.pnn);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR,("Can not access node. Node is not operational.\n"));
+		exit(10);
+	}
+}
+
+/*
+ check if a database exists
+*/
+static int db_exists(struct ctdb_context *ctdb, const char *db_name, bool *persistent)
+{
+	int i, ret;
+	struct ctdb_dbid_map *dbmap=NULL;
+
+	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn));
+		return -1;
+	}
+
+	for(i=0;i<dbmap->num;i++){
+		const char *name;
+
+		ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name);
+		if (!strcmp(name, db_name)) {
+			if (persistent) {
+				*persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
+			}
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+/*
+  see if a process exists
+ */
+static int control_process_exists(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t pnn, pid;
+	int ret;
+	if (argc < 1) {
+		usage();
+	}
+
+	if (sscanf(argv[0], "%u:%u", &pnn, &pid) != 2) {
+		DEBUG(DEBUG_ERR, ("Badly formed pnn:pid\n"));
+		return -1;
+	}
+
+	ret = ctdb_ctrl_process_exists(ctdb, pnn, pid);
+	if (ret == 0) {
+		printf("%u:%u exists\n", pnn, pid);
+	} else {
+		printf("%u:%u does not exist\n", pnn, pid);
+	}
+	return ret;
+}
+
+/*
+  display statistics structure
+ */
+static void show_statistics(struct ctdb_statistics *s, int show_header)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	int i;
+	const char *prefix=NULL;
+	int preflen=0;
+	int tmp, days, hours, minutes, seconds;
+	const struct {
+		const char *name;
+		uint32_t offset;
+	} fields[] = {
+#define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
+		STATISTICS_FIELD(num_clients),
+		STATISTICS_FIELD(frozen),
+		STATISTICS_FIELD(recovering),
+		STATISTICS_FIELD(num_recoveries),
+		STATISTICS_FIELD(client_packets_sent),
+		STATISTICS_FIELD(client_packets_recv),
+		STATISTICS_FIELD(node_packets_sent),
+		STATISTICS_FIELD(node_packets_recv),
+		STATISTICS_FIELD(keepalive_packets_sent),
+		STATISTICS_FIELD(keepalive_packets_recv),
+		STATISTICS_FIELD(node.req_call),
+		STATISTICS_FIELD(node.reply_call),
+		STATISTICS_FIELD(node.req_dmaster),
+		STATISTICS_FIELD(node.reply_dmaster),
+		STATISTICS_FIELD(node.reply_error),
+		STATISTICS_FIELD(node.req_message),
+		STATISTICS_FIELD(node.req_control),
+		STATISTICS_FIELD(node.reply_control),
+		STATISTICS_FIELD(client.req_call),
+		STATISTICS_FIELD(client.req_message),
+		STATISTICS_FIELD(client.req_control),
+		STATISTICS_FIELD(timeouts.call),
+		STATISTICS_FIELD(timeouts.control),
+		STATISTICS_FIELD(timeouts.traverse),
+		STATISTICS_FIELD(total_calls),
+		STATISTICS_FIELD(pending_calls),
+		STATISTICS_FIELD(lockwait_calls),
+		STATISTICS_FIELD(pending_lockwait_calls),
+		STATISTICS_FIELD(childwrite_calls),
+		STATISTICS_FIELD(pending_childwrite_calls),
+		STATISTICS_FIELD(memory_used),
+		STATISTICS_FIELD(max_hop_count),
+	};
+	tmp = s->statistics_current_time.tv_sec - s->statistics_start_time.tv_sec;
+	seconds = tmp%60;
+	tmp    /= 60;
+	minutes = tmp%60;
+	tmp    /= 60;
+	hours   = tmp%24;
+	tmp    /= 24;
+	days    = tmp;
+
+	if (options.machinereadable){
+		if (show_header) {
+			printf("CTDB version:");
+			printf("Current time of statistics:");
+			printf("Statistics collected since:");
+			for (i=0;i<ARRAY_SIZE(fields);i++) {
+				printf("%s:", fields[i].name);
+			}
+			printf("num_reclock_ctdbd_latency:");
+			printf("min_reclock_ctdbd_latency:");
+			printf("avg_reclock_ctdbd_latency:");
+			printf("max_reclock_ctdbd_latency:");
+
+			printf("num_reclock_recd_latency:");
+			printf("min_reclock_recd_latency:");
+			printf("avg_reclock_recd_latency:");
+			printf("max_reclock_recd_latency:");
+
+			printf("num_call_latency:");
+			printf("min_call_latency:");
+			printf("avg_call_latency:");
+			printf("max_call_latency:");
+
+			printf("num_lockwait_latency:");
+			printf("min_lockwait_latency:");
+			printf("avg_lockwait_latency:");
+			printf("max_lockwait_latency:");
+
+			printf("num_childwrite_latency:");
+			printf("min_childwrite_latency:");
+			printf("avg_childwrite_latency:");
+			printf("max_childwrite_latency:");
+			printf("\n");
+		}
+		printf("%d:", CTDB_VERSION);
+		printf("%d:", (int)s->statistics_current_time.tv_sec);
+		printf("%d:", (int)s->statistics_start_time.tv_sec);
+		for (i=0;i<ARRAY_SIZE(fields);i++) {
+			printf("%d:", *(uint32_t *)(fields[i].offset+(uint8_t *)s));
+		}
+		printf("%d:", s->reclock.ctdbd.num);
+		printf("%.6f:", s->reclock.ctdbd.min);
+		printf("%.6f:", s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0);
+		printf("%.6f:", s->reclock.ctdbd.max);
+
+		printf("%d:", s->reclock.recd.num);
+		printf("%.6f:", s->reclock.recd.min);
+		printf("%.6f:", s->reclock.recd.num?s->reclock.recd.total/s->reclock.recd.num:0.0);
+		printf("%.6f:", s->reclock.recd.max);
+
+		printf("%d:", s->call_latency.num);
+		printf("%.6f:", s->call_latency.min);
+		printf("%.6f:", s->call_latency.num?s->call_latency.total/s->call_latency.num:0.0);
+		printf("%.6f:", s->call_latency.max);
+
+		printf("%d:", s->lockwait_latency.num);
+		printf("%.6f:", s->lockwait_latency.min);
+		printf("%.6f:", s->lockwait_latency.num?s->lockwait_latency.total/s->lockwait_latency.num:0.0);
+		printf("%.6f:", s->lockwait_latency.max);
+
+		printf("%d:", s->childwrite_latency.num);
+		printf("%.6f:", s->childwrite_latency.min);
+		printf("%.6f:", s->childwrite_latency.num?s->childwrite_latency.total/s->childwrite_latency.num:0.0);
+		printf("%.6f:", s->childwrite_latency.max);
+		printf("\n");
+	} else {
+		printf("CTDB version %u\n", CTDB_VERSION);
+		printf("Current time of statistics  :                %s", ctime(&s->statistics_current_time.tv_sec));
+		printf("Statistics collected since  : (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&s->statistics_start_time.tv_sec));
+
+		for (i=0;i<ARRAY_SIZE(fields);i++) {
+			if (strchr(fields[i].name, '.')) {
+				preflen = strcspn(fields[i].name, ".")+1;
+				if (!prefix || strncmp(prefix, fields[i].name, preflen) != 0) {
+					prefix = fields[i].name;
+					printf(" %*.*s\n", preflen-1, preflen-1, fields[i].name);
+				}
+			} else {
+				preflen = 0;
+			}
+			printf(" %*s%-22s%*s%10u\n", 
+			       preflen?4:0, "",
+			       fields[i].name+preflen, 
+			       preflen?0:4, "",
+			       *(uint32_t *)(fields[i].offset+(uint8_t *)s));
+		}
+		printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "reclock_ctdbd       MIN/AVG/MAX", s->reclock.ctdbd.min, s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0, s->reclock.ctdbd.max, s->reclock.ctdbd.num);
+
+		printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "reclock_recd       MIN/AVG/MAX", s->reclock.recd.min, s->reclock.recd.num?s->reclock.recd.total/s->reclock.recd.num:0.0, s->reclock.recd.max, s->reclock.recd.num);
+
+		printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "call_latency       MIN/AVG/MAX", s->call_latency.min, s->call_latency.num?s->call_latency.total/s->call_latency.num:0.0, s->call_latency.max, s->call_latency.num);
+		printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "lockwait_latency   MIN/AVG/MAX", s->lockwait_latency.min, s->lockwait_latency.num?s->lockwait_latency.total/s->lockwait_latency.num:0.0, s->lockwait_latency.max, s->lockwait_latency.num);
+		printf(" %-30s     %.6f/%.6f/%.6f sec out of %d\n", "childwrite_latency MIN/AVG/MAX", s->childwrite_latency.min, s->childwrite_latency.num?s->childwrite_latency.total/s->childwrite_latency.num:0.0, s->childwrite_latency.max, s->childwrite_latency.num);
+	}
+
+	talloc_free(tmp_ctx);
+}
+
+/*
+  display remote ctdb statistics combined from all nodes
+ */
+static int control_statistics_all(struct ctdb_context *ctdb)
+{
+	int ret, i;
+	struct ctdb_statistics statistics;
+	uint32_t *nodes;
+	uint32_t num_nodes;
+
+	nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
+	CTDB_NO_MEMORY(ctdb, nodes);
+	
+	ZERO_STRUCT(statistics);
+
+	for (i=0;i<num_nodes;i++) {
+		struct ctdb_statistics s1;
+		int j;
+		uint32_t *v1 = (uint32_t *)&s1;
+		uint32_t *v2 = (uint32_t *)&statistics;
+		uint32_t num_ints = 
+			offsetof(struct ctdb_statistics, __last_counter) / sizeof(uint32_t);
+		ret = ctdb_ctrl_statistics(ctdb, nodes[i], &s1);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get statistics from node %u\n", nodes[i]));
+			return ret;
+		}
+		for (j=0;j<num_ints;j++) {
+			v2[j] += v1[j];
+		}
+		statistics.max_hop_count = 
+			MAX(statistics.max_hop_count, s1.max_hop_count);
+		statistics.call_latency.max = 
+			MAX(statistics.call_latency.max, s1.call_latency.max);
+		statistics.lockwait_latency.max = 
+			MAX(statistics.lockwait_latency.max, s1.lockwait_latency.max);
+	}
+	talloc_free(nodes);
+	printf("Gathered statistics for %u nodes\n", num_nodes);
+	show_statistics(&statistics, 1);
+	return 0;
+}
+
+/*
+  display remote ctdb statistics
+ */
+static int control_statistics(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_statistics statistics;
+
+	if (options.pnn == CTDB_BROADCAST_ALL) {
+		return control_statistics_all(ctdb);
+	}
+
+	ret = ctdb_ctrl_statistics(ctdb, options.pnn, &statistics);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get statistics from node %u\n", options.pnn));
+		return ret;
+	}
+	show_statistics(&statistics, 1);
+	return 0;
+}
+
+
+/*
+  reset remote ctdb statistics
+ */
+static int control_statistics_reset(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+
+	ret = ctdb_statistics_reset(ctdb, options.pnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to reset statistics on node %u\n", options.pnn));
+		return ret;
+	}
+	return 0;
+}
+
+
+/*
+  display remote ctdb rolling statistics
+ */
+static int control_stats(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_statistics_wire *stats;
+	int i, num_records = -1;
+
+	if (argc ==1) {
+		num_records = atoi(argv[0]) - 1;
+	}
+
+	ret = ctdb_ctrl_getstathistory(ctdb, TIMELIMIT(), options.pnn, ctdb, &stats);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get rolling statistics from node %u\n", options.pnn));
+		return ret;
+	}
+	for (i=0;i<stats->num;i++) {
+		if (stats->stats[i].statistics_start_time.tv_sec == 0) {
+			continue;
+		}
+		show_statistics(&stats->stats[i], i==0);
+		if (i == num_records) {
+			break;
+		}
+	}
+	return 0;
+}
+
+
+/*
+  display uptime of remote node
+ */
+static int control_uptime(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_uptime *uptime = NULL;
+	int tmp, days, hours, minutes, seconds;
+
+	ret = ctdb_ctrl_uptime(ctdb, ctdb, TIMELIMIT(), options.pnn, &uptime);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get uptime from node %u\n", options.pnn));
+		return ret;
+	}
+
+	if (options.machinereadable){
+		printf(":Current Node Time:Ctdb Start Time:Last Recovery/Failover Time:Last Recovery/IPFailover Duration:\n");
+		printf(":%u:%u:%u:%lf\n",
+			(unsigned int)uptime->current_time.tv_sec,
+			(unsigned int)uptime->ctdbd_start_time.tv_sec,
+			(unsigned int)uptime->last_recovery_finished.tv_sec,
+			timeval_delta(&uptime->last_recovery_finished,
+				      &uptime->last_recovery_started)
+		);
+		return 0;
+	}
+
+	printf("Current time of node          :                %s", ctime(&uptime->current_time.tv_sec));
+
+	tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
+	seconds = tmp%60;
+	tmp    /= 60;
+	minutes = tmp%60;
+	tmp    /= 60;
+	hours   = tmp%24;
+	tmp    /= 24;
+	days    = tmp;
+	printf("Ctdbd start time              : (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&uptime->ctdbd_start_time.tv_sec));
+
+	tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
+	seconds = tmp%60;
+	tmp    /= 60;
+	minutes = tmp%60;
+	tmp    /= 60;
+	hours   = tmp%24;
+	tmp    /= 24;
+	days    = tmp;
+	printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&uptime->last_recovery_finished.tv_sec));
+	
+	printf("Duration of last recovery/failover: %lf seconds\n",
+		timeval_delta(&uptime->last_recovery_finished,
+			      &uptime->last_recovery_started));
+
+	return 0;
+}
+
+/*
+  show the PNN of the current node
+ */
+static int control_pnn(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t mypnn;
+	bool ret;
+
+	ret = ctdb_getpnn(ctdb_connection, options.pnn, &mypnn);
+	if (!ret) {
+		DEBUG(DEBUG_ERR, ("Unable to get pnn from node."));
+		return -1;
+	}
+
+	printf("PNN:%d\n", mypnn);
+	return 0;
+}
+
+
+struct pnn_node {
+	struct pnn_node *next;
+	const char *addr;
+	int pnn;
+};
+
+static struct pnn_node *read_nodes_file(TALLOC_CTX *mem_ctx)
+{
+	const char *nodes_list;
+	int nlines;
+	char **lines;
+	int i, pnn;
+	struct pnn_node *pnn_nodes = NULL;
+	struct pnn_node *pnn_node;
+	struct pnn_node *tmp_node;
+
+	/* read the nodes file */
+	nodes_list = getenv("CTDB_NODES");
+	if (nodes_list == NULL) {
+		nodes_list = "/etc/ctdb/nodes";
+	}
+	lines = file_lines_load(nodes_list, &nlines, mem_ctx);
+	if (lines == NULL) {
+		return NULL;
+	}
+	while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
+		nlines--;
+	}
+	for (i=0, pnn=0; i<nlines; i++) {
+		char *node;
+
+		node = lines[i];
+		/* strip leading spaces */
+		while((*node == ' ') || (*node == '\t')) {
+			node++;
+		}
+		if (*node == '#') {
+			pnn++;
+			continue;
+		}
+		if (strcmp(node, "") == 0) {
+			continue;
+		}
+		pnn_node = talloc(mem_ctx, struct pnn_node);
+		pnn_node->pnn = pnn++;
+		pnn_node->addr = talloc_strdup(pnn_node, node);
+		pnn_node->next = pnn_nodes;
+		pnn_nodes = pnn_node;
+	}
+
+	/* swap them around so we return them in incrementing order */
+	pnn_node = pnn_nodes;
+	pnn_nodes = NULL;
+	while (pnn_node) {
+		tmp_node = pnn_node;
+		pnn_node = pnn_node->next;
+
+		tmp_node->next = pnn_nodes;
+		pnn_nodes = tmp_node;
+	}
+
+	return pnn_nodes;
+}
+
+/*
+  show the PNN of the current node
+  discover the pnn by loading the nodes file and try to bind to all
+  addresses one at a time until the ip address is found.
+ */
+static int control_xpnn(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	struct pnn_node *pnn_nodes;
+	struct pnn_node *pnn_node;
+
+	pnn_nodes = read_nodes_file(mem_ctx);
+	if (pnn_nodes == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to read nodes file\n"));
+		talloc_free(mem_ctx);
+		return -1;
+	}
+
+	for(pnn_node=pnn_nodes;pnn_node;pnn_node=pnn_node->next) {
+		ctdb_sock_addr addr;
+
+		if (parse_ip(pnn_node->addr, NULL, 63999, &addr) == 0) {
+			DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s' in nodes file\n", pnn_node->addr));
+			talloc_free(mem_ctx);
+			return -1;
+		}
+
+		if (ctdb_sys_have_ip(&addr)) {
+			printf("PNN:%d\n", pnn_node->pnn);
+			talloc_free(mem_ctx);
+			return 0;
+		}
+	}
+
+	printf("Failed to detect which PNN this node is\n");
+	talloc_free(mem_ctx);
+	return -1;
+}
+
+/*
+  display remote ctdb status
+ */
+static int control_status(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	struct ctdb_vnn_map *vnnmap=NULL;
+	struct ctdb_node_map *nodemap=NULL;
+	uint32_t recmode, recmaster;
+	int mypnn;
+
+	mypnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), options.pnn);
+	if (mypnn == -1) {
+		return -1;
+	}
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+		return ret;
+	}
+
+	if (options.machinereadable) {
+		printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
+		       ":Inactive:PartiallyOnline:ThisNode:\n");
+		for (i=0;i<nodemap->num;i++) {
+			int partially_online = 0;
+			int j;
+
+			if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+				continue;
+			}
+			if (nodemap->nodes[i].flags == 0) {
+				struct ctdb_control_get_ifaces *ifaces;
+
+				ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(),
+							   nodemap->nodes[i].pnn,
+							   ctdb, &ifaces);
+				if (ret == 0) {
+					for (j=0; j < ifaces->num; j++) {
+						if (ifaces->ifaces[j].link_state != 0) {
+							continue;
+						}
+						partially_online = 1;
+						break;
+					}
+					talloc_free(ifaces);
+				}
+			}
+			printf(":%d:%s:%d:%d:%d:%d:%d:%d:%d:%c:\n", nodemap->nodes[i].pnn,
+				ctdb_addr_to_str(&nodemap->nodes[i].addr),
+			       !!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED),
+			       !!(nodemap->nodes[i].flags&NODE_FLAGS_BANNED),
+			       !!(nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED),
+			       !!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY),
+			       !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED),
+			       !!(nodemap->nodes[i].flags&NODE_FLAGS_INACTIVE),
+			       partially_online,
+			       (nodemap->nodes[i].pnn == mypnn)?'Y':'N');
+		}
+		return 0;
+	}
+
+	printf("Number of nodes:%d\n", nodemap->num);
+	for(i=0;i<nodemap->num;i++){
+		static const struct {
+			uint32_t flag;
+			const char *name;
+		} flag_names[] = {
+			{ NODE_FLAGS_DISCONNECTED,          "DISCONNECTED" },
+			{ NODE_FLAGS_PERMANENTLY_DISABLED,  "DISABLED" },
+			{ NODE_FLAGS_BANNED,                "BANNED" },
+			{ NODE_FLAGS_UNHEALTHY,             "UNHEALTHY" },
+			{ NODE_FLAGS_DELETED,               "DELETED" },
+			{ NODE_FLAGS_STOPPED,               "STOPPED" },
+			{ NODE_FLAGS_INACTIVE,              "INACTIVE" },
+		};
+		char *flags_str = NULL;
+		int j;
+
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		if (nodemap->nodes[i].flags == 0) {
+			struct ctdb_control_get_ifaces *ifaces;
+
+			ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(),
+						   nodemap->nodes[i].pnn,
+						   ctdb, &ifaces);
+			if (ret == 0) {
+				for (j=0; j < ifaces->num; j++) {
+					if (ifaces->ifaces[j].link_state != 0) {
+						continue;
+					}
+					flags_str = talloc_strdup(ctdb, "PARTIALLYONLINE");
+					break;
+				}
+				talloc_free(ifaces);
+			}
+		}
+		for (j=0;j<ARRAY_SIZE(flag_names);j++) {
+			if (nodemap->nodes[i].flags & flag_names[j].flag) {
+				if (flags_str == NULL) {
+					flags_str = talloc_strdup(ctdb, flag_names[j].name);
+				} else {
+					flags_str = talloc_asprintf_append(flags_str, "|%s",
+									   flag_names[j].name);
+				}
+				CTDB_NO_MEMORY_FATAL(ctdb, flags_str);
+			}
+		}
+		if (flags_str == NULL) {
+			flags_str = talloc_strdup(ctdb, "OK");
+			CTDB_NO_MEMORY_FATAL(ctdb, flags_str);
+		}
+		printf("pnn:%d %-16s %s%s\n", nodemap->nodes[i].pnn,
+		       ctdb_addr_to_str(&nodemap->nodes[i].addr),
+		       flags_str,
+		       nodemap->nodes[i].pnn == mypnn?" (THIS NODE)":"");
+		talloc_free(flags_str);
+	}
+
+	ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &vnnmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n", options.pnn));
+		return ret;
+	}
+	if (vnnmap->generation == INVALID_GENERATION) {
+		printf("Generation:INVALID\n");
+	} else {
+		printf("Generation:%d\n",vnnmap->generation);
+	}
+	printf("Size:%d\n",vnnmap->size);
+	for(i=0;i<vnnmap->size;i++){
+		printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
+	}
+
+	if (!ctdb_getrecmode(ctdb_connection, options.pnn, &recmode)) {
+		DEBUG(DEBUG_ERR, ("Unable to get recmode from node %u\n", options.pnn));
+		return -1;
+	}
+	printf("Recovery mode:%s (%d)\n",recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"RECOVERY",recmode);
+
+	if (!ctdb_getrecmaster(ctdb_connection, options.pnn, &recmaster)) {
+		DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
+		return -1;
+	}
+	printf("Recovery master:%d\n",recmaster);
+
+	return 0;
+}
+
+
+struct natgw_node {
+	struct natgw_node *next;
+	const char *addr;
+};
+
+/*
+  display the list of nodes belonging to this natgw configuration
+ */
+static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	uint32_t capabilities;
+	const char *natgw_list;
+	int nlines;
+	char **lines;
+	struct natgw_node *natgw_nodes = NULL;
+	struct natgw_node *natgw_node;
+	struct ctdb_node_map *nodemap=NULL;
+
+
+	/* read the natgw nodes file into a linked list */
+	natgw_list = getenv("NATGW_NODES");
+	if (natgw_list == NULL) {
+		natgw_list = "/etc/ctdb/natgw_nodes";
+	}
+	lines = file_lines_load(natgw_list, &nlines, ctdb);
+	if (lines == NULL) {
+		ctdb_set_error(ctdb, "Failed to load natgw node list '%s'\n", natgw_list);
+		return -1;
+	}
+	while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
+		nlines--;
+	}
+	for (i=0;i<nlines;i++) {
+		char *node;
+
+		node = lines[i];
+		/* strip leading spaces */
+		while((*node == ' ') || (*node == '\t')) {
+			node++;
+		}
+		if (*node == '#') {
+			continue;
+		}
+		if (strcmp(node, "") == 0) {
+			continue;
+		}
+		natgw_node = talloc(ctdb, struct natgw_node);
+		natgw_node->addr = talloc_strdup(natgw_node, node);
+		CTDB_NO_MEMORY(ctdb, natgw_node->addr);
+		natgw_node->next = natgw_nodes;
+		natgw_nodes = natgw_node;
+	}
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node.\n"));
+		return ret;
+	}
+
+	i=0;
+	while(i<nodemap->num) {
+		for(natgw_node=natgw_nodes;natgw_node;natgw_node=natgw_node->next) {
+			if (!strcmp(natgw_node->addr, ctdb_addr_to_str(&nodemap->nodes[i].addr))) {
+				break;
+			}
+		}
+
+		/* this node was not in the natgw so we just remove it from
+		 * the list
+		 */
+		if ((natgw_node == NULL) 
+		||  (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) ) {
+			int j;
+
+			for (j=i+1; j<nodemap->num; j++) {
+				nodemap->nodes[j-1] = nodemap->nodes[j];
+			}
+			nodemap->num--;
+			continue;
+		}
+
+		i++;
+	}		
+
+	/* pick a node to be natgwmaster
+	 * we dont allow STOPPED, DELETED, BANNED or UNHEALTHY nodes to become the natgwmaster
+	 */
+	for(i=0;i<nodemap->num;i++){
+		if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_UNHEALTHY))) {
+			ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
+				return ret;
+			}
+			if (!(capabilities&CTDB_CAP_NATGW)) {
+				continue;
+			}
+			printf("%d %s\n", nodemap->nodes[i].pnn,ctdb_addr_to_str(&nodemap->nodes[i].addr));
+			break;
+		}
+	}
+	/* we couldnt find any healthy node, try unhealthy ones */
+	if (i == nodemap->num) {
+		for(i=0;i<nodemap->num;i++){
+			if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED))) {
+				ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
+				if (ret != 0) {
+					DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
+					return ret;
+				}
+				if (!(capabilities&CTDB_CAP_NATGW)) {
+					continue;
+				}
+				printf("%d %s\n", nodemap->nodes[i].pnn,ctdb_addr_to_str(&nodemap->nodes[i].addr));
+				break;
+			}
+		}
+	}
+	/* unless all nodes are STOPPED, when we pick one anyway */
+	if (i == nodemap->num) {
+		for(i=0;i<nodemap->num;i++){
+			if (!(nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED))) {
+				ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities);
+				if (ret != 0) {
+					DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
+					return ret;
+				}
+				if (!(capabilities&CTDB_CAP_NATGW)) {
+					continue;
+				}
+				printf("%d %s\n", nodemap->nodes[i].pnn, ctdb_addr_to_str(&nodemap->nodes[i].addr));
+				break;
+			}
+		}
+		/* or if we still can not find any */
+		if (i == nodemap->num) {
+			printf("-1 0.0.0.0\n");
+			ret = 2; /* matches ENOENT */
+		}
+	}
+
+	/* print the pruned list of nodes belonging to this natgw list */
+	for(i=0;i<nodemap->num;i++){
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		printf(":%d:%s:%d:%d:%d:%d:%d\n", nodemap->nodes[i].pnn,
+			ctdb_addr_to_str(&nodemap->nodes[i].addr),
+		       !!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED),
+		       !!(nodemap->nodes[i].flags&NODE_FLAGS_BANNED),
+		       !!(nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED),
+		       !!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY),
+		       !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED));
+	}
+
+	return ret;
+}
+
+/*
+  display the status of the scripts for monitoring (or other events)
+ */
+static int control_one_scriptstatus(struct ctdb_context *ctdb,
+				    enum ctdb_eventscript_call type)
+{
+	struct ctdb_scripts_wire *script_status;
+	int ret, i;
+
+	ret = ctdb_ctrl_getscriptstatus(ctdb, TIMELIMIT(), options.pnn, ctdb, type, &script_status);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get script status from node %u\n", options.pnn));
+		return ret;
+	}
+
+	if (script_status == NULL) {
+		if (!options.machinereadable) {
+			printf("%s cycle never run\n",
+			       ctdb_eventscript_call_names[type]);
+		}
+		return 0;
+	}
+
+	if (!options.machinereadable) {
+		printf("%d scripts were executed last %s cycle\n",
+		       script_status->num_scripts,
+		       ctdb_eventscript_call_names[type]);
+	}
+	for (i=0; i<script_status->num_scripts; i++) {
+		const char *status = NULL;
+
+		switch (script_status->scripts[i].status) {
+		case -ETIME:
+			status = "TIMEDOUT";
+			break;
+		case -ENOEXEC:
+			status = "DISABLED";
+			break;
+		case 0:
+			status = "OK";
+			break;
+		default:
+			if (script_status->scripts[i].status > 0)
+				status = "ERROR";
+			break;
+		}
+		if (options.machinereadable) {
+			printf(":%s:%s:%i:%s:%lu.%06lu:%lu.%06lu:%s:\n",
+			       ctdb_eventscript_call_names[type],
+			       script_status->scripts[i].name,
+			       script_status->scripts[i].status,
+			       status,
+			       (long)script_status->scripts[i].start.tv_sec,
+			       (long)script_status->scripts[i].start.tv_usec,
+			       (long)script_status->scripts[i].finished.tv_sec,
+			       (long)script_status->scripts[i].finished.tv_usec,
+			       script_status->scripts[i].output);
+			continue;
+		}
+		if (status)
+			printf("%-20s Status:%s    ",
+			       script_status->scripts[i].name, status);
+		else
+			/* Some other error, eg from stat. */
+			printf("%-20s Status:CANNOT RUN (%s)",
+			       script_status->scripts[i].name,
+			       strerror(-script_status->scripts[i].status));
+
+		if (script_status->scripts[i].status >= 0) {
+			printf("Duration:%.3lf ",
+			timeval_delta(&script_status->scripts[i].finished,
+			      &script_status->scripts[i].start));
+		}
+		if (script_status->scripts[i].status != -ENOEXEC) {
+			printf("%s",
+			       ctime(&script_status->scripts[i].start.tv_sec));
+			if (script_status->scripts[i].status != 0) {
+				printf("   OUTPUT:%s\n",
+				       script_status->scripts[i].output);
+			}
+		} else {
+			printf("\n");
+		}
+	}
+	return 0;
+}
+
+
+static int control_scriptstatus(struct ctdb_context *ctdb,
+				int argc, const char **argv)
+{
+	int ret;
+	enum ctdb_eventscript_call type, min, max;
+	const char *arg;
+
+	if (argc > 1) {
+		DEBUG(DEBUG_ERR, ("Unknown arguments to scriptstatus\n"));
+		return -1;
+	}
+
+	if (argc == 0)
+		arg = ctdb_eventscript_call_names[CTDB_EVENT_MONITOR];
+	else
+		arg = argv[0];
+
+	for (type = 0; type < CTDB_EVENT_MAX; type++) {
+		if (strcmp(arg, ctdb_eventscript_call_names[type]) == 0) {
+			min = type;
+			max = type+1;
+			break;
+		}
+	}
+	if (type == CTDB_EVENT_MAX) {
+		if (strcmp(arg, "all") == 0) {
+			min = 0;
+			max = CTDB_EVENT_MAX;
+		} else {
+			DEBUG(DEBUG_ERR, ("Unknown event type %s\n", argv[0]));
+			return -1;
+		}
+	}
+
+	if (options.machinereadable) {
+		printf(":Type:Name:Code:Status:Start:End:Error Output...:\n");
+	}
+
+	for (type = min; type < max; type++) {
+		ret = control_one_scriptstatus(ctdb, type);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/*
+  enable an eventscript
+ */
+static int control_enablescript(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	ret = ctdb_ctrl_enablescript(ctdb, TIMELIMIT(), options.pnn, argv[0]);
+	if (ret != 0) {
+	  DEBUG(DEBUG_ERR, ("Unable to enable script %s on node %u\n", argv[0], options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  disable an eventscript
+ */
+static int control_disablescript(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	ret = ctdb_ctrl_disablescript(ctdb, TIMELIMIT(), options.pnn, argv[0]);
+	if (ret != 0) {
+	  DEBUG(DEBUG_ERR, ("Unable to disable script %s on node %u\n", argv[0], options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  display the pnn of the recovery master
+ */
+static int control_recmaster(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t recmaster;
+
+	if (!ctdb_getrecmaster(ctdb_connection, options.pnn, &recmaster)) {
+		DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
+		return -1;
+	}
+	printf("%d\n",recmaster);
+
+	return 0;
+}
+
+/*
+  add a tickle to a public address
+ */
+static int control_add_tickle(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	struct ctdb_tcp_connection t;
+	TDB_DATA data;
+	int ret;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	if (parse_ip_port(argv[0], &t.src_addr) == 0) {
+		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
+		return -1;
+	}
+	if (parse_ip_port(argv[1], &t.dst_addr) == 0) {
+		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[1]));
+		return -1;
+	}
+
+	data.dptr = (uint8_t *)&t;
+	data.dsize = sizeof(t);
+
+	/* tell all nodes about this tcp connection */
+	ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE,
+			   0, data, ctdb, NULL, NULL, NULL, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to add tickle\n"));
+		return -1;
+	}
+	
+	return 0;
+}
+
+
+/*
+  delete a tickle from a node
+ */
+static int control_del_tickle(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	struct ctdb_tcp_connection t;
+	TDB_DATA data;
+	int ret;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	if (parse_ip_port(argv[0], &t.src_addr) == 0) {
+		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
+		return -1;
+	}
+	if (parse_ip_port(argv[1], &t.dst_addr) == 0) {
+		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[1]));
+		return -1;
+	}
+
+	data.dptr = (uint8_t *)&t;
+	data.dsize = sizeof(t);
+
+	/* tell all nodes about this tcp connection */
+	ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_TCP_REMOVE,
+			   0, data, ctdb, NULL, NULL, NULL, NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to remove tickle\n"));
+		return -1;
+	}
+	
+	return 0;
+}
+
+
+/*
+  get a list of all tickles for this pnn
+ */
+static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	struct ctdb_control_tcp_tickle_list *list;
+	ctdb_sock_addr addr;
+	int i, ret;
+	unsigned port = 0;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	if (argc == 2) {
+		port = atoi(argv[1]);
+	}
+
+	if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
+		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
+		return -1;
+	}
+
+	ret = ctdb_ctrl_get_tcp_tickles(ctdb, TIMELIMIT(), options.pnn, ctdb, &addr, &list);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR, ("Unable to list tickles\n"));
+		return -1;
+	}
+
+	if (options.machinereadable){
+		printf(":source ip:port:destination ip:port:\n");
+		for (i=0;i<list->tickles.num;i++) {
+			if (port && port != ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)) {
+				continue;
+			}
+			printf(":%s:%u", ctdb_addr_to_str(&list->tickles.connections[i].src_addr), ntohs(list->tickles.connections[i].src_addr.ip.sin_port));
+			printf(":%s:%u:\n", ctdb_addr_to_str(&list->tickles.connections[i].dst_addr), ntohs(list->tickles.connections[i].dst_addr.ip.sin_port));
+		}
+	} else {
+		printf("Tickles for ip:%s\n", ctdb_addr_to_str(&list->addr));
+		printf("Num tickles:%u\n", list->tickles.num);
+		for (i=0;i<list->tickles.num;i++) {
+			if (port && port != ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)) {
+				continue;
+			}
+			printf("SRC: %s:%u   ", ctdb_addr_to_str(&list->tickles.connections[i].src_addr), ntohs(list->tickles.connections[i].src_addr.ip.sin_port));
+			printf("DST: %s:%u\n", ctdb_addr_to_str(&list->tickles.connections[i].dst_addr), ntohs(list->tickles.connections[i].dst_addr.ip.sin_port));
+		}
+	}
+
+	talloc_free(list);
+	
+	return 0;
+}
+
+
+static int move_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr, uint32_t pnn)
+{
+	struct ctdb_all_public_ips *ips;
+	struct ctdb_public_ip ip;
+	int i, ret;
+	uint32_t *nodes;
+	uint32_t disable_time;
+	TDB_DATA data;
+	struct ctdb_node_map *nodemap=NULL;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+	disable_time = 30;
+	data.dptr  = (uint8_t*)&disable_time;
+	data.dsize = sizeof(disable_time);
+	ret = ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_DISABLE_IP_CHECK, data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send message to disable ipcheck\n"));
+		return -1;
+	}
+
+
+
+	/* read the public ip list from the node */
+	ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), pnn, ctdb, &ips);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", pnn));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	for (i=0;i<ips->num;i++) {
+		if (ctdb_same_ip(addr, &ips->ips[i].addr)) {
+			break;
+		}
+	}
+	if (i==ips->num) {
+		DEBUG(DEBUG_ERR, ("Node %u can not host ip address '%s'\n",
+			pnn, ctdb_addr_to_str(addr)));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ip.pnn  = pnn;
+	ip.addr = *addr;
+
+	data.dptr  = (uint8_t *)&ip;
+	data.dsize = sizeof(ip);
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+       	nodes = list_of_active_nodes_except_pnn(ctdb, nodemap, tmp_ctx, pnn);
+	ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_RELEASE_IP,
+					nodes, 0,
+					LONGTIMELIMIT(),
+					false, data,
+					NULL, NULL,
+					NULL);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to release IP on nodes\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ret = ctdb_ctrl_takeover_ip(ctdb, LONGTIMELIMIT(), pnn, &ip);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to take over IP on node %d\n", pnn));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	/* update the recovery daemon so it now knows to expect the new
+	   node assignment for this ip.
+	*/
+	ret = ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_RECD_UPDATE_IP, data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send message to update the ip on the recovery master.\n"));
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  move/failover an ip address to a specific node
+ */
+static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t pnn;
+	int ret, retries = 0;
+	ctdb_sock_addr addr;
+
+	if (argc < 2) {
+		usage();
+		return -1;
+	}
+
+	if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
+		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
+		return -1;
+	}
+
+
+	if (sscanf(argv[1], "%u", &pnn) != 1) {
+		DEBUG(DEBUG_ERR, ("Badly formed pnn\n"));
+		return -1;
+	}
+
+	do {
+		ret = move_ip(ctdb, &addr, pnn);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR,("Failed to move ip to node %d. Wait 3 second and try again.\n", pnn));
+			sleep(3);
+			retries++;
+		}
+	} while (retries < 5 && ret != 0);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to move ip to node %d. Giving up.\n", pnn));
+		return -1;
+	}
+
+	return 0;
+}
+
+void getips_store_callback(void *param, void *data)
+{
+	struct ctdb_public_ip *node_ip = (struct ctdb_public_ip *)data;
+	struct ctdb_all_public_ips *ips = param;
+	int i;
+
+	i = ips->num++;
+	ips->ips[i].pnn  = node_ip->pnn;
+	ips->ips[i].addr = node_ip->addr;
+}
+
+void getips_count_callback(void *param, void *data)
+{
+	uint32_t *count = param;
+
+	(*count)++;
+}
+
+#define IP_KEYLEN	4
+static uint32_t *ip_key(ctdb_sock_addr *ip)
+{
+	static uint32_t key[IP_KEYLEN];
+
+	bzero(key, sizeof(key));
+
+	switch (ip->sa.sa_family) {
+	case AF_INET:
+		key[0]	= ip->ip.sin_addr.s_addr;
+		break;
+	case AF_INET6:
+		key[0]	= ip->ip6.sin6_addr.s6_addr32[3];
+		key[1]	= ip->ip6.sin6_addr.s6_addr32[2];
+		key[2]	= ip->ip6.sin6_addr.s6_addr32[1];
+		key[3]	= ip->ip6.sin6_addr.s6_addr32[0];
+		break;
+	default:
+		DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", ip->sa.sa_family));
+		return key;
+	}
+
+	return key;
+}
+
+static void *add_ip_callback(void *parm, void *data)
+{
+	return parm;
+}
+
+static int
+control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struct ctdb_all_public_ips **ips)
+{
+	struct ctdb_all_public_ips *tmp_ips;
+	struct ctdb_node_map *nodemap=NULL;
+	trbt_tree_t *ip_tree;
+	int i, j, len, ret;
+	uint32_t count;
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+		return ret;
+	}
+
+	ip_tree = trbt_create(tmp_ctx, 0);
+
+	for(i=0;i<nodemap->num;i++){
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+			continue;
+		}
+		if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+			continue;
+		}
+
+		/* read the public ip list from this node */
+		ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &tmp_ips);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", nodemap->nodes[i].pnn));
+			return -1;
+		}
+	
+		for (j=0; j<tmp_ips->num;j++) {
+			struct ctdb_public_ip *node_ip;
+
+			node_ip = talloc(tmp_ctx, struct ctdb_public_ip);
+			node_ip->pnn  = tmp_ips->ips[j].pnn;
+			node_ip->addr = tmp_ips->ips[j].addr;
+
+			trbt_insertarray32_callback(ip_tree,
+				IP_KEYLEN, ip_key(&tmp_ips->ips[j].addr),
+				add_ip_callback,
+				node_ip);
+		}
+		talloc_free(tmp_ips);
+	}
+
+	/* traverse */
+	count = 0;
+	trbt_traversearray32(ip_tree, IP_KEYLEN, getips_count_callback, &count);
+
+	len = offsetof(struct ctdb_all_public_ips, ips) + 
+		count*sizeof(struct ctdb_public_ip);
+	tmp_ips = talloc_zero_size(tmp_ctx, len);
+	trbt_traversearray32(ip_tree, IP_KEYLEN, getips_store_callback, tmp_ips);
+
+	*ips = tmp_ips;
+
+	return 0;
+}
+
+
+/* 
+ * scans all other nodes and returns a pnn for another node that can host this 
+ * ip address or -1
+ */
+static int
+find_other_host_for_public_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_all_public_ips *ips;
+	struct ctdb_node_map *nodemap=NULL;
+	int i, j, ret;
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	for(i=0;i<nodemap->num;i++){
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (nodemap->nodes[i].pnn == options.pnn) {
+			continue;
+		}
+
+		/* read the public ip list from this node */
+		ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", nodemap->nodes[i].pnn));
+			return -1;
+		}
+
+		for (j=0;j<ips->num;j++) {
+			if (ctdb_same_ip(addr, &ips->ips[j].addr)) {
+				talloc_free(tmp_ctx);
+				return nodemap->nodes[i].pnn;
+			}
+		}
+		talloc_free(ips);
+	}
+
+	talloc_free(tmp_ctx);
+	return -1;
+}
+
+static uint32_t ipreallocate_finished;
+
+/*
+  handler for receiving the response to ipreallocate
+*/
+static void ip_reallocate_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	ipreallocate_finished = 1;
+}
+
+static void ctdb_every_second(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
+{
+	struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
+
+	event_add_timed(ctdb->ev, ctdb, 
+				timeval_current_ofs(1, 0),
+				ctdb_every_second, ctdb);
+}
+
+/*
+  ask the recovery daemon on the recovery master to perform a ip reallocation
+ */
+static int control_ipreallocate(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	TDB_DATA data;
+	struct takeover_run_reply rd;
+	uint32_t recmaster;
+	struct ctdb_node_map *nodemap=NULL;
+	int retries=0;
+	struct timeval tv = timeval_current();
+
+	/* we need some events to trigger so we can timeout and restart
+	   the loop
+	*/
+	event_add_timed(ctdb->ev, ctdb, 
+				timeval_current_ofs(1, 0),
+				ctdb_every_second, ctdb);
+
+	rd.pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+	if (rd.pnn == -1) {
+		DEBUG(DEBUG_ERR, ("Failed to get pnn of local node\n"));
+		return -1;
+	}
+	rd.srvid = getpid();
+
+	/* register a message port for receiveing the reply so that we
+	   can receive the reply
+	*/
+	ctdb_client_set_message_handler(ctdb, rd.srvid, ip_reallocate_handler, NULL);
+
+	data.dptr = (uint8_t *)&rd;
+	data.dsize = sizeof(rd);
+
+again:
+	/* check that there are valid nodes available */
+	if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		return -1;
+	}
+	for (i=0; i<nodemap->num;i++) {
+		if ((nodemap->nodes[i].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) == 0) {
+			break;
+		}
+	}
+	if (i==nodemap->num) {
+		DEBUG(DEBUG_ERR,("No recmaster available, no need to wait for cluster convergence\n"));
+		return 0;
+	}
+
+
+	if (!ctdb_getrecmaster(ctdb_connection, options.pnn, &recmaster)) {
+		DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
+		return -1;
+	}
+
+	/* verify the node exists */
+	if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), recmaster, ctdb, &nodemap) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		return -1;
+	}
+
+
+	/* check tha there are nodes available that can act as a recmaster */
+	for (i=0; i<nodemap->num; i++) {
+		if (nodemap->nodes[i].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
+			continue;
+		}
+		break;
+	}
+	if (i == nodemap->num) {
+		DEBUG(DEBUG_ERR,("No possible nodes to host addresses.\n"));
+		return 0;
+	}
+
+	/* verify the recovery master is not STOPPED, nor BANNED */
+	if (nodemap->nodes[recmaster].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
+		DEBUG(DEBUG_ERR,("No suitable recmaster found. Try again\n"));
+		retries++;
+		sleep(1);
+		goto again;
+	} 
+	
+	/* verify the recovery master is not STOPPED, nor BANNED */
+	if (nodemap->nodes[recmaster].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
+		DEBUG(DEBUG_ERR,("No suitable recmaster found. Try again\n"));
+		retries++;
+		sleep(1);
+		goto again;
+	} 
+
+	ipreallocate_finished = 0;
+	ret = ctdb_client_send_message(ctdb, recmaster, CTDB_SRVID_TAKEOVER_RUN, data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send ip takeover run request message to %u\n", options.pnn));
+		return -1;
+	}
+
+	tv = timeval_current();
+	/* this loop will terminate when we have received the reply */
+	while (timeval_elapsed(&tv) < 5.0 && ipreallocate_finished == 0) {
+		event_loop_once(ctdb->ev);
+	}
+	if (ipreallocate_finished == 1) {
+		return 0;
+	}
+
+	retries++;
+	sleep(1);
+	goto again;
+
+	return 0;
+}
+
+
+/*
+  add a public ip address to a node
+ */
+static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	int len, retries = 0;
+	unsigned mask;
+	ctdb_sock_addr addr;
+	struct ctdb_control_ip_iface *pub;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_all_public_ips *ips;
+
+
+	if (argc != 2) {
+		talloc_free(tmp_ctx);
+		usage();
+	}
+
+	if (!parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
+		DEBUG(DEBUG_ERR, ("Badly formed ip/mask : %s\n", argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	/* read the public ip list from the node */
+	ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &ips);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	for (i=0;i<ips->num;i++) {
+		if (ctdb_same_ip(&addr, &ips->ips[i].addr)) {
+			DEBUG(DEBUG_ERR,("Can not add ip to node. Node already hosts this ip\n"));
+			return 0;
+		}
+	}
+
+
+
+	/* Dont timeout. This command waits for an ip reallocation
+	   which sometimes can take wuite a while if there has
+	   been a recent recovery
+	*/
+	alarm(0);
+
+	len = offsetof(struct ctdb_control_ip_iface, iface) + strlen(argv[1]) + 1;
+	pub = talloc_size(tmp_ctx, len); 
+	CTDB_NO_MEMORY(ctdb, pub);
+
+	pub->addr  = addr;
+	pub->mask  = mask;
+	pub->len   = strlen(argv[1])+1;
+	memcpy(&pub->iface[0], argv[1], strlen(argv[1])+1);
+
+	do {
+		ret = ctdb_ctrl_add_public_ip(ctdb, TIMELIMIT(), options.pnn, pub);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to add public ip to node %u. Wait 3 seconds and try again.\n", options.pnn));
+			sleep(3);
+			retries++;
+		}
+	} while (retries < 5 && ret != 0);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to add public ip to node %u. Giving up.\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	do {
+		ret = control_ipreallocate(ctdb, argc, argv);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u. Wait 3 seconds and try again.\n", options.pnn));
+			sleep(3);
+			retries++;
+		}
+	} while (retries < 5 && ret != 0);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u. Giving up.\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv);
+
+static int control_delip_all(struct ctdb_context *ctdb, int argc, const char **argv, ctdb_sock_addr *addr)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_all_public_ips *ips;
+	int ret, i, j;
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from current node\n"));
+		return ret;
+	}
+
+	/* remove it from the nodes that are not hosting the ip currently */
+	for(i=0;i<nodemap->num;i++){
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips) != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %d\n", nodemap->nodes[i].pnn));
+			continue;
+		}
+
+		for (j=0;j<ips->num;j++) {
+			if (ctdb_same_ip(addr, &ips->ips[j].addr)) {
+				break;
+			}
+		}
+		if (j==ips->num) {
+			continue;
+		}
+
+		if (ips->ips[j].pnn == nodemap->nodes[i].pnn) {
+			continue;
+		}
+
+		options.pnn = nodemap->nodes[i].pnn;
+		control_delip(ctdb, argc, argv);
+	}
+
+
+	/* remove it from every node (also the one hosting it) */
+	for(i=0;i<nodemap->num;i++){
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips) != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %d\n", nodemap->nodes[i].pnn));
+			continue;
+		}
+
+		for (j=0;j<ips->num;j++) {
+			if (ctdb_same_ip(addr, &ips->ips[j].addr)) {
+				break;
+			}
+		}
+		if (j==ips->num) {
+			continue;
+		}
+
+		options.pnn = nodemap->nodes[i].pnn;
+		control_delip(ctdb, argc, argv);
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+	
+/*
+  delete a public ip address from a node
+ */
+static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	int retries = 0;
+	ctdb_sock_addr addr;
+	struct ctdb_control_ip_iface pub;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_all_public_ips *ips;
+
+	if (argc != 1) {
+		talloc_free(tmp_ctx);
+		usage();
+	}
+
+	if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
+		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
+		return -1;
+	}
+
+	if (options.pnn == CTDB_BROADCAST_ALL) {
+		return control_delip_all(ctdb, argc, argv, &addr);
+	}
+
+	pub.addr  = addr;
+	pub.mask  = 0;
+	pub.len   = 0;
+
+	ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &ips);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get public ip list from cluster\n"));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+	
+	for (i=0;i<ips->num;i++) {
+		if (ctdb_same_ip(&addr, &ips->ips[i].addr)) {
+			break;
+		}
+	}
+
+	if (i==ips->num) {
+		DEBUG(DEBUG_ERR, ("This node does not support this public address '%s'\n",
+			ctdb_addr_to_str(&addr)));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (ips->ips[i].pnn == options.pnn) {
+		ret = find_other_host_for_public_ip(ctdb, &addr);
+		if (ret != -1) {
+			do {
+				ret = move_ip(ctdb, &addr, ret);
+				if (ret != 0) {
+					DEBUG(DEBUG_ERR,("Failed to move ip to node %d. Wait 3 seconds and try again.\n", options.pnn));
+					sleep(3);
+					retries++;
+				}
+			} while (retries < 5 && ret != 0);
+			if (ret != 0) {
+				DEBUG(DEBUG_ERR,("Failed to move ip to node %d. Giving up.\n", options.pnn));
+				return -1;
+			}
+		}
+	}
+
+	ret = ctdb_ctrl_del_public_ip(ctdb, TIMELIMIT(), options.pnn, &pub);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to del public ip from node %u\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  kill a tcp connection
+ */
+static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_control_killtcp killtcp;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	if (!parse_ip_port(argv[0], &killtcp.src_addr)) {
+		DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[0]));
+		return -1;
+	}
+
+	if (!parse_ip_port(argv[1], &killtcp.dst_addr)) {
+		DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[1]));
+		return -1;
+	}
+
+	ret = ctdb_ctrl_killtcp(ctdb, TIMELIMIT(), options.pnn, &killtcp);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to killtcp from node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+
+/*
+  send a gratious arp
+ */
+static int control_gratious_arp(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	ctdb_sock_addr addr;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	if (!parse_ip(argv[0], NULL, 0, &addr)) {
+		DEBUG(DEBUG_ERR, ("Bad IP '%s'\n", argv[0]));
+		return -1;
+	}
+
+	ret = ctdb_ctrl_gratious_arp(ctdb, TIMELIMIT(), options.pnn, &addr, argv[1]);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to send gratious_arp from node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  register a server id
+ */
+static int regsrvid(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_server_id server_id;
+
+	if (argc < 3) {
+		usage();
+	}
+
+	server_id.pnn       = strtoul(argv[0], NULL, 0);
+	server_id.type      = strtoul(argv[1], NULL, 0);
+	server_id.server_id = strtoul(argv[2], NULL, 0);
+
+	ret = ctdb_ctrl_register_server_id(ctdb, TIMELIMIT(), &server_id);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to register server_id from node %u\n", options.pnn));
+		return ret;
+	}
+	DEBUG(DEBUG_ERR,("Srvid registered. Sleeping for 999 seconds\n"));
+	sleep(999);
+	return -1;
+}
+
+/*
+  unregister a server id
+ */
+static int unregsrvid(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_server_id server_id;
+
+	if (argc < 3) {
+		usage();
+	}
+
+	server_id.pnn       = strtoul(argv[0], NULL, 0);
+	server_id.type      = strtoul(argv[1], NULL, 0);
+	server_id.server_id = strtoul(argv[2], NULL, 0);
+
+	ret = ctdb_ctrl_unregister_server_id(ctdb, TIMELIMIT(), &server_id);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to unregister server_id from node %u\n", options.pnn));
+		return ret;
+	}
+	return -1;
+}
+
+/*
+  check if a server id exists
+ */
+static int chksrvid(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t status;
+	int ret;
+	struct ctdb_server_id server_id;
+
+	if (argc < 3) {
+		usage();
+	}
+
+	server_id.pnn       = strtoul(argv[0], NULL, 0);
+	server_id.type      = strtoul(argv[1], NULL, 0);
+	server_id.server_id = strtoul(argv[2], NULL, 0);
+
+	ret = ctdb_ctrl_check_server_id(ctdb, TIMELIMIT(), options.pnn, &server_id, &status);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to check server_id from node %u\n", options.pnn));
+		return ret;
+	}
+
+	if (status) {
+		printf("Server id %d:%d:%d EXISTS\n", server_id.pnn, server_id.type, server_id.server_id);
+	} else {
+		printf("Server id %d:%d:%d does NOT exist\n", server_id.pnn, server_id.type, server_id.server_id);
+	}
+	return 0;
+}
+
+/*
+  get a list of all server ids that are registered on a node
+ */
+static int getsrvids(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	struct ctdb_server_id_list *server_ids;
+
+	ret = ctdb_ctrl_get_server_id_list(ctdb, ctdb, TIMELIMIT(), options.pnn, &server_ids);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get server_id list from node %u\n", options.pnn));
+		return ret;
+	}
+
+	for (i=0; i<server_ids->num; i++) {
+		printf("Server id %d:%d:%d\n", 
+			server_ids->server_ids[i].pnn, 
+			server_ids->server_ids[i].type, 
+			server_ids->server_ids[i].server_id); 
+	}
+
+	return -1;
+}
+
+/*
+  send a tcp tickle ack
+ */
+static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	ctdb_sock_addr	src, dst;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	if (!parse_ip_port(argv[0], &src)) {
+		DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[0]));
+		return -1;
+	}
+
+	if (!parse_ip_port(argv[1], &dst)) {
+		DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[1]));
+		return -1;
+	}
+
+	ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
+	if (ret==0) {
+		return 0;
+	}
+	DEBUG(DEBUG_ERR, ("Error while sending tickle ack\n"));
+
+	return -1;
+}
+
+
+/*
+  display public ip status
+ */
+static int control_ip(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_all_public_ips *ips;
+
+	if (options.pnn == CTDB_BROADCAST_ALL) {
+		/* read the list of public ips from all nodes */
+		ret = control_get_all_public_ips(ctdb, tmp_ctx, &ips);
+	} else {
+		/* read the public ip list from this node */
+		ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &ips);
+	}
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get public ips from node %u\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	if (options.machinereadable){
+		printf(":Public IP:Node:");
+		if (options.verbose){
+			printf("ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:");
+		}
+		printf("\n");
+	} else {
+		if (options.pnn == CTDB_BROADCAST_ALL) {
+			printf("Public IPs on ALL nodes\n");
+		} else {
+			printf("Public IPs on node %u\n", options.pnn);
+		}
+	}
+
+	for (i=1;i<=ips->num;i++) {
+		struct ctdb_control_public_ip_info *info = NULL;
+		int32_t pnn;
+		char *aciface = NULL;
+		char *avifaces = NULL;
+		char *cifaces = NULL;
+
+		if (options.pnn == CTDB_BROADCAST_ALL) {
+			pnn = ips->ips[ips->num-i].pnn;
+		} else {
+			pnn = options.pnn;
+		}
+
+		if (pnn != -1) {
+			ret = ctdb_ctrl_get_public_ip_info(ctdb, TIMELIMIT(), pnn, ctdb,
+						   &ips->ips[ips->num-i].addr, &info);
+		} else {
+			ret = -1;
+		}
+
+		if (ret == 0) {
+			int j;
+			for (j=0; j < info->num; j++) {
+				if (cifaces == NULL) {
+					cifaces = talloc_strdup(info,
+								info->ifaces[j].name);
+				} else {
+					cifaces = talloc_asprintf_append(cifaces,
+									 ",%s",
+									 info->ifaces[j].name);
+				}
+
+				if (info->active_idx == j) {
+					aciface = info->ifaces[j].name;
+				}
+
+				if (info->ifaces[j].link_state == 0) {
+					continue;
+				}
+
+				if (avifaces == NULL) {
+					avifaces = talloc_strdup(info, info->ifaces[j].name);
+				} else {
+					avifaces = talloc_asprintf_append(avifaces,
+									  ",%s",
+									  info->ifaces[j].name);
+				}
+			}
+		}
+
+		if (options.machinereadable){
+			printf(":%s:%d:",
+				ctdb_addr_to_str(&ips->ips[ips->num-i].addr),
+				ips->ips[ips->num-i].pnn);
+			if (options.verbose){
+				printf("%s:%s:%s:",
+					aciface?aciface:"",
+					avifaces?avifaces:"",
+					cifaces?cifaces:"");
+			}
+			printf("\n");
+		} else {
+			if (options.verbose) {
+				printf("%s node[%d] active[%s] available[%s] configured[%s]\n",
+					ctdb_addr_to_str(&ips->ips[ips->num-i].addr),
+					ips->ips[ips->num-i].pnn,
+					aciface?aciface:"",
+					avifaces?avifaces:"",
+					cifaces?cifaces:"");
+			} else {
+				printf("%s %d\n",
+					ctdb_addr_to_str(&ips->ips[ips->num-i].addr),
+					ips->ips[ips->num-i].pnn);
+			}
+		}
+		talloc_free(info);
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  public ip info
+ */
+static int control_ipinfo(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	ctdb_sock_addr addr;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_control_public_ip_info *info;
+
+	if (argc != 1) {
+		talloc_free(tmp_ctx);
+		usage();
+	}
+
+	if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
+		DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
+		return -1;
+	}
+
+	/* read the public ip info from this node */
+	ret = ctdb_ctrl_get_public_ip_info(ctdb, TIMELIMIT(), options.pnn,
+					   tmp_ctx, &addr, &info);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get public ip[%s]info from node %u\n",
+				  argv[0], options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	printf("Public IP[%s] info on node %u\n",
+	       ctdb_addr_to_str(&info->ip.addr),
+	       options.pnn);
+
+	printf("IP:%s\nCurrentNode:%d\nNumInterfaces:%u\n",
+	       ctdb_addr_to_str(&info->ip.addr),
+	       info->ip.pnn, info->num);
+
+	for (i=0; i<info->num; i++) {
+		info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
+
+		printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
+		       i+1, info->ifaces[i].name,
+		       info->ifaces[i].link_state?"up":"down",
+		       (unsigned int)info->ifaces[i].references,
+		       (i==info->active_idx)?" (active)":"");
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  display interfaces status
+ */
+static int control_ifaces(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_control_get_ifaces *ifaces;
+
+	/* read the public ip list from this node */
+	ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(), options.pnn,
+				   tmp_ctx, &ifaces);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get interfaces from node %u\n",
+				  options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	if (options.machinereadable){
+		printf(":Name:LinkStatus:References:\n");
+	} else {
+		printf("Interfaces on node %u\n", options.pnn);
+	}
+
+	for (i=0; i<ifaces->num; i++) {
+		if (options.machinereadable){
+			printf(":%s:%s:%u\n",
+			       ifaces->ifaces[i].name,
+			       ifaces->ifaces[i].link_state?"1":"0",
+			       (unsigned int)ifaces->ifaces[i].references);
+		} else {
+			printf("name:%s link:%s references:%u\n",
+			       ifaces->ifaces[i].name,
+			       ifaces->ifaces[i].link_state?"up":"down",
+			       (unsigned int)ifaces->ifaces[i].references);
+		}
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+
+/*
+  set link status of an interface
+ */
+static int control_setifacelink(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_control_iface_info info;
+
+	ZERO_STRUCT(info);
+
+	if (argc != 2) {
+		usage();
+	}
+
+	if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
+		DEBUG(DEBUG_ERR, ("interfaces name '%s' too long\n",
+				  argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	strcpy(info.name, argv[0]);
+
+	if (strcmp(argv[1], "up") == 0) {
+		info.link_state = 1;
+	} else if (strcmp(argv[1], "down") == 0) {
+		info.link_state = 0;
+	} else {
+		DEBUG(DEBUG_ERR, ("link state invalid '%s' should be 'up' or 'down'\n",
+				  argv[1]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	/* read the public ip list from this node */
+	ret = ctdb_ctrl_set_iface_link(ctdb, TIMELIMIT(), options.pnn,
+				   tmp_ctx, &info);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to set link state for interfaces %s node %u\n",
+				  argv[0], options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  display pid of a ctdb daemon
+ */
+static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t pid;
+	int ret;
+
+	ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.pnn, &pid);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get daemon pid from node %u\n", options.pnn));
+		return ret;
+	}
+	printf("Pid:%d\n", pid);
+
+	return 0;
+}
+
+/*
+  disable a remote node
+ */
+static int control_disable(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_node_map *nodemap=NULL;
+
+	/* check if the node is already disabled */
+	if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		exit(10);
+	}
+	if (nodemap->nodes[options.pnn].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
+		DEBUG(DEBUG_ERR,("Node %d is already disabled.\n", options.pnn));
+		return 0;
+	}
+
+	do {
+		ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn, NODE_FLAGS_PERMANENTLY_DISABLED, 0);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to disable node %u\n", options.pnn));
+			return ret;
+		}
+
+		sleep(1);
+
+		/* read the nodemap and verify the change took effect */
+		if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+			exit(10);
+		}
+
+	} while (!(nodemap->nodes[options.pnn].flags & NODE_FLAGS_PERMANENTLY_DISABLED));
+	ret = control_ipreallocate(ctdb, argc, argv);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  enable a disabled remote node
+ */
+static int control_enable(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+
+	struct ctdb_node_map *nodemap=NULL;
+
+
+	/* check if the node is already enabled */
+	if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		exit(10);
+	}
+	if (!(nodemap->nodes[options.pnn].flags & NODE_FLAGS_PERMANENTLY_DISABLED)) {
+		DEBUG(DEBUG_ERR,("Node %d is already enabled.\n", options.pnn));
+		return 0;
+	}
+
+	do {
+		ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn, 0, NODE_FLAGS_PERMANENTLY_DISABLED);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to enable node %u\n", options.pnn));
+			return ret;
+		}
+
+		sleep(1);
+
+		/* read the nodemap and verify the change took effect */
+		if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+			exit(10);
+		}
+
+	} while (nodemap->nodes[options.pnn].flags & NODE_FLAGS_PERMANENTLY_DISABLED);
+
+	ret = control_ipreallocate(ctdb, argc, argv);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  stop a remote node
+ */
+static int control_stop(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_node_map *nodemap=NULL;
+
+	do {
+		ret = ctdb_ctrl_stop_node(ctdb, TIMELIMIT(), options.pnn);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to stop node %u   try again\n", options.pnn));
+		}
+	
+		sleep(1);
+
+		/* read the nodemap and verify the change took effect */
+		if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+			exit(10);
+		}
+
+	} while (!(nodemap->nodes[options.pnn].flags & NODE_FLAGS_STOPPED));
+	ret = control_ipreallocate(ctdb, argc, argv);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  restart a stopped remote node
+ */
+static int control_continue(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+
+	struct ctdb_node_map *nodemap=NULL;
+
+	do {
+		ret = ctdb_ctrl_continue_node(ctdb, TIMELIMIT(), options.pnn);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to continue node %u\n", options.pnn));
+			return ret;
+		}
+	
+		sleep(1);
+
+		/* read the nodemap and verify the change took effect */
+		if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+			exit(10);
+		}
+
+	} while (nodemap->nodes[options.pnn].flags & NODE_FLAGS_STOPPED);
+	ret = control_ipreallocate(ctdb, argc, argv);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+static uint32_t get_generation(struct ctdb_context *ctdb)
+{
+	struct ctdb_vnn_map *vnnmap=NULL;
+	int ret;
+
+	/* wait until the recmaster is not in recovery mode */
+	while (1) {
+		uint32_t recmode, recmaster;
+		
+		if (vnnmap != NULL) {
+			talloc_free(vnnmap);
+			vnnmap = NULL;
+		}
+
+		/* get the recmaster */
+		if (!ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster)) {
+			DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
+			exit(10);
+		}
+
+		/* get recovery mode */
+		if (!ctdb_getrecmode(ctdb_connection, recmaster, &recmode)) {
+			DEBUG(DEBUG_ERR, ("Unable to get recmode from node %u\n", options.pnn));
+			exit(10);
+		}
+
+		/* get the current generation number */
+		ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), recmaster, ctdb, &vnnmap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get vnnmap from recmaster (%u)\n", recmaster));
+			exit(10);
+		}
+
+		if ((recmode == CTDB_RECOVERY_NORMAL)
+		&&  (vnnmap->generation != 1)){
+			return vnnmap->generation;
+		}
+		sleep(1);
+	}
+}
+
+/*
+  ban a node from the cluster
+ */
+static int control_ban(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_ban_time bantime;
+
+	if (argc < 1) {
+		usage();
+	}
+	
+	/* verify the node exists */
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		return ret;
+	}
+
+	if (nodemap->nodes[options.pnn].flags & NODE_FLAGS_BANNED) {
+		DEBUG(DEBUG_ERR,("Node %u is already banned.\n", options.pnn));
+		return -1;
+	}
+
+	bantime.pnn  = options.pnn;
+	bantime.time = strtoul(argv[0], NULL, 0);
+
+	ret = ctdb_ctrl_set_ban(ctdb, TIMELIMIT(), options.pnn, &bantime);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Banning node %d for %d seconds failed.\n", bantime.pnn, bantime.time));
+		return -1;
+	}	
+
+	ret = control_ipreallocate(ctdb, argc, argv);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+
+/*
+  unban a node from the cluster
+ */
+static int control_unban(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_ban_time bantime;
+
+	/* verify the node exists */
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		return ret;
+	}
+
+	if (!(nodemap->nodes[options.pnn].flags & NODE_FLAGS_BANNED)) {
+		DEBUG(DEBUG_ERR,("Node %u is not banned.\n", options.pnn));
+		return -1;
+	}
+
+	bantime.pnn  = options.pnn;
+	bantime.time = 0;
+
+	ret = ctdb_ctrl_set_ban(ctdb, TIMELIMIT(), options.pnn, &bantime);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Unbanning node %d failed.\n", bantime.pnn));
+		return -1;
+	}	
+
+	ret = control_ipreallocate(ctdb, argc, argv);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("IP Reallocate failed on node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+
+/*
+  show ban information for a node
+ */
+static int control_showban(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_ban_time *bantime;
+
+	/* verify the node exists */
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		return ret;
+	}
+
+	ret = ctdb_ctrl_get_ban(ctdb, TIMELIMIT(), options.pnn, ctdb, &bantime);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Showing ban info for node %d failed.\n", options.pnn));
+		return -1;
+	}	
+
+	if (bantime->time == 0) {
+		printf("Node %u is not banned\n", bantime->pnn);
+	} else {
+		printf("Node %u is banned banned for %d seconds\n", bantime->pnn, bantime->time);
+	}
+
+	return 0;
+}
+
+/*
+  shutdown a daemon
+ */
+static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+
+	ret = ctdb_ctrl_shutdown(ctdb, TIMELIMIT(), options.pnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to shutdown node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  trigger a recovery
+ */
+static int control_recover(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	uint32_t generation, next_generation;
+
+	/* record the current generation number */
+	generation = get_generation(ctdb);
+
+	ret = ctdb_ctrl_freeze_priority(ctdb, TIMELIMIT(), options.pnn, 1);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to freeze node\n"));
+		return ret;
+	}
+
+	ret = ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to set recovery mode\n"));
+		return ret;
+	}
+
+	/* wait until we are in a new generation */
+	while (1) {
+		next_generation = get_generation(ctdb);
+		if (next_generation != generation) {
+			return 0;
+		}
+		sleep(1);
+	}
+
+	return 0;
+}
+
+
+/*
+  display monitoring mode of a remote node
+ */
+static int control_getmonmode(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t monmode;
+	int ret;
+
+	ret = ctdb_ctrl_getmonmode(ctdb, TIMELIMIT(), options.pnn, &monmode);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get monmode from node %u\n", options.pnn));
+		return ret;
+	}
+	if (!options.machinereadable){
+		printf("Monitoring mode:%s (%d)\n",monmode==CTDB_MONITORING_ACTIVE?"ACTIVE":"DISABLED",monmode);
+	} else {
+		printf(":mode:\n");
+		printf(":%d:\n",monmode);
+	}
+	return 0;
+}
+
+
+/*
+  display capabilities of a remote node
+ */
+static int control_getcapabilities(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t capabilities;
+	int ret;
+
+	ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), options.pnn, &capabilities);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", options.pnn));
+		return ret;
+	}
+	
+	if (!options.machinereadable){
+		printf("RECMASTER: %s\n", (capabilities&CTDB_CAP_RECMASTER)?"YES":"NO");
+		printf("LMASTER: %s\n", (capabilities&CTDB_CAP_LMASTER)?"YES":"NO");
+		printf("LVS: %s\n", (capabilities&CTDB_CAP_LVS)?"YES":"NO");
+		printf("NATGW: %s\n", (capabilities&CTDB_CAP_NATGW)?"YES":"NO");
+	} else {
+		printf(":RECMASTER:LMASTER:LVS:NATGW:\n");
+		printf(":%d:%d:%d:%d:\n",
+			!!(capabilities&CTDB_CAP_RECMASTER),
+			!!(capabilities&CTDB_CAP_LMASTER),
+			!!(capabilities&CTDB_CAP_LVS),
+			!!(capabilities&CTDB_CAP_NATGW));
+	}
+	return 0;
+}
+
+/*
+  display lvs configuration
+ */
+static int control_lvs(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t *capabilities;
+	struct ctdb_node_map *nodemap=NULL;
+	int i, ret;
+	int healthy_count = 0;
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+		return ret;
+	}
+
+	capabilities = talloc_array(ctdb, uint32_t, nodemap->num);
+	CTDB_NO_MEMORY(ctdb, capabilities);
+	
+	/* collect capabilities for all connected nodes */
+	for (i=0; i<nodemap->num; i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
+			continue;
+		}
+	
+		ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i));
+			return ret;
+		}
+
+		if (!(capabilities[i] & CTDB_CAP_LVS)) {
+			continue;
+		}
+
+		if (!(nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY)) {
+			healthy_count++;
+		}
+	}
+
+	/* Print all LVS nodes */
+	for (i=0; i<nodemap->num; i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
+			continue;
+		}
+		if (!(capabilities[i] & CTDB_CAP_LVS)) {
+			continue;
+		}
+
+		if (healthy_count != 0) {
+			if (nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY) {
+				continue;
+			}
+		}
+
+		printf("%d:%s\n", i, 
+			ctdb_addr_to_str(&nodemap->nodes[i].addr));
+	}
+
+	return 0;
+}
+
+/*
+  display who is the lvs master
+ */
+static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t *capabilities;
+	struct ctdb_node_map *nodemap=NULL;
+	int i, ret;
+	int healthy_count = 0;
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+		return ret;
+	}
+
+	capabilities = talloc_array(ctdb, uint32_t, nodemap->num);
+	CTDB_NO_MEMORY(ctdb, capabilities);
+	
+	/* collect capabilities for all connected nodes */
+	for (i=0; i<nodemap->num; i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
+			continue;
+		}
+	
+		ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i));
+			return ret;
+		}
+
+		if (!(capabilities[i] & CTDB_CAP_LVS)) {
+			continue;
+		}
+
+		if (!(nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY)) {
+			healthy_count++;
+		}
+	}
+
+	/* find and show the lvsmaster */
+	for (i=0; i<nodemap->num; i++) {
+		if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+			continue;
+		}
+		if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
+			continue;
+		}
+		if (!(capabilities[i] & CTDB_CAP_LVS)) {
+			continue;
+		}
+
+		if (healthy_count != 0) {
+			if (nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY) {
+				continue;
+			}
+		}
+
+		if (options.machinereadable){
+			printf("%d\n", i);
+		} else {
+			printf("Node %d is LVS master\n", i);
+		}
+		return 0;
+	}
+
+	printf("There is no LVS master\n");
+	return -1;
+}
+
+/*
+  disable monitoring on a  node
+ */
+static int control_disable_monmode(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	
+	int ret;
+
+	ret = ctdb_ctrl_disable_monmode(ctdb, TIMELIMIT(), options.pnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to disable monmode on node %u\n", options.pnn));
+		return ret;
+	}
+	printf("Monitoring mode:%s\n","DISABLED");
+
+	return 0;
+}
+
+/*
+  enable monitoring on a  node
+ */
+static int control_enable_monmode(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	
+	int ret;
+
+	ret = ctdb_ctrl_enable_monmode(ctdb, TIMELIMIT(), options.pnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to enable monmode on node %u\n", options.pnn));
+		return ret;
+	}
+	printf("Monitoring mode:%s\n","ACTIVE");
+
+	return 0;
+}
+
+/*
+  display remote list of keys/data for a db
+ */
+static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *db_name;
+	struct ctdb_db_context *ctdb_db;
+	int ret;
+	bool persistent;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	db_name = argv[0];
+
+
+	if (db_exists(ctdb, db_name, &persistent)) {
+		DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+		return -1;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
+
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
+		return -1;
+	}
+
+	/* traverse and dump the cluster tdb */
+	ret = ctdb_dump_db(ctdb_db, stdout);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR, ("Unable to dump database\n"));
+		DEBUG(DEBUG_ERR, ("Maybe try 'ctdb getdbstatus %s'"
+				  " and 'ctdb getvar AllowUnhealthyDBRead'\n",
+				  db_name));
+		return -1;
+	}
+	talloc_free(ctdb_db);
+
+	printf("Dumped %d records\n", ret);
+	return 0;
+}
+
+struct cattdb_data {
+	struct ctdb_context *ctdb;
+	uint32_t count;
+};
+
+static int cattdb_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
+{
+	struct cattdb_data *d = private_data;
+
+	d->count++;
+	
+	return ctdb_dumpdb_record(d->ctdb, key, data, stdout);
+}
+
+/*
+  cat the local tdb database using same format as catdb
+ */
+static int control_cattdb(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *db_name;
+	struct ctdb_db_context *ctdb_db;
+	struct cattdb_data d;
+	bool persistent;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	db_name = argv[0];
+
+
+	if (db_exists(ctdb, db_name, &persistent)) {
+		DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+		return -1;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, false, 0);
+
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
+		return -1;
+	}
+
+	/* traverse the local tdb */
+	d.count = 0;
+	d.ctdb  = ctdb;
+	if (tdb_traverse_read(ctdb_db->ltdb->tdb, cattdb_traverse, &d) == -1) {
+		printf("Failed to cattdb data\n");
+		exit(10);
+	}
+	talloc_free(ctdb_db);
+
+	printf("Dumped %d records\n", d.count);
+	return 0;
+}
+
+/*
+  display the content of a database key
+ */
+static int control_readkey(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *db_name;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_record_handle *h;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA key, data;
+	bool persistent;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	db_name = argv[0];
+
+
+	if (db_exists(ctdb, db_name, &persistent)) {
+		DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+		return -1;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
+
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
+		return -1;
+	}
+
+	key.dptr  = discard_const(argv[1]);
+	key.dsize = strlen((char *)key.dptr);
+ 
+	h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data);
+	if (h == NULL) {
+		printf("Failed to fetch record '%s' on node %d\n", 
+	       		(const char *)key.dptr, ctdb_get_pnn(ctdb));
+		talloc_free(tmp_ctx);
+		exit(10);
+	}
+
+	printf("Data: size:%d ptr:[%s]\n", (int)data.dsize, data.dptr);
+
+	talloc_free(ctdb_db);
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  display the content of a database key
+ */
+static int control_writekey(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *db_name;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_record_handle *h;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA key, data;
+	bool persistent;
+
+	if (argc < 3) {
+		usage();
+	}
+
+	db_name = argv[0];
+
+
+	if (db_exists(ctdb, db_name, &persistent)) {
+		DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+		return -1;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
+
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
+		return -1;
+	}
+
+	key.dptr  = discard_const(argv[1]);
+	key.dsize = strlen((char *)key.dptr);
+ 
+	h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data);
+	if (h == NULL) {
+		printf("Failed to fetch record '%s' on node %d\n", 
+	       		(const char *)key.dptr, ctdb_get_pnn(ctdb));
+		talloc_free(tmp_ctx);
+		exit(10);
+	}
+
+	data.dptr  = discard_const(argv[2]);
+	data.dsize = strlen((char *)data.dptr);
+ 
+	if (ctdb_record_store(h, data) != 0) {
+		printf("Failed to store record\n");
+	}
+
+	talloc_free(h);
+	talloc_free(ctdb_db);
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  fetch a record from a persistent database
+ */
+static int control_pfetch(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *db_name;
+	struct ctdb_db_context *ctdb_db;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_transaction_handle *h;
+	TDB_DATA key, data;
+	int fd, ret;
+	bool persistent;
+
+	if (argc < 2) {
+		talloc_free(tmp_ctx);
+		usage();
+	}
+
+	db_name = argv[0];
+
+
+	if (db_exists(ctdb, db_name, &persistent)) {
+		DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (!persistent) {
+		DEBUG(DEBUG_ERR,("Database '%s' is not persistent\n", db_name));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
+
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	h = ctdb_transaction_start(ctdb_db, tmp_ctx);
+	if (h == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", db_name));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	key.dptr  = discard_const(argv[1]);
+	key.dsize = strlen(argv[1]);
+	ret = ctdb_transaction_fetch(h, tmp_ctx, key, &data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to fetch record\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (data.dsize == 0 || data.dptr == NULL) {
+		DEBUG(DEBUG_ERR,("Record is empty\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (argc == 3) {
+	  fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
+		if (fd == -1) {
+			DEBUG(DEBUG_ERR,("Failed to open output file %s\n", argv[2]));
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+		write(fd, data.dptr, data.dsize);
+		close(fd);
+	} else {
+		write(1, data.dptr, data.dsize);
+	}
+
+	/* abort the transaction */
+	talloc_free(h);
+
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  fetch a record from a tdb-file
+ */
+static int control_tfetch(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *tdb_file;
+	TDB_CONTEXT *tdb;
+	TDB_DATA key, data;
+	int fd;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	tdb_file = argv[0];
+
+	tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0);
+	if (tdb == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to open TDB file %s\n", tdb_file));
+		return -1;
+	}
+
+	key.dptr  = discard_const(argv[1]);
+	key.dsize = strlen(argv[1]);
+	data = tdb_fetch(tdb, key);
+	if (data.dptr == NULL || data.dsize < sizeof(struct ctdb_ltdb_header)) {
+		DEBUG(DEBUG_ERR,("Failed to read record %s from tdb %s\n", argv[1], tdb_file));
+		tdb_close(tdb);
+		return -1;
+	}
+
+	tdb_close(tdb);
+
+	if (argc == 3) {
+	  fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
+		if (fd == -1) {
+			DEBUG(DEBUG_ERR,("Failed to open output file %s\n", argv[2]));
+			return -1;
+		}
+		write(fd, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header));
+		close(fd);
+	} else {
+		write(1, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header));
+	}
+
+	return 0;
+}
+
+/*
+  write a record to a persistent database
+ */
+static int control_pstore(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *db_name;
+	struct ctdb_db_context *ctdb_db;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct ctdb_transaction_handle *h;
+	struct stat st;
+	TDB_DATA key, data;
+	int fd, ret;
+
+	if (argc < 3) {
+		talloc_free(tmp_ctx);
+		usage();
+	}
+
+	fd = open(argv[2], O_RDONLY);
+	if (fd == -1) {
+		DEBUG(DEBUG_ERR,("Failed to open file containing record data : %s  %s\n", argv[2], strerror(errno)));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	
+	ret = fstat(fd, &st);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR,("fstat of file %s failed: %s\n", argv[2], strerror(errno)));
+		close(fd);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	if (!S_ISREG(st.st_mode)) {
+		DEBUG(DEBUG_ERR,("Not a regular file %s\n", argv[2]));
+		close(fd);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	data.dsize = st.st_size;
+	if (data.dsize == 0) {
+		data.dptr  = NULL;
+	} else {
+		data.dptr = talloc_size(tmp_ctx, data.dsize);
+		if (data.dptr == NULL) {
+			DEBUG(DEBUG_ERR,("Failed to talloc %d of memory to store record data\n", (int)data.dsize));
+			close(fd);
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+		ret = read(fd, data.dptr, data.dsize);
+		if (ret != data.dsize) {
+			DEBUG(DEBUG_ERR,("Failed to read %d bytes of record data\n", (int)data.dsize));
+			close(fd);
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+	}
+	close(fd);
+
+
+	db_name = argv[0];
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, true, 0);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	h = ctdb_transaction_start(ctdb_db, tmp_ctx);
+	if (h == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", db_name));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	key.dptr  = discard_const(argv[1]);
+	key.dsize = strlen(argv[1]);
+	ret = ctdb_transaction_store(h, key, data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to store record\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ret = ctdb_transaction_commit(h);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to commit transaction\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  check if a service is bound to a port or not
+ */
+static int control_chktcpport(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int s, ret;
+	unsigned v;
+	int port;
+        struct sockaddr_in sin;
+
+	if (argc != 1) {
+		printf("Use: ctdb chktcport <port>\n");
+		return EINVAL;
+	}
+
+	port = atoi(argv[0]);
+
+	s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (s == -1) {
+		printf("Failed to open local socket\n");
+		return errno;
+	}
+
+	v = fcntl(s, F_GETFL, 0);
+        fcntl(s, F_SETFL, v | O_NONBLOCK);
+
+	bzero(&sin, sizeof(sin));
+	sin.sin_family = PF_INET;
+	sin.sin_port   = htons(port);
+	ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
+	close(s);
+	if (ret == -1) {
+		printf("Failed to bind to local socket: %d %s\n", errno, strerror(errno));
+		return errno;
+	}
+
+	return 0;
+}
+
+
+
+static void log_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	DEBUG(DEBUG_ERR,("Log data received\n"));
+	if (data.dsize > 0) {
+		printf("%s", data.dptr);
+	}
+
+	exit(0);
+}
+
+/*
+  display a list of log messages from the in memory ringbuffer
+ */
+static int control_getlog(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	int32_t res;
+	struct ctdb_get_log_addr log_addr;
+	TDB_DATA data;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	char *errmsg;
+	struct timeval tv;
+
+	if (argc != 1) {
+		DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	log_addr.pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+	log_addr.srvid = getpid();
+	if (isalpha(argv[0][0]) || argv[0][0] == '-') { 
+		log_addr.level = get_debug_by_desc(argv[0]);
+	} else {
+		log_addr.level = strtol(argv[0], NULL, 0);
+	}
+
+
+	data.dptr = (unsigned char *)&log_addr;
+	data.dsize = sizeof(log_addr);
+
+	DEBUG(DEBUG_ERR, ("Pulling logs from node %u\n", options.pnn));
+
+	ctdb_client_set_message_handler(ctdb, log_addr.srvid, log_handler, NULL);
+	sleep(1);
+
+	DEBUG(DEBUG_ERR,("Listen for response on %d\n", (int)log_addr.srvid));
+
+	ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_GET_LOG,
+			   0, data, tmp_ctx, NULL, &res, NULL, &errmsg);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,("Failed to get logs - %s\n", errmsg));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	tv = timeval_current();
+	/* this loop will terminate when we have received the reply */
+	while (timeval_elapsed(&tv) < 3.0) {	
+		event_loop_once(ctdb->ev);
+	}
+
+	DEBUG(DEBUG_INFO,("Timed out waiting for log data.\n"));
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  clear the in memory log area
+ */
+static int control_clearlog(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	int32_t res;
+	char *errmsg;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+	ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_CLEAR_LOG,
+			   0, tdb_null, tmp_ctx, NULL, &res, NULL, &errmsg);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,("Failed to clear logs\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+
+
+/*
+  display a list of the databases on a remote ctdb
+ */
+static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	struct ctdb_dbid_map *dbmap=NULL;
+
+	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn));
+		return ret;
+	}
+
+	if(options.machinereadable){
+		printf(":ID:Name:Path:Persistent:Unhealthy:ReadOnly:\n");
+		for(i=0;i<dbmap->num;i++){
+			const char *path;
+			const char *name;
+			const char *health;
+			bool persistent;
+			bool readonly;
+
+			ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn,
+					    dbmap->dbs[i].dbid, ctdb, &path);
+			ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn,
+					    dbmap->dbs[i].dbid, ctdb, &name);
+			ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn,
+					      dbmap->dbs[i].dbid, ctdb, &health);
+			persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
+			readonly   = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
+			printf(":0x%08X:%s:%s:%d:%d:%d:\n",
+			       dbmap->dbs[i].dbid, name, path,
+			       !!(persistent), !!(health), !!(readonly));
+		}
+		return 0;
+	}
+
+	printf("Number of databases:%d\n", dbmap->num);
+	for(i=0;i<dbmap->num;i++){
+		const char *path;
+		const char *name;
+		const char *health;
+		bool persistent;
+		bool readonly;
+
+		ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &path);
+		ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name);
+		ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &health);
+		persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
+		readonly   = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
+		printf("dbid:0x%08x name:%s path:%s%s%s%s\n",
+		       dbmap->dbs[i].dbid, name, path,
+		       persistent?" PERSISTENT":"",
+		       readonly?" READONLY":"",
+		       health?" UNHEALTHY":"");
+	}
+
+	return 0;
+}
+
+/*
+  display the status of a database on a remote ctdb
+ */
+static int control_getdbstatus(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	struct ctdb_dbid_map *dbmap=NULL;
+	const char *db_name;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	db_name = argv[0];
+
+	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn));
+		return ret;
+	}
+
+	for(i=0;i<dbmap->num;i++){
+		const char *path;
+		const char *name;
+		const char *health;
+		bool persistent;
+		bool readonly;
+
+		ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name);
+		if (strcmp(name, db_name) != 0) {
+			continue;
+		}
+
+		ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &path);
+		ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &health);
+		persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
+		readonly   = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
+		printf("dbid: 0x%08x\nname: %s\npath: %s\nPERSISTENT: %s\nREADONLY: %s\nHEALTH: %s\n",
+		       dbmap->dbs[i].dbid, name, path,
+		       persistent?"yes":"no",
+		       readonly?"yes":"no",
+		       health?health:"OK");
+		return 0;
+	}
+
+	DEBUG(DEBUG_ERR, ("db %s doesn't exist on node %u\n", db_name, options.pnn));
+	return 0;
+}
+
+/*
+  check if the local node is recmaster or not
+  it will return 1 if this node is the recmaster and 0 if it is not
+  or if the local ctdb daemon could not be contacted
+ */
+static int control_isnotrecmaster(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t mypnn, recmaster;
+
+	mypnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), options.pnn);
+	if (mypnn == -1) {
+		printf("Failed to get pnn of node\n");
+		return 1;
+	}
+
+	if (!ctdb_getrecmaster(ctdb_connection, options.pnn, &recmaster)) {
+		printf("Failed to get the recmaster\n");
+		return 1;
+	}
+
+	if (recmaster != mypnn) {
+		printf("this node is not the recmaster\n");
+		return 1;
+	}
+
+	printf("this node is the recmaster\n");
+	return 0;
+}
+
+/*
+  ping a node
+ */
+static int control_ping(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	struct timeval tv = timeval_current();
+	ret = ctdb_ctrl_ping(ctdb, options.pnn);
+	if (ret == -1) {
+		printf("Unable to get ping response from node %u\n", options.pnn);
+		return -1;
+	} else {
+		printf("response from %u time=%.6f sec  (%d clients)\n", 
+		       options.pnn, timeval_elapsed(&tv), ret);
+	}
+	return 0;
+}
+
+
+/*
+  get a tunable
+ */
+static int control_getvar(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *name;
+	uint32_t value;
+	int ret;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	name = argv[0];
+	ret = ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(), options.pnn, name, &value);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR, ("Unable to get tunable variable '%s'\n", name));
+		return -1;
+	}
+
+	printf("%-19s = %u\n", name, value);
+	return 0;
+}
+
+/*
+  set a tunable
+ */
+static int control_setvar(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *name;
+	uint32_t value;
+	int ret;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	name = argv[0];
+	value = strtoul(argv[1], NULL, 0);
+
+	ret = ctdb_ctrl_set_tunable(ctdb, TIMELIMIT(), options.pnn, name, value);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR, ("Unable to set tunable variable '%s'\n", name));
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  list all tunables
+ */
+static int control_listvars(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t count;
+	const char **list;
+	int ret, i;
+
+	ret = ctdb_ctrl_list_tunables(ctdb, TIMELIMIT(), options.pnn, ctdb, &list, &count);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR, ("Unable to list tunable variables\n"));
+		return -1;
+	}
+
+	for (i=0;i<count;i++) {
+		control_getvar(ctdb, 1, &list[i]);
+	}
+
+	talloc_free(list);
+	
+	return 0;
+}
+
+/*
+  display debug level on a node
+ */
+static int control_getdebug(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	int32_t level;
+
+	ret = ctdb_ctrl_get_debuglevel(ctdb, options.pnn, &level);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get debuglevel response from node %u\n", options.pnn));
+		return ret;
+	} else {
+		if (options.machinereadable){
+			printf(":Name:Level:\n");
+			printf(":%s:%d:\n",get_debug_by_level(level),level);
+		} else {
+			printf("Node %u is at debug level %s (%d)\n", options.pnn, get_debug_by_level(level), level);
+		}
+	}
+	return 0;
+}
+
+/*
+  display reclock file of a node
+ */
+static int control_getreclock(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	const char *reclock;
+
+	ret = ctdb_ctrl_getreclock(ctdb, TIMELIMIT(), options.pnn, ctdb, &reclock);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get reclock file from node %u\n", options.pnn));
+		return ret;
+	} else {
+		if (options.machinereadable){
+			if (reclock != NULL) {
+				printf("%s", reclock);
+			}
+		} else {
+			if (reclock == NULL) {
+				printf("No reclock file used.\n");
+			} else {
+				printf("Reclock file:%s\n", reclock);
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+  set the reclock file of a node
+ */
+static int control_setreclock(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	const char *reclock;
+
+	if (argc == 0) {
+		reclock = NULL;
+	} else if (argc == 1) {
+		reclock = argv[0];
+	} else {
+		usage();
+	}
+
+	ret = ctdb_ctrl_setreclock(ctdb, TIMELIMIT(), options.pnn, reclock);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get reclock file from node %u\n", options.pnn));
+		return ret;
+	}
+	return 0;
+}
+
+/*
+  set the natgw state on/off
+ */
+static int control_setnatgwstate(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	uint32_t natgwstate;
+
+	if (argc == 0) {
+		usage();
+	}
+
+	if (!strcmp(argv[0], "on")) {
+		natgwstate = 1;
+	} else if (!strcmp(argv[0], "off")) {
+		natgwstate = 0;
+	} else {
+		usage();
+	}
+
+	ret = ctdb_ctrl_setnatgwstate(ctdb, TIMELIMIT(), options.pnn, natgwstate);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to set the natgw state for node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  set the lmaster role on/off
+ */
+static int control_setlmasterrole(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	uint32_t lmasterrole;
+
+	if (argc == 0) {
+		usage();
+	}
+
+	if (!strcmp(argv[0], "on")) {
+		lmasterrole = 1;
+	} else if (!strcmp(argv[0], "off")) {
+		lmasterrole = 0;
+	} else {
+		usage();
+	}
+
+	ret = ctdb_ctrl_setlmasterrole(ctdb, TIMELIMIT(), options.pnn, lmasterrole);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to set the lmaster role for node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  set the recmaster role on/off
+ */
+static int control_setrecmasterrole(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	uint32_t recmasterrole;
+
+	if (argc == 0) {
+		usage();
+	}
+
+	if (!strcmp(argv[0], "on")) {
+		recmasterrole = 1;
+	} else if (!strcmp(argv[0], "off")) {
+		recmasterrole = 0;
+	} else {
+		usage();
+	}
+
+	ret = ctdb_ctrl_setrecmasterrole(ctdb, TIMELIMIT(), options.pnn, recmasterrole);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to set the recmaster role for node %u\n", options.pnn));
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+  set debug level on a node or all nodes
+ */
+static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	int32_t level;
+
+	if (argc == 0) {
+		printf("You must specify the debug level. Valid levels are:\n");
+		for (i=0; debug_levels[i].description != NULL; i++) {
+			printf("%s (%d)\n", debug_levels[i].description, debug_levels[i].level);
+		}
+
+		return 0;
+	}
+
+	if (isalpha(argv[0][0]) || argv[0][0] == '-') { 
+		level = get_debug_by_desc(argv[0]);
+	} else {
+		level = strtol(argv[0], NULL, 0);
+	}
+
+	for (i=0; debug_levels[i].description != NULL; i++) {
+		if (level == debug_levels[i].level) {
+			break;
+		}
+	}
+	if (debug_levels[i].description == NULL) {
+		printf("Invalid debug level, must be one of\n");
+		for (i=0; debug_levels[i].description != NULL; i++) {
+			printf("%s (%d)\n", debug_levels[i].description, debug_levels[i].level);
+		}
+		return -1;
+	}
+
+	ret = ctdb_ctrl_set_debuglevel(ctdb, options.pnn, level);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to set debug level on node %u\n", options.pnn));
+	}
+	return 0;
+}
+
+
+/*
+  thaw a node
+ */
+static int control_thaw(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	uint32_t priority;
+	
+	if (argc == 1) {
+		priority = strtol(argv[0], NULL, 0);
+	} else {
+		priority = 0;
+	}
+	DEBUG(DEBUG_ERR,("Thaw by priority %u\n", priority));
+
+	ret = ctdb_ctrl_thaw_priority(ctdb, TIMELIMIT(), options.pnn, priority);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to thaw node %u\n", options.pnn));
+	}		
+	return 0;
+}
+
+
+/*
+  attach to a database
+ */
+static int control_attach(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	const char *db_name;
+	struct ctdb_db_context *ctdb_db;
+	bool persistent = false;
+
+	if (argc < 1) {
+		usage();
+	}
+	db_name = argv[0];
+	if (argc > 2) {
+		usage();
+	}
+	if (argc == 2) {
+		if (strcmp(argv[1], "persistent") != 0) {
+			usage();
+		}
+		persistent = true;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  set db priority
+ */
+static int control_setdbprio(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	struct ctdb_db_priority db_prio;
+	int ret;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	db_prio.db_id    = strtoul(argv[0], NULL, 0);
+	db_prio.priority = strtoul(argv[1], NULL, 0);
+
+	ret = ctdb_ctrl_set_db_priority(ctdb, TIMELIMIT(), options.pnn, &db_prio);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Unable to set db prio\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  get db priority
+ */
+static int control_getdbprio(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t db_id, priority;
+	int ret;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	db_id = strtoul(argv[0], NULL, 0);
+
+	ret = ctdb_ctrl_get_db_priority(ctdb, TIMELIMIT(), options.pnn, db_id, &priority);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Unable to get db prio\n"));
+		return -1;
+	}
+
+	DEBUG(DEBUG_ERR,("Priority:%u\n", priority));
+
+	return 0;
+}
+
+/*
+  set the readonly capability for a database
+ */
+static int control_setdbreadonly(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint32_t db_id;
+	int ret;
+
+	if (argc < 1) {
+		usage();
+	}
+
+	db_id = strtoul(argv[0], NULL, 0);
+
+	ret = ctdb_ctrl_set_db_readonly(ctdb, options.pnn, db_id);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Unable to set db to support readonly\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  run an eventscript on a node
+ */
+static int control_eventscript(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	TDB_DATA data;
+	int ret;
+	int32_t res;
+	char *errmsg;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+
+	if (argc != 1) {
+		DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+		return -1;
+	}
+
+	data.dptr = (unsigned char *)discard_const(argv[0]);
+	data.dsize = strlen((char *)data.dptr) + 1;
+
+	DEBUG(DEBUG_ERR, ("Running eventscripts with arguments \"%s\" on node %u\n", data.dptr, options.pnn));
+
+	ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_RUN_EVENTSCRIPTS,
+			   0, data, tmp_ctx, NULL, &res, NULL, &errmsg);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,("Failed to run eventscripts - %s\n", errmsg));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+#define DB_VERSION 1
+#define MAX_DB_NAME 64
+struct db_file_header {
+	unsigned long version;
+	time_t timestamp;
+	unsigned long persistent;
+	unsigned long size;
+	const char name[MAX_DB_NAME];
+};
+
+struct backup_data {
+	struct ctdb_marshall_buffer *records;
+	uint32_t len;
+	uint32_t total;
+	bool traverse_error;
+};
+
+static int backup_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
+{
+	struct backup_data *bd = talloc_get_type(private, struct backup_data);
+	struct ctdb_rec_data *rec;
+
+	/* add the record */
+	rec = ctdb_marshall_record(bd->records, 0, key, NULL, data);
+	if (rec == NULL) {
+		bd->traverse_error = true;
+		DEBUG(DEBUG_ERR,("Failed to marshall record\n"));
+		return -1;
+	}
+	bd->records = talloc_realloc_size(NULL, bd->records, rec->length + bd->len);
+	if (bd->records == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to expand marshalling buffer\n"));
+		bd->traverse_error = true;
+		return -1;
+	}
+	bd->records->count++;
+	memcpy(bd->len+(uint8_t *)bd->records, rec, rec->length);
+	bd->len += rec->length;
+	talloc_free(rec);
+
+	bd->total++;
+	return 0;
+}
+
+/*
+ * backup a database to a file 
+ */
+static int control_backupdb(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	struct ctdb_dbid_map *dbmap=NULL;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	struct db_file_header dbhdr;
+	struct ctdb_db_context *ctdb_db;
+	struct backup_data *bd;
+	int fh = -1;
+	int status = -1;
+	const char *reason = NULL;
+
+	if (argc != 2) {
+		DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+		return -1;
+	}
+
+	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn));
+		return ret;
+	}
+
+	for(i=0;i<dbmap->num;i++){
+		const char *name;
+
+		ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name);
+		if(!strcmp(argv[0], name)){
+			talloc_free(discard_const(name));
+			break;
+		}
+		talloc_free(discard_const(name));
+	}
+	if (i == dbmap->num) {
+		DEBUG(DEBUG_ERR,("No database with name '%s' found\n", argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ret = ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn,
+				    dbmap->dbs[i].dbid, tmp_ctx, &reason);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Unable to get dbhealth for database '%s'\n",
+				 argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	if (reason) {
+		uint32_t allow_unhealthy = 0;
+
+		ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(), options.pnn,
+				      "AllowUnhealthyDBRead",
+				      &allow_unhealthy);
+
+		if (allow_unhealthy != 1) {
+			DEBUG(DEBUG_ERR,("database '%s' is unhealthy: %s\n",
+					 argv[0], reason));
+
+			DEBUG(DEBUG_ERR,("disallow backup : tunable AllowUnhealthyDBRead = %u\n",
+					 allow_unhealthy));
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+
+		DEBUG(DEBUG_WARNING,("WARNING database '%s' is unhealthy - see 'ctdb getdbstatus %s'\n",
+				     argv[0], argv[0]));
+		DEBUG(DEBUG_WARNING,("WARNING! allow backup of unhealthy database: "
+				     "tunnable AllowUnhealthyDBRead = %u\n",
+				     allow_unhealthy));
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, 0);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR,("Failed to start transaction\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	bd = talloc_zero(tmp_ctx, struct backup_data);
+	if (bd == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to allocate backup_data\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	bd->records = talloc_zero(bd, struct ctdb_marshall_buffer);
+	if (bd->records == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to allocate ctdb_marshall_buffer\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	bd->len = offsetof(struct ctdb_marshall_buffer, data);
+	bd->records->db_id = ctdb_db->db_id;
+	/* traverse the database collecting all records */
+	if (tdb_traverse_read(ctdb_db->ltdb->tdb, backup_traverse, bd) == -1 ||
+	    bd->traverse_error) {
+		DEBUG(DEBUG_ERR,("Traverse error\n"));
+		talloc_free(tmp_ctx);
+		return -1;		
+	}
+
+	tdb_transaction_cancel(ctdb_db->ltdb->tdb);
+
+
+	fh = open(argv[1], O_RDWR|O_CREAT, 0600);
+	if (fh == -1) {
+		DEBUG(DEBUG_ERR,("Failed to open file '%s'\n", argv[1]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	dbhdr.version = DB_VERSION;
+	dbhdr.timestamp = time(NULL);
+	dbhdr.persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
+	dbhdr.size = bd->len;
+	if (strlen(argv[0]) >= MAX_DB_NAME) {
+		DEBUG(DEBUG_ERR,("Too long dbname\n"));
+		goto done;
+	}
+	strncpy(discard_const(dbhdr.name), argv[0], MAX_DB_NAME);
+	ret = write(fh, &dbhdr, sizeof(dbhdr));
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR,("write failed: %s\n", strerror(errno)));
+		goto done;
+	}
+	ret = write(fh, bd->records, bd->len);
+	if (ret == -1) {
+		DEBUG(DEBUG_ERR,("write failed: %s\n", strerror(errno)));
+		goto done;
+	}
+
+	status = 0;
+done:
+	if (fh != -1) {
+		ret = close(fh);
+		if (ret == -1) {
+			DEBUG(DEBUG_ERR,("close failed: %s\n", strerror(errno)));
+		}
+	}
+
+	DEBUG(DEBUG_ERR,("Database backed up to %s\n", argv[1]));
+
+	talloc_free(tmp_ctx);
+	return status;
+}
+
+/*
+ * restore a database from a file 
+ */
+static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA outdata;
+	TDB_DATA data;
+	struct db_file_header dbhdr;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_node_map *nodemap=NULL;
+	struct ctdb_vnn_map *vnnmap=NULL;
+	int i, fh;
+	struct ctdb_control_wipe_database w;
+	uint32_t *nodes;
+	uint32_t generation;
+	struct tm *tm;
+	char tbuf[100];
+	char *dbname;
+
+	if (argc < 1 || argc > 2) {
+		DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+		return -1;
+	}
+
+	fh = open(argv[0], O_RDONLY);
+	if (fh == -1) {
+		DEBUG(DEBUG_ERR,("Failed to open file '%s'\n", argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	read(fh, &dbhdr, sizeof(dbhdr));
+	if (dbhdr.version != DB_VERSION) {
+		DEBUG(DEBUG_ERR,("Invalid version of database dump. File is version %lu but expected version was %u\n", dbhdr.version, DB_VERSION));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	dbname = discard_const(dbhdr.name);
+	if (argc == 2) {
+		dbname = discard_const(argv[1]);
+	}
+
+	outdata.dsize = dbhdr.size;
+	outdata.dptr = talloc_size(tmp_ctx, outdata.dsize);
+	if (outdata.dptr == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to allocate data of size '%lu'\n", dbhdr.size));
+		close(fh);
+		talloc_free(tmp_ctx);
+		return -1;
+	}		
+	read(fh, outdata.dptr, outdata.dsize);
+	close(fh);
+
+	tm = localtime(&dbhdr.timestamp);
+	strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
+	printf("Restoring database '%s' from backup @ %s\n",
+		dbname, tbuf);
+
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), dbname, dbhdr.persistent, 0);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", dbname));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+
+	ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &vnnmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n", options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	/* freeze all nodes */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+		if (ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE,
+					nodes, i,
+					TIMELIMIT(),
+					false, tdb_null,
+					NULL, NULL,
+					NULL) != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to freeze nodes.\n"));
+			ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+	}
+
+	generation = vnnmap->generation;
+	data.dptr = (void *)&generation;
+	data.dsize = sizeof(generation);
+
+	/* start a cluster wide transaction */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_START,
+					nodes, 0,
+					TIMELIMIT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to start cluster wide transactions.\n"));
+		return -1;
+	}
+
+
+	w.db_id = ctdb_db->db_id;
+	w.transaction_id = generation;
+
+	data.dptr = (void *)&w;
+	data.dsize = sizeof(w);
+
+	/* wipe all the remote databases. */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_WIPE_DATABASE,
+					nodes, 0,
+					TIMELIMIT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to wipe database.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	
+	/* push the database */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_PUSH_DB,
+					nodes, 0,
+					TIMELIMIT(), false, outdata,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to push database.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	data.dptr = (void *)&ctdb_db->db_id;
+	data.dsize = sizeof(ctdb_db->db_id);
+
+	/* mark the database as healthy */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_DB_SET_HEALTHY,
+					nodes, 0,
+					TIMELIMIT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to mark database as healthy.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	data.dptr = (void *)&generation;
+	data.dsize = sizeof(generation);
+
+	/* commit all the changes */
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_COMMIT,
+					nodes, 0,
+					TIMELIMIT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to commit databases.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	/* thaw all nodes */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_THAW,
+					nodes, 0,
+					TIMELIMIT(),
+					false, tdb_null,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to thaw nodes.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+ * dump a database backup from a file
+ */
+static int control_dumpdbbackup(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA outdata;
+	struct db_file_header dbhdr;
+	int i, fh;
+	struct tm *tm;
+	char tbuf[100];
+	struct ctdb_rec_data *rec = NULL;
+	struct ctdb_marshall_buffer *m;
+
+	if (argc != 1) {
+		DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+		return -1;
+	}
+
+	fh = open(argv[0], O_RDONLY);
+	if (fh == -1) {
+		DEBUG(DEBUG_ERR,("Failed to open file '%s'\n", argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	read(fh, &dbhdr, sizeof(dbhdr));
+	if (dbhdr.version != DB_VERSION) {
+		DEBUG(DEBUG_ERR,("Invalid version of database dump. File is version %lu but expected version was %u\n", dbhdr.version, DB_VERSION));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	outdata.dsize = dbhdr.size;
+	outdata.dptr = talloc_size(tmp_ctx, outdata.dsize);
+	if (outdata.dptr == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to allocate data of size '%lu'\n", dbhdr.size));
+		close(fh);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	read(fh, outdata.dptr, outdata.dsize);
+	close(fh);
+	m = (struct ctdb_marshall_buffer *)outdata.dptr;
+
+	tm = localtime(&dbhdr.timestamp);
+	strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
+	printf("Backup of database name:'%s' dbid:0x%x08x from @ %s\n",
+		dbhdr.name, m->db_id, tbuf);
+
+	for (i=0; i < m->count; i++) {
+		uint32_t reqid = 0;
+		TDB_DATA key, data;
+
+		/* we do not want the header splitted, so we pass NULL*/
+		rec = ctdb_marshall_loop_next(m, rec, &reqid,
+					      NULL, &key, &data);
+
+		ctdb_dumpdb_record(ctdb, key, data, stdout);
+	}
+
+	printf("Dumped %d records\n", i);
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+ * wipe a database from a file
+ */
+static int control_wipedb(struct ctdb_context *ctdb, int argc,
+			  const char **argv)
+{
+	int ret;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	TDB_DATA data;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_node_map *nodemap = NULL;
+	struct ctdb_vnn_map *vnnmap = NULL;
+	int i;
+	struct ctdb_control_wipe_database w;
+	uint32_t *nodes;
+	uint32_t generation;
+	struct ctdb_dbid_map *dbmap = NULL;
+
+	if (argc != 1) {
+		DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+		return -1;
+	}
+
+	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx,
+				 &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n",
+				  options.pnn));
+		return ret;
+	}
+
+	for(i=0;i<dbmap->num;i++){
+		const char *name;
+
+		ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn,
+				    dbmap->dbs[i].dbid, tmp_ctx, &name);
+		if(!strcmp(argv[0], name)){
+			talloc_free(discard_const(name));
+			break;
+		}
+		talloc_free(discard_const(name));
+	}
+	if (i == dbmap->num) {
+		DEBUG(DEBUG_ERR, ("No database with name '%s' found\n",
+				  argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, 0);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR, ("Unable to attach to database '%s'\n",
+				  argv[0]));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb,
+				   &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n",
+				  options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx,
+				  &vnnmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n",
+				  options.pnn));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	/* freeze all nodes */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+		ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE,
+						nodes, i,
+						TIMELIMIT(),
+						false, tdb_null,
+						NULL, NULL,
+						NULL);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to freeze nodes.\n"));
+			ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn,
+					     CTDB_RECOVERY_ACTIVE);
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+	}
+
+	generation = vnnmap->generation;
+	data.dptr = (void *)&generation;
+	data.dsize = sizeof(generation);
+
+	/* start a cluster wide transaction */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_START,
+					nodes, 0,
+					TIMELIMIT(), false, data,
+					NULL, NULL,
+					NULL);
+	if (ret!= 0) {
+		DEBUG(DEBUG_ERR, ("Unable to start cluster wide "
+				  "transactions.\n"));
+		return -1;
+	}
+
+	w.db_id = ctdb_db->db_id;
+	w.transaction_id = generation;
+
+	data.dptr = (void *)&w;
+	data.dsize = sizeof(w);
+
+	/* wipe all the remote databases. */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_WIPE_DATABASE,
+					nodes, 0,
+					TIMELIMIT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to wipe database.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	data.dptr = (void *)&ctdb_db->db_id;
+	data.dsize = sizeof(ctdb_db->db_id);
+
+	/* mark the database as healthy */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_DB_SET_HEALTHY,
+					nodes, 0,
+					TIMELIMIT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Failed to mark database as healthy.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	data.dptr = (void *)&generation;
+	data.dsize = sizeof(generation);
+
+	/* commit all the changes */
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_COMMIT,
+					nodes, 0,
+					TIMELIMIT(), false, data,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to commit databases.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	/* thaw all nodes */
+	nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+	if (ctdb_client_async_control(ctdb, CTDB_CONTROL_THAW,
+					nodes, 0,
+					TIMELIMIT(),
+					false, tdb_null,
+					NULL, NULL,
+					NULL) != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to thaw nodes.\n"));
+		ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	DEBUG(DEBUG_ERR, ("Database wiped.\n"));
+
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  dump memory usage
+ */
+static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	TDB_DATA data;
+	int ret;
+	int32_t res;
+	char *errmsg;
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+	ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_DUMP_MEMORY,
+			   0, tdb_null, tmp_ctx, &data, &res, NULL, &errmsg);
+	if (ret != 0 || res != 0) {
+		DEBUG(DEBUG_ERR,("Failed to dump memory - %s\n", errmsg));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	write(1, data.dptr, data.dsize);
+	talloc_free(tmp_ctx);
+	return 0;
+}
+
+/*
+  handler for memory dumps
+*/
+static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	write(1, data.dptr, data.dsize);
+	exit(0);
+}
+
+/*
+  dump memory usage on the recovery daemon
+ */
+static int control_rddumpmemory(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int ret;
+	TDB_DATA data;
+	struct rd_memdump_reply rd;
+
+	rd.pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+	if (rd.pnn == -1) {
+		DEBUG(DEBUG_ERR, ("Failed to get pnn of local node\n"));
+		return -1;
+	}
+	rd.srvid = getpid();
+
+	/* register a message port for receiveing the reply so that we
+	   can receive the reply
+	*/
+	ctdb_client_set_message_handler(ctdb, rd.srvid, mem_dump_handler, NULL);
+
+
+	data.dptr = (uint8_t *)&rd;
+	data.dsize = sizeof(rd);
+
+	ret = ctdb_client_send_message(ctdb, options.pnn, CTDB_SRVID_MEM_DUMP, data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send memdump request message to %u\n", options.pnn));
+		return -1;
+	}
+
+	/* this loop will terminate when we have received the reply */
+	while (1) {	
+		event_loop_once(ctdb->ev);
+	}
+
+	return 0;
+}
+
+/*
+  send a message to a srvid
+ */
+static int control_msgsend(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	unsigned long srvid;
+	int ret;
+	TDB_DATA data;
+
+	if (argc < 2) {
+		usage();
+	}
+
+	srvid      = strtoul(argv[0], NULL, 0);
+
+	data.dptr = (uint8_t *)discard_const(argv[1]);
+	data.dsize= strlen(argv[1]);
+
+	ret = ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, srvid, data);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,("Failed to send memdump request message to %u\n", options.pnn));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  handler for msglisten
+*/
+static void msglisten_handler(struct ctdb_context *ctdb, uint64_t srvid, 
+			     TDB_DATA data, void *private_data)
+{
+	int i;
+
+	printf("Message received: ");
+	for (i=0;i<data.dsize;i++) {
+		printf("%c", data.dptr[i]);
+	}
+	printf("\n");
+}
+
+/*
+  listen for messages on a messageport
+ */
+static int control_msglisten(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	uint64_t srvid;
+
+	srvid = getpid();
+
+	/* register a message port and listen for messages
+	*/
+	ctdb_client_set_message_handler(ctdb, srvid, msglisten_handler, NULL);
+	printf("Listening for messages on srvid:%d\n", (int)srvid);
+
+	while (1) {	
+		event_loop_once(ctdb->ev);
+	}
+
+	return 0;
+}
+
+/*
+  list all nodes in the cluster
+  we parse the nodes file directly
+ */
+static int control_listnodes(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	struct pnn_node *pnn_nodes;
+	struct pnn_node *pnn_node;
+
+	pnn_nodes = read_nodes_file(mem_ctx);
+	if (pnn_nodes == NULL) {
+		DEBUG(DEBUG_ERR,("Failed to read nodes file\n"));
+		talloc_free(mem_ctx);
+		return -1;
+	}
+
+	for(pnn_node=pnn_nodes;pnn_node;pnn_node=pnn_node->next) {
+		ctdb_sock_addr addr;
+		if (parse_ip(pnn_node->addr, NULL, 63999, &addr) == 0) {
+			DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s' in nodes file\n", pnn_node->addr));
+			talloc_free(mem_ctx);
+			return -1;
+		}
+		if (options.machinereadable){
+			printf(":%d:%s:\n", pnn_node->pnn, pnn_node->addr);
+		} else {
+			printf("%s\n", pnn_node->addr);
+		}
+	}
+	talloc_free(mem_ctx);
+
+	return 0;
+}
+
+/*
+  reload the nodes file on the local node
+ */
+static int control_reload_nodes_file(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	int i, ret;
+	int mypnn;
+	struct ctdb_node_map *nodemap=NULL;
+
+	mypnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+	if (mypnn == -1) {
+		DEBUG(DEBUG_ERR, ("Failed to read pnn of local node\n"));
+		return -1;
+	}
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		return ret;
+	}
+
+	/* reload the nodes file on all remote nodes */
+	for (i=0;i<nodemap->num;i++) {
+		if (nodemap->nodes[i].pnn == mypnn) {
+			continue;
+		}
+		DEBUG(DEBUG_NOTICE, ("Reloading nodes file on node %u\n", nodemap->nodes[i].pnn));
+		ret = ctdb_ctrl_reload_nodes_file(ctdb, TIMELIMIT(),
+			nodemap->nodes[i].pnn);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually!\n", nodemap->nodes[i].pnn));
+		}
+	}
+
+	/* reload the nodes file on the local node */
+	DEBUG(DEBUG_NOTICE, ("Reloading nodes file on node %u\n", mypnn));
+	ret = ctdb_ctrl_reload_nodes_file(ctdb, TIMELIMIT(), mypnn);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually!\n", mypnn));
+	}
+
+	/* initiate a recovery */
+	control_recover(ctdb, argc, argv);
+
+	return 0;
+}
+
+
+static const struct {
+	const char *name;
+	int (*fn)(struct ctdb_context *, int, const char **);
+	bool auto_all;
+	bool without_daemon; /* can be run without daemon running ? */
+	const char *msg;
+	const char *args;
+} ctdb_commands[] = {
+#ifdef CTDB_VERS
+	{ "version",         control_version,           true,	false,  "show version of ctdb" },
+#endif
+	{ "status",          control_status,            true,	false,  "show node status" },
+	{ "uptime",          control_uptime,            true,	false,  "show node uptime" },
+	{ "ping",            control_ping,              true,	false,  "ping all nodes" },
+	{ "getvar",          control_getvar,            true,	false,  "get a tunable variable",               "<name>"},
+	{ "setvar",          control_setvar,            true,	false,  "set a tunable variable",               "<name> <value>"},
+	{ "listvars",        control_listvars,          true,	false,  "list tunable variables"},
+	{ "statistics",      control_statistics,        false,	false, "show statistics" },
+	{ "statisticsreset", control_statistics_reset,  true,	false,  "reset statistics"},
+	{ "stats",           control_stats,             false,	false,  "show rolling statistics", "[number of history records]" },
+	{ "ip",              control_ip,                false,	false,  "show which public ip's that ctdb manages" },
+	{ "ipinfo",          control_ipinfo,            true,	false,  "show details about a public ip that ctdb manages", "<ip>" },
+	{ "ifaces",          control_ifaces,            true,	false,  "show which interfaces that ctdb manages" },
+	{ "setifacelink",    control_setifacelink,      true,	false,  "set interface link status", "<iface> <status>" },
+	{ "process-exists",  control_process_exists,    true,	false,  "check if a process exists on a node",  "<pid>"},
+	{ "getdbmap",        control_getdbmap,          true,	false,  "show the database map" },
+	{ "getdbstatus",     control_getdbstatus,       true,	false,  "show the status of a database", "<dbname>" },
+	{ "catdb",           control_catdb,             true,	false,  "dump a ctdb database" ,                     "<dbname>"},
+	{ "cattdb",          control_cattdb,            true,	false,  "dump a local tdb database" ,                     "<dbname>"},
+	{ "getmonmode",      control_getmonmode,        true,	false,  "show monitoring mode" },
+	{ "getcapabilities", control_getcapabilities,   true,	false,  "show node capabilities" },
+	{ "pnn",             control_pnn,               true,	false,  "show the pnn of the currnet node" },
+	{ "lvs",             control_lvs,               true,	false,  "show lvs configuration" },
+	{ "lvsmaster",       control_lvsmaster,         true,	false,  "show which node is the lvs master" },
+	{ "disablemonitor",      control_disable_monmode,true,	false,  "set monitoring mode to DISABLE" },
+	{ "enablemonitor",      control_enable_monmode, true,	false,  "set monitoring mode to ACTIVE" },
+	{ "setdebug",        control_setdebug,          true,	false,  "set debug level",                      "<EMERG|ALERT|CRIT|ERR|WARNING|NOTICE|INFO|DEBUG>" },
+	{ "getdebug",        control_getdebug,          true,	false,  "get debug level" },
+	{ "getlog",          control_getlog,            true,	false,  "get the log data from the in memory ringbuffer", "<level>" },
+	{ "clearlog",          control_clearlog,        true,	false,  "clear the log data from the in memory ringbuffer" },
+	{ "attach",          control_attach,            true,	false,  "attach to a database",                 "<dbname> [persistent]" },
+	{ "dumpmemory",      control_dumpmemory,        true,	false,  "dump memory map to stdout" },
+	{ "rddumpmemory",    control_rddumpmemory,      true,	false,  "dump memory map from the recovery daemon to stdout" },
+	{ "getpid",          control_getpid,            true,	false,  "get ctdbd process ID" },
+	{ "disable",         control_disable,           true,	false,  "disable a nodes public IP" },
+	{ "enable",          control_enable,            true,	false,  "enable a nodes public IP" },
+	{ "stop",            control_stop,              true,	false,  "stop a node" },
+	{ "continue",        control_continue,          true,	false,  "re-start a stopped node" },
+	{ "ban",             control_ban,               true,	false,  "ban a node from the cluster",          "<bantime|0>"},
+	{ "unban",           control_unban,             true,	false,  "unban a node" },
+	{ "showban",         control_showban,           true,	false,  "show ban information"},
+	{ "shutdown",        control_shutdown,          true,	false,  "shutdown ctdbd" },
+	{ "recover",         control_recover,           true,	false,  "force recovery" },
+	{ "sync", 	     control_ipreallocate,      true,	false,  "wait until ctdbd has synced all state changes" },
+	{ "ipreallocate",    control_ipreallocate,      true,	false,  "force the recovery daemon to perform a ip reallocation procedure" },
+	{ "thaw",            control_thaw,              true,	false,  "thaw databases", "[priority:1-3]" },
+	{ "isnotrecmaster",  control_isnotrecmaster,    false,	false,  "check if the local node is recmaster or not" },
+	{ "killtcp",         kill_tcp,                  false,	false, "kill a tcp connection.", "<srcip:port> <dstip:port>" },
+	{ "gratiousarp",     control_gratious_arp,      false,	false, "send a gratious arp", "<ip> <interface>" },
+	{ "tickle",          tickle_tcp,                false,	false, "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
+	{ "gettickles",      control_get_tickles,       false,	false, "get the list of tickles registered for this ip", "<ip> [<port>]" },
+	{ "addtickle",       control_add_tickle,        false,	false, "add a tickle for this ip", "<ip>:<port> <ip>:<port>" },
+
+	{ "deltickle",       control_del_tickle,        false,	false, "delete a tickle from this ip", "<ip>:<port> <ip>:<port>" },
+
+	{ "regsrvid",        regsrvid,			false,	false, "register a server id", "<pnn> <type> <id>" },
+	{ "unregsrvid",      unregsrvid,		false,	false, "unregister a server id", "<pnn> <type> <id>" },
+	{ "chksrvid",        chksrvid,			false,	false, "check if a server id exists", "<pnn> <type> <id>" },
+	{ "getsrvids",       getsrvids,			false,	false, "get a list of all server ids"},
+	{ "vacuum",          ctdb_vacuum,		false,	false, "vacuum the databases of empty records", "[max_records]"},
+	{ "repack",          ctdb_repack,		false,	false, "repack all databases", "[max_freelist]"},
+	{ "listnodes",       control_listnodes,		false,	true, "list all nodes in the cluster"},
+	{ "reloadnodes",     control_reload_nodes_file,	false,	false, "reload the nodes file and restart the transport on all nodes"},
+	{ "moveip",          control_moveip,		false,	false, "move/failover an ip address to another node", "<ip> <node>"},
+	{ "addip",           control_addip,		true,	false, "add a ip address to a node", "<ip/mask> <iface>"},
+	{ "delip",           control_delip,		false,	false, "delete an ip address from a node", "<ip>"},
+	{ "eventscript",     control_eventscript,	true,	false, "run the eventscript with the given parameters on a node", "<arguments>"},
+	{ "backupdb",        control_backupdb,          false,	false, "backup the database into a file.", "<database> <file>"},
+	{ "restoredb",        control_restoredb,        false,	false, "restore the database from a file.", "<file> [dbname]"},
+	{ "dumpdbbackup",    control_dumpdbbackup,      false,	true,  "dump database backup from a file.", "<file>"},
+	{ "wipedb",           control_wipedb,        false,	false, "wipe the contents of a database.", "<dbname>"},
+	{ "recmaster",        control_recmaster,        false,	false, "show the pnn for the recovery master."},
+	{ "scriptstatus",    control_scriptstatus,  false,	false, "show the status of the monitoring scripts (or all scripts)", "[all]"},
+	{ "enablescript",     control_enablescript,  false,	false, "enable an eventscript", "<script>"},
+	{ "disablescript",    control_disablescript,  false,	false, "disable an eventscript", "<script>"},
+	{ "natgwlist",        control_natgwlist,        false,	false, "show the nodes belonging to this natgw configuration"},
+	{ "xpnn",             control_xpnn,             true,	true,  "find the pnn of the local node without talking to the daemon (unreliable)" },
+	{ "getreclock",       control_getreclock,	false,	false, "Show the reclock file of a node"},
+	{ "setreclock",       control_setreclock,	false,	false, "Set/clear the reclock file of a node", "[filename]"},
+	{ "setnatgwstate",    control_setnatgwstate,	false,	false, "Set NATGW state to on/off", "{on|off}"},
+	{ "setlmasterrole",   control_setlmasterrole,	false,	false, "Set LMASTER role to on/off", "{on|off}"},
+	{ "setrecmasterrole", control_setrecmasterrole,	false,	false, "Set RECMASTER role to on/off", "{on|off}"},
+	{ "setdbprio",        control_setdbprio,	false,	false, "Set DB priority", "<dbid> <prio:1-3>"},
+	{ "getdbprio",        control_getdbprio,	false,	false, "Get DB priority", "<dbid>"},
+	{ "setdbreadonly",    control_setdbreadonly,	false,	false, "Set DB readonly capable", "<dbid>"},
+	{ "msglisten",        control_msglisten,	false,	false, "Listen on a srvid port for messages", "<msg srvid>"},
+	{ "msgsend",          control_msgsend,	false,	false, "Send a message to srvid", "<srvid> <message>"},
+	{ "sync", 	     control_ipreallocate,      false,	false,  "wait until ctdbd has synced all state changes" },
+	{ "pfetch", 	     control_pfetch,      	false,	false,  "fetch a record from a persistent database", "<db> <key> [<file>]" },
+	{ "pstore", 	     control_pstore,      	false,	false,  "write a record to a persistent database", "<db> <key> <file containing record>" },
+	{ "tfetch", 	     control_tfetch,      	false,	true,  "fetch a record from a [c]tdb-file", "<tdb-file> <key> [<file>]" },
+	{ "readkey", 	     control_readkey,      	true,	false,  "read the content off a database key", "<tdb-file> <key>" },
+	{ "writekey", 	     control_writekey,      	true,	false,  "write to a database key", "<tdb-file> <key> <value>" },
+	{ "checktcpport",    control_chktcpport,      	false,	true,  "check if a service is bound to a specific tcp port or not", "<port>" },
+};
+
+/*
+  show usage message
+ */
+static void usage(void)
+{
+	int i;
+	printf(
+"Usage: ctdb [options] <control>\n" \
+"Options:\n" \
+"   -n <node>          choose node number, or 'all' (defaults to local node)\n"
+"   -Y                 generate machinereadable output\n"
+"   -v                 generate verbose output\n"
+"   -t <timelimit>     set timelimit for control in seconds (default %u)\n", options.timelimit);
+	printf("Controls:\n");
+	for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
+		printf("  %-15s %-27s  %s\n", 
+		       ctdb_commands[i].name, 
+		       ctdb_commands[i].args?ctdb_commands[i].args:"",
+		       ctdb_commands[i].msg);
+	}
+	exit(1);
+}
+
+
+static void ctdb_alarm(int sig)
+{
+	printf("Maximum runtime exceeded - exiting\n");
+	_exit(ERR_TIMEOUT);
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+	struct ctdb_context *ctdb;
+	char *nodestring = NULL;
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		POPT_CTDB_CMDLINE
+		{ "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0, "timelimit", "integer" },
+		{ "node",      'n', POPT_ARG_STRING, &nodestring, 0, "node", "integer|all" },
+		{ "machinereadable", 'Y', POPT_ARG_NONE, &options.machinereadable, 0, "enable machinereadable output", NULL },
+		{ "verbose",    'v', POPT_ARG_NONE, &options.verbose, 0, "enable verbose output", NULL },
+		{ "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0, "die if runtime exceeds this limit (in seconds)", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	const char **extra_argv;
+	int extra_argc = 0;
+	int ret=-1, i;
+	poptContext pc;
+	struct event_context *ev;
+	const char *control;
+
+	setlinebuf(stdout);
+	
+	/* set some defaults */
+	options.maxruntime = 0;
+	options.timelimit = 3;
+	options.pnn = CTDB_CURRENT_NODE;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			DEBUG(DEBUG_ERR, ("Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt)));
+			exit(1);
+		}
+	}
+
+	/* setup the remaining options for the main program to use */
+	extra_argv = poptGetArgs(pc);
+	if (extra_argv) {
+		extra_argv++;
+		while (extra_argv[extra_argc]) extra_argc++;
+	}
+
+	if (extra_argc < 1) {
+		usage();
+	}
+
+	if (options.maxruntime == 0) {
+		const char *ctdb_timeout;
+		ctdb_timeout = getenv("CTDB_TIMEOUT");
+		if (ctdb_timeout != NULL) {
+			options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
+		} else {
+			/* default timeout is 120 seconds */
+			options.maxruntime = 120;
+		}
+	}
+
+	signal(SIGALRM, ctdb_alarm);
+	alarm(options.maxruntime);
+
+	/* setup the node number to contact */
+	if (nodestring != NULL) {
+		if (strcmp(nodestring, "all") == 0) {
+			options.pnn = CTDB_BROADCAST_ALL;
+		} else {
+			options.pnn = strtoul(nodestring, NULL, 0);
+		}
+	}
+
+	control = extra_argv[0];
+
+	ev = event_context_init(NULL);
+	if (!ev) {
+		DEBUG(DEBUG_ERR, ("Failed to initialize event system\n"));
+		exit(1);
+	}
+	tevent_loop_allow_nesting(ev);
+
+	for (i=0;i<ARRAY_SIZE(ctdb_commands);i++) {
+		if (strcmp(control, ctdb_commands[i].name) == 0) {
+			int j;
+
+			if (ctdb_commands[i].without_daemon == true) {
+				close(2);
+			}
+
+			/* initialise ctdb */
+			ctdb = ctdb_cmdline_client(ev, TIMELIMIT());
+
+			if (ctdb_commands[i].without_daemon == false) {
+				const char *socket_name;
+
+				if (ctdb == NULL) {
+					DEBUG(DEBUG_ERR, ("Failed to init ctdb\n"));
+					exit(1);
+				}
+
+				/* initialize a libctdb connection as well */
+				socket_name = ctdb_get_socketname(ctdb);
+				ctdb_connection = ctdb_connect(socket_name,
+						       ctdb_log_file, stderr);
+				if (ctdb_connection == NULL) {
+					fprintf(stderr, "Failed to connect to daemon from libctdb\n");
+					exit(1);
+				}				
+			
+				/* verify the node exists */
+				verify_node(ctdb);
+
+				if (options.pnn == CTDB_CURRENT_NODE) {
+					int pnn;
+					pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), options.pnn);		
+					if (pnn == -1) {
+						return -1;
+					}
+					options.pnn = pnn;
+				}
+			}
+
+			if (ctdb_commands[i].auto_all && 
+			    options.pnn == CTDB_BROADCAST_ALL) {
+				uint32_t *nodes;
+				uint32_t num_nodes;
+				ret = 0;
+
+				nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes);
+				CTDB_NO_MEMORY(ctdb, nodes);
+	
+				for (j=0;j<num_nodes;j++) {
+					options.pnn = nodes[j];
+					ret |= ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1);
+				}
+				talloc_free(nodes);
+			} else {
+				ret = ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1);
+			}
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(ctdb_commands)) {
+		DEBUG(DEBUG_ERR, ("Unknown control '%s'\n", control));
+		exit(1);
+	}
+
+	return ret;
+}

Added: branches/ctdb/squeeze-backports/tools/ctdb_diagnostics
===================================================================
--- branches/ctdb/squeeze-backports/tools/ctdb_diagnostics	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tools/ctdb_diagnostics	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,323 @@
+#!/bin/sh
+# a script to test the basic setup of a CTDB/Samba install 
+# tridge at samba.org September 2007
+# martin at meltin.net August 2010
+
+usage ()
+{
+    cat >&2 <<EOF
+Usage: ctdb_diagnostics [OPTION] ...
+  options:
+    -n <nodes>  Comma separated list of nodes to operate on
+    -c          Ignore comment lines (starting with '#') in file comparisons
+    -w          Ignore whitespace in file comparisons
+    --no-ads    Do not use commands that assume an Active Directory Server
+EOF
+    exit 1
+
+}
+
+nodes=$(ctdb listnodes -Y | cut -d: -f2)
+bad_nodes=""
+diff_opts=
+no_ads=false
+
+parse_options ()
+{
+    temp=$(getopt -n "ctdb_diagnostics" -o "n:cwh" -l no-ads,help -- "$@")
+
+    [ $? != 0 ] && usage
+
+    eval set -- "$temp"
+
+    while true ; do
+	case "$1" in
+	    -n) nodes=$(echo "$2" | sed -e 's@,@ @g') ; shift 2 ;;
+	    -c) diff_opts="${diff_opts} -I ^#.*" ; shift ;;
+	    -w) diff_opts="${diff_opts} -w" ; shift ;;
+	    --no-ads) no_ads=true ; shift ;;
+	    --) shift ; break ;;
+	    -h|--help|*) usage ;;
+	esac
+    done
+
+    [ $# -ne 0 ] && usage
+}
+
+parse_options "$@"
+
+# Use 5s ssh timeout if EXTRA_SSH_OPTS doesn't set a timeout.
+case "$EXTRA_SSH_OPTS" in
+    *ConnectTimeout=*) : ;;
+    *)
+	export EXTRA_SSH_OPTS="${EXTRA_SSH_OPTS} -o ConnectTimeout=5"
+esac
+
+# Filter nodes.  Remove any nodes we can't contact from $node and add
+# them to $bad_nodes.
+_nodes=""
+for _i in $nodes ; do
+    if onnode $_i true >/dev/null 2>&1 ; then
+	_nodes="${_nodes}${_nodes:+ }${_i}"
+    else
+	bad_nodes="${bad_nodes}${bad_nodes:+,}${_i}"
+    fi
+done
+nodes="$_nodes"
+
+nodes_comma=$(echo $nodes | sed -e 's@[[:space:]]@, at g')
+
+PATH="$PATH:/sbin:/usr/sbin:/usr/lpp/mmfs/bin"
+
+# list of config files that must exist and that we check are the same 
+# on the nodes
+CONFIG_FILES_MUST="/etc/krb5.conf /etc/hosts /etc/ctdb/nodes /etc/sysconfig/ctdb /etc/resolv.conf /etc/nsswitch.conf /etc/sysctl.conf /etc/samba/smb.conf /etc/fstab /etc/multipath.conf /etc/pam.d/system-auth /etc/sysconfig/nfs /etc/exports /etc/vsftpd/vsftpd.conf"
+
+# list of config files that may exist and should be checked that they
+# are the same on the nodes
+CONFIG_FILES_MAY="/etc/ctdb/public_addresses /etc/ctdb/static-routes"
+
+2>&1
+
+cat <<EOF
+--------------------------------------------------------------------
+ctdb_diagnostics starting. This script will gather information about
+your ctdb cluster. You should send the output of this script along
+with any ctdb or clustered Samba bug reports.
+--------------------------------------------------------------------
+EOF
+
+date
+
+error() {
+    msg="$1"
+    echo "ERROR: $msg"
+    NUM_ERRORS=`expr $NUM_ERRORS + 1`
+    echo " ERROR[$NUM_ERRORS]: $msg" >> $ERRORS
+}
+
+show_file() {
+    fname="$1"
+    echo "  ================================"
+    echo "  File: $fname"
+    echo "  `ls -l $fname 2>&1`"
+    cat "$fname" 2>&1 | sed 's/^/  /'
+    echo "  ================================"
+}
+
+show_all() {
+    echo "running $1 on nodes $nodes_comma"
+    onnode $nodes_comma "hostname; date; $1 2>&1 | sed 's/^/  /'" 2>&1
+}
+
+show_and_compare_files () {
+
+    fmt="$1" ; shift
+
+    for f ; do
+
+	first=true
+
+	for n in $nodes ; do
+
+	    if $first ; then
+		onnode $n [ -r "$f" ] || {
+		    msg=$(printf "$fmt" "$f" $n)
+		    error "$msg"
+		    continue 2;
+		}
+
+		fstf=/tmp/`basename $f`.node$n
+		onnode $n cat $f > $fstf 2>&1
+
+		echo "  ================================"
+		echo "  File (on node $n): $f"
+		echo "  `onnode $n ls -l $f 2>&1`"
+		cat "$fstf" | sed 's/^/  /'
+		echo "  ================================"
+		first=false
+	    else
+		echo "Testing for same config file $f on node $n"
+		tmpf=/tmp/`basename $f`.node$n
+		onnode $n cat $f > $tmpf 2>&1
+		diff $diff_opts $fstf $tmpf >/dev/null 2>&1 || {
+		    error "File $f is different on node $n"
+		    diff -u $diff_opts $fstf $tmpf
+		}
+		rm -f $tmpf
+	    fi
+	done
+
+	rm -f $fstf
+    done
+}
+
+ERRORS="/tmp/diag_err.$$"
+NUM_ERRORS=0
+
+cat <<EOF
+Diagnosis started on these nodes:
+$nodes_comma
+EOF
+
+if [ -n "$bad_nodes" ] ; then
+    cat <<EOF
+
+NOT RUNNING DIAGNOSTICS on these uncontactable nodes:
+$bad_nodes
+EOF
+
+fi
+
+cat <<EOF
+
+For reference, here is the nodes file on the current node...
+EOF
+
+show_file /etc/ctdb/nodes
+
+cat <<EOF
+--------------------------------------------------------------------
+Comping critical config files on nodes $nodes_comma
+EOF
+
+show_and_compare_files \
+    "%s is missing on node %d" \
+    $CONFIG_FILES_MUST
+
+show_and_compare_files \
+    "Optional file %s is not present on node %d" \
+    $CONFIG_FILES_MAY
+
+cat <<EOF
+--------------------------------------------------------------------
+Checking for clock drift
+EOF
+t=`date +%s`
+for i in $nodes; do
+    t2=`onnode $i date +%s`
+    d=`expr $t2 - $t`
+    if [ $d -gt 30 -o $d -lt -30 ]; then
+	error "time on node $i differs by $d seconds"
+    fi
+done
+
+cat <<EOF
+--------------------------------------------------------------------
+Showing software versions
+EOF
+show_all "uname -a"
+[ -x /bin/rpm ] && {
+    show_all "rpm -qa | egrep 'samba|ctdb|gpfs'"
+}
+[ -x /usr/bin/dpkg-query ] && {
+    show_all "/usr/bin/dpkg-query --show 'ctdb'"
+    show_all "/usr/bin/dpkg-query --show 'samba'"
+    #show_all "/usr/bin/dpkg-query --show 'gpfs'"
+}
+
+
+cat <<EOF
+--------------------------------------------------------------------
+Showing ctdb status and recent log entries
+EOF
+show_all "ctdb status; ctdb ip"
+show_all "ctdb statistics"
+show_all "ctdb uptime"
+
+echo "Showing log.ctdb"
+show_all "test -f /var/log/log.ctdb && tail -100 /var/log/log.ctdb"
+
+echo "Showing log.ctdb"
+show_all "test -f /var/log/log.ctdb && tail -100 /var/log/log.ctdb"
+
+show_all "tail -200 /var/log/messages"
+show_all "tail -200 /etc/ctdb/state/vacuum.log"
+show_all "ls -lRs /var/ctdb"
+show_all "ls -lRs /etc/ctdb"
+
+
+cat <<EOF
+--------------------------------------------------------------------
+Showing system and process status
+EOF
+show_all "df"
+show_all "df -i"
+show_all "mount"
+show_all "w"
+show_all "ps axfwu"
+show_all "dmesg"
+show_all "/sbin/lspci"
+show_all "dmidecode"
+show_all "cat /proc/partitions"
+show_all "cat /proc/cpuinfo"
+show_all "cat /proc/scsi/scsi"
+show_all "/sbin/ifconfig -a"
+show_all "/sbin/ifconfig -a"
+show_all "/sbin/ip addr list"
+show_all "/sbin/route -n"
+show_all "netstat -s"
+show_all "free"
+show_all "crontab -l"
+show_all "sysctl -a"
+show_all "iptables -L -n"
+show_all "iptables -L -n -t nat"
+show_all "/usr/sbin/rpcinfo -p"
+show_all "/usr/sbin/showmount -a"
+show_all "/usr/sbin/showmount -e"
+show_all "/usr/sbin/nfsstat -v"
+[ -x /sbin/multipath ] && {
+    show_all "/sbin/multipath -ll"
+}
+[ -x /sbin/chkconfig ] && {
+    show_all "/sbin/chkconfig --list"
+}
+[ -x /usr/sbin/getenforce ] && {
+    show_all "/usr/sbin/getenforce"
+}
+[ -d /proc/net/bonding ] && {
+    for f in /proc/net/bonding/*; do
+	show_all "cat $f"
+    done
+}
+
+cat <<EOF
+--------------------------------------------------------------------
+Showing Samba status
+EOF
+show_all "smbstatus -n -B"
+if $no_ads ; then
+    echo
+    echo "Skipping \"net ads testjoin\" as requested"
+    echo
+else
+    show_all "net ads testjoin"
+fi
+show_all "net conf list"
+show_all "lsof -n | grep smbd"
+show_all "lsof -n | grep ctdbd"
+show_all "netstat -tan"
+if $no_ads ; then
+    echo
+    echo "Skipping \"net ads info\" as requested"
+    echo
+else
+    show_all "net ads info"
+fi
+show_all "date"
+show_all "smbclient -U% -L 127.0.0.1"
+WORKGROUP=`testparm -s --parameter-name=WORKGROUP 2> /dev/null`
+show_all id "$WORKGROUP/Administrator"
+show_all "wbinfo -p"
+show_all "wbinfo --online-status"
+show_all "smbd -b"
+
+date
+echo "Diagnostics finished with $NUM_ERRORS errors"
+
+[ -r $ERRORS ] && {
+    cat $ERRORS
+    rm -f $ERRORS
+}
+exit $NUM_ERRORS
+


Property changes on: branches/ctdb/squeeze-backports/tools/ctdb_diagnostics
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/tools/ctdb_vacuum.c
===================================================================
--- branches/ctdb/squeeze-backports/tools/ctdb_vacuum.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tools/ctdb_vacuum.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,640 @@
+/* 
+   ctdb control tool - database vacuum 
+
+   Copyright (C) Andrew Tridgell  2008
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/tevent/tevent.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "../include/ctdb_client.h"
+#include "../include/ctdb_private.h"
+#include "../common/rb_tree.h"
+#include "db_wrap.h"
+
+/* should be tunable */
+#define TIMELIMIT() timeval_current_ofs(10, 0)
+
+
+/* 
+   a list of records to possibly delete
+ */
+struct vacuum_data {
+	uint32_t vacuum_limit;
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	trbt_tree_t *delete_tree;
+	uint32_t delete_count;
+	struct ctdb_marshall_buffer **list;
+	bool traverse_error;
+	uint32_t total;
+};
+
+/* this structure contains the information for one record to be deleted */
+struct delete_record_data {
+	struct ctdb_context *ctdb;
+	struct ctdb_db_context *ctdb_db;
+	struct ctdb_ltdb_header hdr;
+	TDB_DATA key;
+};
+
+/*
+  traverse function for vacuuming
+ */
+static int vacuum_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
+{
+	struct vacuum_data *vdata = talloc_get_type(private, struct vacuum_data);
+	struct ctdb_context *ctdb = vdata->ctdb;
+	struct ctdb_db_context *ctdb_db = vdata->ctdb_db;
+	uint32_t lmaster;
+	struct ctdb_ltdb_header *hdr;
+	struct ctdb_rec_data *rec;
+	size_t old_size;
+	       
+	lmaster = ctdb_lmaster(ctdb, &key);
+	if (lmaster >= ctdb->vnn_map->size) {
+		return 0;
+	}
+
+	if (data.dsize != sizeof(struct ctdb_ltdb_header)) {
+		/* its not a deleted record */
+		return 0;
+	}
+
+	hdr = (struct ctdb_ltdb_header *)data.dptr;
+
+	if (hdr->dmaster != ctdb->pnn) {
+		return 0;
+	}
+
+
+	/* is this a records we could possibly delete? I.e.
+	   if the record is empty and also we are both lmaster
+	   and dmaster for the record we should be able to delete it
+	*/
+	if ( (lmaster == ctdb->pnn)
+	   &&( (vdata->delete_count < vdata->vacuum_limit)
+	     ||(vdata->vacuum_limit == 0) ) ){
+		uint32_t hash;
+
+		hash = ctdb_hash(&key);
+		if (trbt_lookup32(vdata->delete_tree, hash)) {
+			DEBUG(DEBUG_INFO, (__location__ " Hash collission when vacuuming, skipping this record.\n"));
+		} else {
+			struct delete_record_data *dd;
+
+			/* store key and header indexed by the key hash */
+			dd = talloc_zero(vdata->delete_tree, struct delete_record_data);
+			if (dd == NULL) {
+				DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+				return -1;
+			}
+			dd->ctdb      = ctdb;
+			dd->ctdb_db   = ctdb_db;
+			dd->key.dsize = key.dsize;
+			dd->key.dptr  = talloc_memdup(dd, key.dptr, key.dsize);
+			if (dd->key.dptr == NULL) {
+				DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+				return -1;
+			}
+
+			dd->hdr = *hdr;
+
+	
+			trbt_insert32(vdata->delete_tree, hash, dd);
+
+			vdata->delete_count++;
+		}
+	}
+
+
+	/* add the record to the blob ready to send to the nodes */
+	rec = ctdb_marshall_record(vdata->list[lmaster], ctdb->pnn, key, NULL, tdb_null);
+	if (rec == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		vdata->traverse_error = true;
+		return -1;
+	}
+	old_size = talloc_get_size(vdata->list[lmaster]);
+	vdata->list[lmaster] = talloc_realloc_size(NULL, vdata->list[lmaster], 
+						   old_size + rec->length);
+	if (vdata->list[lmaster] == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to expand\n"));
+		vdata->traverse_error = true;
+		return -1;
+	}
+	vdata->list[lmaster]->count++;
+	memcpy(old_size+(uint8_t *)vdata->list[lmaster], rec, rec->length);
+	talloc_free(rec);
+
+	vdata->total++;
+
+	/* don't gather too many records */
+	if (vdata->vacuum_limit != 0 &&
+	    vdata->total == vdata->vacuum_limit) {
+		return -1;
+	}
+
+	return 0;
+}
+
+struct delete_records_list {
+	struct ctdb_marshall_buffer *records;
+};
+
+/*
+ traverse the tree of records to delete and marshall them into
+ a blob
+*/
+static void
+delete_traverse(void *param, void *data)
+{
+	struct delete_record_data *dd = talloc_get_type(data, struct delete_record_data);
+	struct delete_records_list *recs = talloc_get_type(param, struct delete_records_list);
+	struct ctdb_rec_data *rec;
+	size_t old_size;
+
+	rec = ctdb_marshall_record(dd, recs->records->db_id, dd->key, &dd->hdr, tdb_null);
+	if (rec == NULL) {
+		DEBUG(DEBUG_ERR, (__location__ " failed to marshall record\n"));
+		return;
+	}
+
+	old_size = talloc_get_size(recs->records);
+	recs->records = talloc_realloc_size(NULL, recs->records, old_size + rec->length);
+	if (recs->records == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to expand\n"));
+		return;
+	}
+	recs->records->count++;
+	memcpy(old_size+(uint8_t *)(recs->records), rec, rec->length);
+}
+
+
+static void delete_record(void *param, void *d)
+{
+	struct delete_record_data *dd = talloc_get_type(d, struct delete_record_data);
+	struct ctdb_context *ctdb = dd->ctdb;
+	struct ctdb_db_context *ctdb_db = dd->ctdb_db;
+	uint32_t *count = (uint32_t *)param;
+	struct ctdb_ltdb_header *hdr;
+	TDB_DATA data;
+
+	/* its deleted on all other nodes - refetch, check and delete */
+	if (tdb_chainlock_nonblock(ctdb_db->ltdb->tdb, dd->key) != 0) {
+		/* the chain is busy - come back later */
+		return;
+	}
+
+	data = tdb_fetch(ctdb_db->ltdb->tdb, dd->key);
+	if (data.dptr == NULL) {
+		tdb_chainunlock(ctdb_db->ltdb->tdb, dd->key);
+		return;
+	}
+	if (data.dsize != sizeof(struct ctdb_ltdb_header)) {
+		free(data.dptr);
+		tdb_chainunlock(ctdb_db->ltdb->tdb, dd->key);
+		return;
+	}
+
+	hdr = (struct ctdb_ltdb_header *)data.dptr;
+
+	/* if we are not the lmaster and the dmaster then skip the record */
+	if (hdr->dmaster != ctdb->pnn ||
+	    ctdb_lmaster(ctdb, &(dd->key)) != ctdb->pnn ||
+	    dd->hdr.rsn != hdr->rsn) {
+		tdb_chainunlock(ctdb_db->ltdb->tdb, dd->key);
+		free(data.dptr);
+		return;
+	}
+
+	ctdb_block_signal(SIGALRM);
+	tdb_delete(ctdb_db->ltdb->tdb, dd->key);
+	ctdb_unblock_signal(SIGALRM);
+	tdb_chainunlock(ctdb_db->ltdb->tdb, dd->key);
+	free(data.dptr);
+
+	(*count)++;
+}
+
+/* vacuum one database */
+static int ctdb_vacuum_db(struct ctdb_context *ctdb, uint32_t db_id, struct ctdb_node_map *map,
+			  bool persistent, uint32_t vacuum_limit)
+{
+	struct ctdb_db_context *ctdb_db;
+	const char *name;
+	struct vacuum_data *vdata;
+	int i;
+
+	vdata = talloc_zero(ctdb, struct vacuum_data);
+	if (vdata == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		return -1;
+	}
+
+	vdata->ctdb = ctdb;
+	vdata->vacuum_limit = vacuum_limit;
+	vdata->delete_tree = trbt_create(vdata, 0);
+	if (vdata->delete_tree == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		return -1;
+	}
+
+	if (ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, db_id, vdata, &name) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get name of db 0x%x\n", db_id));
+		talloc_free(vdata);
+		return -1;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), name, persistent, 0);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to attach to database '%s'\n", name));
+		talloc_free(vdata);
+		return -1;
+	}
+	vdata->ctdb_db = ctdb_db;
+
+	/* the list needs to be of length num_nodes */
+	vdata->list = talloc_array(vdata, struct ctdb_marshall_buffer *, ctdb->vnn_map->size);
+	if (vdata->list == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+		talloc_free(vdata);
+		return -1;
+	}
+	for (i=0;i<ctdb->vnn_map->size;i++) {
+		vdata->list[i] = (struct ctdb_marshall_buffer *)
+			talloc_zero_size(vdata->list, 
+				    offsetof(struct ctdb_marshall_buffer, data));
+		if (vdata->list[i] == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+			talloc_free(vdata);
+			return -1;
+		}
+		vdata->list[i]->db_id = db_id;
+	}
+
+	/* traverse, looking for records that might be able to be vacuumed */
+	if (tdb_traverse_read(ctdb_db->ltdb->tdb, vacuum_traverse, vdata) == -1 ||
+	    vdata->traverse_error) {
+		DEBUG(DEBUG_ERR,(__location__ " Traverse error in vacuuming '%s'\n", name));
+		talloc_free(vdata);
+		return -1;		
+	}
+
+
+	for (i=0;i<ctdb->vnn_map->size;i++) {
+		if (vdata->list[i]->count == 0) {
+			continue;
+		}
+
+		/* for records where we are not the lmaster, tell the lmaster to fetch the record */
+		if (ctdb->vnn_map->map[i] != ctdb->pnn) {
+			TDB_DATA data;
+			printf("Found %u records for lmaster %u in '%s'\n", vdata->list[i]->count, i, name);
+
+			data.dsize = talloc_get_size(vdata->list[i]);
+			data.dptr  = (void *)vdata->list[i];
+			if (ctdb_client_send_message(ctdb, ctdb->vnn_map->map[i], CTDB_SRVID_VACUUM_FETCH, data) != 0) {
+				DEBUG(DEBUG_ERR,(__location__ " Failed to send vacuum fetch message to %u\n",
+					 ctdb->vnn_map->map[i]));
+				talloc_free(vdata);
+				return -1;		
+			}
+			continue;
+		}
+	}	
+
+
+	/* Process all records we can delete (if any) */
+	if (vdata->delete_count > 0) {
+		struct delete_records_list *recs;
+		TDB_DATA indata, outdata;
+		int ret;
+		int32_t res;
+		uint32_t count;
+
+		recs = talloc_zero(vdata, struct delete_records_list);
+		if (recs == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+			return -1;
+		}
+		recs->records = (struct ctdb_marshall_buffer *)
+			talloc_zero_size(vdata, 
+				    offsetof(struct ctdb_marshall_buffer, data));
+		if (recs->records == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+			return -1;
+		}
+		recs->records->db_id = db_id;
+
+		/* traverse the tree of all records we want to delete and
+		   create a blob we can send to the other nodes.
+		*/
+		trbt_traversearray32(vdata->delete_tree, 1, delete_traverse, recs);
+
+		indata.dsize = talloc_get_size(recs->records);
+		indata.dptr  = (void *)recs->records;
+
+		/* now tell all the other nodes to delete all these records
+		   (if possible)
+		 */
+		for (i=0;i<ctdb->vnn_map->size;i++) {
+			struct ctdb_marshall_buffer *records;
+			struct ctdb_rec_data *rec;
+
+			if (ctdb->vnn_map->map[i] == ctdb->pnn) {
+				/* we dont delete the records on the local node
+				   just yet
+				*/
+				continue;
+			}
+
+			ret = ctdb_control(ctdb, ctdb->vnn_map->map[i], 0,
+					CTDB_CONTROL_TRY_DELETE_RECORDS, 0,
+					indata, recs, &outdata, &res,
+					NULL, NULL);
+			if (ret != 0 || res != 0) {
+				DEBUG(DEBUG_ERR,("Failed to delete records on node %u\n", ctdb->vnn_map->map[i]));
+				exit(10);
+			}
+
+			/* outdata countains the list of records coming back
+			   from the node which the node could not delete
+			*/
+			records = (struct ctdb_marshall_buffer *)outdata.dptr;
+			rec = (struct ctdb_rec_data *)&records->data[0];
+			while (records->count-- > 1) {
+				TDB_DATA reckey, recdata;
+				struct ctdb_ltdb_header *rechdr;
+
+				reckey.dptr = &rec->data[0];
+				reckey.dsize = rec->keylen;
+				recdata.dptr = &rec->data[reckey.dsize];
+				recdata.dsize = rec->datalen;
+
+				if (recdata.dsize < sizeof(struct ctdb_ltdb_header)) {
+					DEBUG(DEBUG_CRIT,(__location__ " bad ltdb record\n"));
+					exit(10);
+				}
+				rechdr = (struct ctdb_ltdb_header *)recdata.dptr;
+				recdata.dptr += sizeof(*rechdr);
+				recdata.dsize -= sizeof(*rechdr);
+
+				/* that other node couldnt delete the record
+				   so we shouldnt delete it either.
+				   remove it from the tree.
+				*/
+				talloc_free(trbt_lookup32(vdata->delete_tree, ctdb_hash(&reckey)));
+
+				rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+			}	    
+		}
+
+
+		/* the only records remaining in the tree would be those
+		   records where all other nodes could successfully
+		   delete them, so we can now safely delete them on the
+		   lmaster as well.
+		*/
+		count = 0;
+		trbt_traversearray32(vdata->delete_tree, 1, delete_record, &count);
+		if (vdata->delete_count != 0) {
+			printf("Deleted %u records out of %u on this node from '%s'\n", count, vdata->delete_count, name);
+		}
+	}
+
+	/* this ensures we run our event queue */
+	ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+
+	talloc_free(vdata);
+
+	return 0;
+}
+
+
+/*
+  vacuum all our databases
+ */
+int ctdb_vacuum(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	struct ctdb_dbid_map *dbmap=NULL;
+	struct ctdb_node_map *nodemap=NULL;
+	int ret, i, pnn;
+	uint32_t vacuum_limit = 0;
+
+	if (argc > 0) {
+		vacuum_limit = atoi(argv[0]);
+	}
+
+	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get dbids from local node\n"));
+		return ret;
+	}
+
+	ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+		return ret;
+	}
+
+	ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &ctdb->vnn_map);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get vnnmap from local node\n"));
+		return ret;
+	}
+
+	pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE);
+	if (pnn == -1) {
+		DEBUG(DEBUG_ERR, ("Unable to get pnn from local node\n"));
+		return -1;
+	}
+	ctdb->pnn = pnn;
+
+	for (i=0;i<dbmap->num;i++) {
+		if (ctdb_vacuum_db(ctdb, dbmap->dbs[i].dbid, nodemap, 
+				   dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, vacuum_limit) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to vacuum db 0x%x\n", dbmap->dbs[i].dbid));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+struct traverse_state {
+	bool error;
+	struct tdb_context *dest_db;
+};
+
+/*
+  traverse function for repacking
+ */
+static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
+{
+	struct traverse_state *state = (struct traverse_state *)private;
+	if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
+		state->error = true;
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  repack a tdb
+ */
+static int ctdb_repack_tdb(struct tdb_context *tdb)
+{
+	struct tdb_context *tmp_db;
+	struct traverse_state state;
+
+	if (tdb_transaction_start(tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n"));
+		return -1;
+	}
+
+	tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb),
+			  TDB_INTERNAL|TDB_DISALLOW_NESTING,
+			  O_RDWR|O_CREAT, 0);
+	if (tmp_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to create tmp_db\n"));
+		tdb_transaction_cancel(tdb);
+		return -1;
+	}
+
+	state.error = false;
+	state.dest_db = tmp_db;
+
+	if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying out\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;		
+	}
+
+	if (state.error) {
+		DEBUG(DEBUG_ERR,(__location__ " Error during traversal\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	if (tdb_wipe_all(tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	state.error = false;
+	state.dest_db = tdb;
+
+	if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying back\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;		
+	}
+
+	if (state.error) {
+		DEBUG(DEBUG_ERR,(__location__ " Error during second traversal\n"));
+		tdb_transaction_cancel(tdb);
+		tdb_close(tmp_db);
+		return -1;
+	}
+
+	tdb_close(tmp_db);
+
+	if (tdb_transaction_commit(tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to commit\n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/* repack one database */
+static int ctdb_repack_db(struct ctdb_context *ctdb, uint32_t db_id, 
+			  bool persistent, uint32_t repack_limit)
+{
+	struct ctdb_db_context *ctdb_db;
+	const char *name;
+	int size;
+
+	if (ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, db_id, ctdb, &name) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get name of db 0x%x\n", db_id));
+		return -1;
+	}
+
+	ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), name, persistent, 0);
+	if (ctdb_db == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to attach to database '%s'\n", name));
+		return -1;
+	}
+
+	size = tdb_freelist_size(ctdb_db->ltdb->tdb);
+	if (size == -1) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to get freelist size for '%s'\n", name));
+		return -1;
+	}
+
+	if (size <= repack_limit) {
+		return 0;
+	}
+
+	printf("Repacking %s with %u freelist entries\n", name, size);
+
+	if (ctdb_repack_tdb(ctdb_db->ltdb->tdb) != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to repack '%s'\n", name));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+  repack all our databases
+ */
+int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+	struct ctdb_dbid_map *dbmap=NULL;
+	int ret, i;
+	/* a reasonable default limit to prevent us using too much memory */
+	uint32_t repack_limit = 10000; 
+
+	if (argc > 0) {
+		repack_limit = atoi(argv[0]);
+	}
+
+	ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &dbmap);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR, ("Unable to get dbids from local node\n"));
+		return ret;
+	}
+
+	for (i=0;i<dbmap->num;i++) {
+		if (ctdb_repack_db(ctdb, dbmap->dbs[i].dbid, 
+				   dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, repack_limit) != 0) {
+			DEBUG(DEBUG_ERR,("Failed to repack db 0x%x\n", dbmap->dbs[i].dbid));
+			return -1;
+		}
+	}
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/tools/ltdbtool.c
===================================================================
--- branches/ctdb/squeeze-backports/tools/ltdbtool.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tools/ltdbtool.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,392 @@
+/*
+ * ctdb local tdb tool
+ *
+ * Copyright (C) Gregor Beck 2011
+ * Copyright (C) Michael Adam 2011
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <ctype.h> /* isprint */
+#include <string.h> /* strstr */
+#include <fcntl.h> /* mode_t */
+#include <sys/stat.h> /* S_IRUSR */
+#include <stdint.h> /* uint32_t */
+#include <netinet/in.h> /* struct sockaddr_in */
+#include <sys/socket.h> /* struct sockaddr */
+#include <sys/param.h>  /* MIN */
+#include <tdb.h>
+#include <unistd.h> /* getopt */
+#include <errno.h>
+
+#include "ctdb_protocol.h"
+
+enum {
+	MAX_HEADER_SIZE=24,
+	OUT_MODE = S_IRUSR | S_IWUSR,
+	OUT_FLAGS = O_EXCL|O_CREAT|O_RDWR,
+};
+
+union  ltdb_header {
+	struct ctdb_ltdb_header hdr;
+	uint32_t uints[MAX_HEADER_SIZE/4];
+};
+
+static const union ltdb_header DEFAULT_HDR = {
+	.hdr.dmaster = -1,
+};
+
+static int help(const char* cmd)
+{
+	fprintf(stdout, ""
+"Usage: %s [options] <command>\n"
+"\n"
+"Options:\n"
+"   -s {0|32|64}    specify how to determine the ctdb record header size\n"
+"                   for the input database:\n"
+"                   0: no ctdb header\n"
+"                   32: ctdb header size of a 32 bit system (20 bytes)\n"
+"                   64: ctdb header size of a 64 bit system (24 bytes)\n"
+"                   default: 32 or 64 depending on the system architecture\n"
+"\n"
+"   -S <num>        the number of bytes to interpret as ctdb record header\n"
+"                   for the input database (beware!)\n"
+"\n"
+"   -o {0|32|64}    specify how to determine the ctdb record header size\n"
+"                   for the output database\n"
+"                   0: no ctdb header\n"
+"                   32: ctdb header size of a 32 bit system (20 bytes)\n"
+"                   64: ctdb header size of a 64 bit system (24 bytes)\n"
+"                   default: 32 or 64 depending on the system architecture\n"
+"\n"
+"   -O <num>        the number of bytes to interpret as ctdb record header\n"
+"                   for the output database (beware!)\n"
+"\n"
+"   -p              print header (for the dump command), defaults ot off\n"
+"\n"
+"   -h              print this help\n"
+"\n"
+"Commands:\n"
+"  help                         print this help\n"
+"  dump <db>                    dump the db to stdout\n"
+"  convert <in_db> <out_db>     convert the db\n\n", cmd);
+	return 0;
+}
+
+static int usage(const char* cmd)
+{
+	fprintf(stderr,
+		"Usage: %s dump [-p] [-s{0|32|64}] <idb>\n"
+		"       %s convert [-s{0|32|64}] [-o{0|32|64}] <idb> <odb>\n"
+		"       %s {help|-h}\n"
+		, cmd, cmd, cmd);
+	return -1;
+}
+
+static int
+ltdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT*, TDB_DATA, TDB_DATA,
+					  struct ctdb_ltdb_header*, void *),
+	      void *state, int hsize, bool skip_empty);
+
+struct write_record_ctx {
+	TDB_CONTEXT* tdb;
+	size_t hsize;
+	int tdb_store_flags;
+};
+
+static int
+write_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
+	     struct ctdb_ltdb_header* hdr,
+	     void* write_record_ctx);
+
+
+struct dump_record_ctx {
+	FILE* file;
+	void (*print_data)(FILE*, TDB_DATA);
+	void (*dump_header)(struct dump_record_ctx*, struct ctdb_ltdb_header*);
+};
+
+static int dump_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
+		       struct ctdb_ltdb_header* hdr,
+		       void* dump_record_ctx);
+static void print_data_tdbdump(FILE* file, TDB_DATA data);
+static void dump_header_full(struct dump_record_ctx*, struct ctdb_ltdb_header*);
+static void dump_header_nop(struct dump_record_ctx* c,
+			    struct ctdb_ltdb_header* h)
+{}
+
+static int dump_db(const char* iname, FILE* ofile, int hsize, bool dump_header,
+		   bool empty)
+{
+	int ret = -1;
+	TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0);
+	if (!idb) {
+		perror("tdbopen in");
+	} else {
+		struct dump_record_ctx dump_ctx = {
+			.file = ofile,
+			.print_data =  &print_data_tdbdump,
+			.dump_header = dump_header ? &dump_header_full
+			                           : &dump_header_nop,
+		};
+		ret = ltdb_traverse(idb, &dump_record, &dump_ctx, hsize, !empty);
+		tdb_close(idb);
+	}
+	return ret;
+}
+
+static int conv_db(const char* iname, const char* oname, size_t isize,
+		   size_t osize, bool keep_empty)
+{
+	int ret = -1;
+	TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0);
+	if (!idb) {
+		perror("tdbopen in");
+	} else {
+		TDB_CONTEXT* odb = tdb_open(oname, 0, TDB_DEFAULT, OUT_FLAGS, OUT_MODE);
+		if (!odb) {
+			perror("tdbopen out");
+		} else {
+			struct write_record_ctx ctx = {
+				.tdb = odb,
+				.hsize = osize,
+				.tdb_store_flags = TDB_REPLACE,
+			};
+			ret = ltdb_traverse(idb, &write_record, &ctx, isize, !keep_empty);
+			tdb_close(odb);
+		}
+		tdb_close(idb);
+	}
+	return ret;
+}
+
+static bool parse_size(size_t* size, const char* arg, bool raw) {
+	long val;
+	errno = 0;
+	val = strtol(arg, (char **) NULL, 10);
+	if (errno != 0) {
+		return false;
+	}
+	if (!raw) {
+		switch(val) {
+		case 0:
+			break;
+		case 32:
+			val = 20;
+			break;
+		case 64:
+			val = 24;
+			break;
+		default:
+			return false;
+		}
+	}
+	*size = MIN(val, MAX_HEADER_SIZE);
+	return true;
+}
+
+
+int main(int argc, char* argv[])
+{
+	size_t isize = sizeof(struct ctdb_ltdb_header);
+	size_t osize = sizeof(struct ctdb_ltdb_header);
+	bool print_header = false;
+	bool keep_empty = false;
+	int opt;
+	const char *cmd, *idb, *odb;
+
+	while ((opt = getopt(argc, argv, "s:o:S:O:ph:e")) != -1) {
+		switch (opt) {
+		case 's':
+		case 'S':
+			if (!parse_size(&isize, optarg, isupper(opt))) {
+				return usage(argv[0]);
+			}
+			break;
+		case 'o':
+		case 'O':
+			if (!parse_size(&osize, optarg, isupper(opt))) {
+				return usage(argv[0]);
+			}
+			break;
+		case 'p':
+			print_header = true;
+			break;
+		case 'e':
+			keep_empty = true;
+		case 'h':
+			return help(argv[0]);
+		default:
+			return usage(argv[0]);
+		}
+	}
+
+	if (argc - optind < 1) {
+		return usage(argv[0]);
+	}
+
+	cmd = argv[optind];
+
+	if (strcmp(cmd, "help") == 0) {
+		return help(argv[0]);
+	}
+	else if (strcmp(cmd, "dump") == 0) {
+		int ret;
+		if (argc - optind != 2) {
+			return usage(argv[0]);
+		}
+		idb = argv[optind+1];
+		ret = dump_db(idb, stdout, isize, print_header, keep_empty);
+		return (ret >= 0) ? 0 : ret;
+	}
+	else if (strcmp(cmd, "convert") == 0) {
+		int ret;
+		if (argc - optind != 3) {
+			return usage(argv[0]);
+		}
+		idb = argv[optind+1];
+		odb = argv[optind+2];
+		ret = conv_db(idb, odb, isize, osize, keep_empty);
+		return (ret >= 0) ? 0 : ret;
+	}
+
+	return usage(argv[0]);
+}
+
+struct ltdb_traverse_ctx {
+	int (*fn)(TDB_CONTEXT*,TDB_DATA,TDB_DATA,struct ctdb_ltdb_header*,void *);
+	void* state;
+	size_t hsize;
+	bool skip_empty;
+	unsigned nempty;
+};
+
+static int
+ltdb_traverse_fn(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
+		 void* ltdb_traverse_ctx)
+{
+	struct ltdb_traverse_ctx* ctx =
+		(struct ltdb_traverse_ctx*)ltdb_traverse_ctx;
+	union ltdb_header hdr = DEFAULT_HDR;
+
+	const size_t hsize = MIN(sizeof(hdr), ctx->hsize);
+	if (val.dsize < hsize) {
+		fprintf(stderr, "Value too short to contain a ctdb header: ");
+		print_data_tdbdump(stderr, key);
+		fprintf(stderr, " = ");
+		print_data_tdbdump(stderr, val);
+		fputc('\n', stderr);
+		return -1;
+	}
+	if (val.dsize == hsize && ctx->skip_empty) {
+		ctx->nempty++;
+		return 0;
+	}
+
+	memcpy(&hdr, val.dptr, hsize);
+
+	if (hdr.uints[5] != 0) {
+		fprintf(stderr, "Warning: header padding isn't zero! Wrong header size?\n");
+	}
+	val.dptr += ctx->hsize;
+	val.dsize -= ctx->hsize;
+	return ctx->fn(tdb, key, val, &hdr.hdr, ctx->state);
+}
+
+int ltdb_traverse(TDB_CONTEXT *tdb,
+		  int (*fn)(TDB_CONTEXT *,TDB_DATA,TDB_DATA,struct ctdb_ltdb_header*,void *),
+		  void *state, int hsize, bool skip_empty)
+{
+	struct ltdb_traverse_ctx ctx = {
+		.fn = fn,
+		.state = state,
+		.hsize = hsize < 0 ? sizeof(struct ctdb_ltdb_header) : hsize,
+		.skip_empty = skip_empty,
+		.nempty = 0,
+	};
+	int ret = tdb_traverse(tdb, &ltdb_traverse_fn, &ctx);
+
+	return (ret < 0) ? ret : (ret - ctx.nempty);
+}
+
+int write_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
+		 struct ctdb_ltdb_header* hdr,
+		 void* write_record_ctx)
+{
+	struct write_record_ctx* ctx
+		= (struct write_record_ctx*)write_record_ctx;
+
+	if (ctx->hsize == 0) {
+		if (tdb_store(ctx->tdb, key, val, ctx->tdb_store_flags) == -1) {
+			fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb));
+			return -1;
+		}
+	} else {
+		TDB_DATA h = {
+			.dptr = (void*)hdr,
+			.dsize = ctx->hsize,
+		};
+		if(tdb_store(ctx->tdb, key, h, ctx->tdb_store_flags) == -1) {
+			fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb));
+			return -1;
+		}
+		if(tdb_append(ctx->tdb, key, val) == -1) {
+			fprintf(stderr, "tdb_append: %s\n", tdb_errorstr(ctx->tdb));
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int dump_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
+		struct ctdb_ltdb_header* hdr,
+		void* dump_record_ctx)
+{
+	struct dump_record_ctx* ctx = (struct dump_record_ctx*)dump_record_ctx;
+
+	fprintf(ctx->file, "{\nkey(%d) = ", (int)key.dsize);
+	ctx->print_data(ctx->file, key);
+	fputc('\n', ctx->file);
+	ctx->dump_header(ctx, hdr);
+	fprintf(ctx->file, "data(%d) = ", (int)val.dsize);
+	ctx->print_data(ctx->file, val);
+	fprintf(ctx->file, "\n}\n");
+	return 0;
+}
+
+void dump_header_full(struct dump_record_ctx* c, struct ctdb_ltdb_header* h)
+{
+	fprintf(c->file, "dmaster: %d\nrsn: %llu\nflags: 0x%X\n",
+		(int)h->dmaster,
+		(unsigned long long)h->rsn, h->flags);
+}
+
+void print_data_tdbdump(FILE* file, TDB_DATA data) {
+	unsigned char *ptr = data.dptr;
+	fputc('"', file);
+	while (data.dsize--) {
+		if (isprint(*ptr) && !strchr("\"\\", *ptr)) {
+			fputc(*ptr, file);
+		} else {
+			fprintf(file, "\\%02X", *ptr);
+		}
+		ptr++;
+	}
+	fputc('"',file);
+}
+

Added: branches/ctdb/squeeze-backports/tools/onnode
===================================================================
--- branches/ctdb/squeeze-backports/tools/onnode	                        (rev 0)
+++ branches/ctdb/squeeze-backports/tools/onnode	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,396 @@
+#!/bin/bash
+
+# Run commands on CTDB nodes.
+
+# See http://ctdb.samba.org/ for more information about CTDB.
+
+# Copyright (C) Martin Schwenke  2008
+
+# Based on an earlier script by Andrew Tridgell and Ronnie Sahlberg.
+
+# Copyright (C) Andrew Tridgell  2007
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+   
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+   
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+prog=$(basename $0)
+
+usage ()
+{
+    cat >&2 <<EOF
+Usage: onnode [OPTION] ... <NODES> <COMMAND> ...
+  options:
+    -c          Run in current working directory on specified nodes.
+    -o <prefix> Save standard output from each node to file <prefix>.<ip>
+    -p          Run command in parallel on specified nodes.
+    -q          Do not print node addresses (overrides -v).
+    -n          Allow nodes to be specified by name.
+    -f          Specify nodes file, overrides CTDB_NODES_FILE.
+    -v          Print node address even for a single node.
+  <NODES>       "all", "any", "ok" (or "healthy"), "con" (or "connected"),
+                "rm" (or "recmaster"), "lvs" (or "lvsmaster"),
+                "natgw" (or "natgwlist"); or
+                a node number (0 base); or
+                a hostname (if -n is specified); or
+                list (comma separated) of <NODES>; or
+                range (hyphen separated) of node numbers.
+EOF
+    exit 1
+
+}
+
+invalid_nodespec ()
+{
+    echo "Invalid <nodespec>" >&2 ; echo >&2
+    usage
+}
+
+# Defaults.
+current=false
+parallel=false
+verbose=false
+quiet=false
+prefix=""
+names_ok=false
+
+ctdb_base="${CTDB_BASE:-/etc/ctdb}"
+
+parse_options ()
+{
+    # $POSIXLY_CORRECT means that the command passed to onnode can
+    # take options and getopt won't reorder things to make them
+    # options ot onnode.
+    local temp
+    # Not on the previous line - local returns 0!
+    temp=$(POSIXLY_CORRECT=1 getopt -n "$prog" -o "cf:hno:pqv" -l help -- "$@")
+
+    [ $? != 0 ] && usage
+
+    eval set -- "$temp"
+
+    while true ; do
+	case "$1" in
+	    -c) current=true ; shift ;;
+	    -f) CTDB_NODES_FILE="$2" ; shift 2 ;;
+	    -n) names_ok=true ; shift ;;
+	    -o) prefix="$2" ; shift 2 ;;
+	    -p) parallel=true ; shift ;;
+	    -q) quiet=true ; shift ;;
+	    -v) verbose=true ; shift ;;
+	    --) shift ; break ;;
+	    -h|--help|*) usage ;; # Shouldn't happen, so this is reasonable.
+	esac
+    done
+
+    [ $# -lt 2 ] && usage
+
+    nodespec="$1" ; shift
+    command="$@"
+}
+
+echo_nth ()
+{
+    local n="$1" ; shift
+
+    shift $n
+    local node="$1"
+
+    if [ -n "$node" -a "$node" != "#DEAD" ] ; then
+	echo $node
+    else
+	echo "${prog}: \"node ${n}\" does not exist" >&2
+	exit 1
+    fi
+}
+
+parse_nodespec ()
+{
+    # Subshell avoids hacks to restore $IFS.
+    (
+	IFS=","
+	for i in $1 ; do
+	    case "$i" in
+		*-*) seq "${i%-*}" "${i#*-}" 2>/dev/null || invalid_nodespec ;;
+		# Separate lines for readability.
+		all|any|ok|healthy|con|connected) echo "$i" ;;
+		rm|recmaster|lvs|lvsmaster|natgw|natgwlist) echo "$i" ;;
+		*)
+		    [ $i -gt -1 ] 2>/dev/null || $names_ok || invalid_nodespec
+		    echo $i
+	    esac
+	done
+    )
+}
+
+ctdb_status_output="" # cache
+get_nodes_with_status ()
+{
+    local all_nodes="$1"
+    local status="$2"
+
+    if [ -z "$ctdb_status_output" ] ; then
+	ctdb_status_output=$(ctdb -Y status 2>&1)
+	if [ $? -ne 0 ] ; then
+	    echo "${prog}: unable to get status of CTDB nodes" >&2
+	    echo "$ctdb_status_output" >&2
+	    exit 1
+	fi
+	local nl="
+"
+	ctdb_status_output="${ctdb_status_output#*${nl}}"
+    fi
+
+    (
+	local i
+	IFS="${IFS}:"
+	while IFS="" read i ; do
+
+	    set -- $i # split line on colons
+	    shift     # line starts with : so 1st field is empty
+	    local pnn="$1" ; shift
+	    local ip="$1" ; shift
+
+	    case "$status" in
+		healthy)
+		    # If any bit is not 0, don't match this address.
+		    local s
+		    for s ; do
+			[ "$s" = "0" ] || continue 2
+		    done
+		    ;;
+		connected)
+		    # If disconnected bit is not 0, don't match this address.
+		    [ "$1" = "0" ] || continue
+		    ;;
+		*)
+		    invalid_nodespec
+	    esac
+
+	    echo_nth "$pnn" $all_nodes
+	done <<<"$ctdb_status_output"
+    )
+}
+
+ctdb_props="" # cache
+get_node_with_property ()
+{
+    local all_nodes="$1"
+    local prop="$2"
+
+    local prop_node=""
+    if [ "${ctdb_props##:${prop}:}" = "$ctdb_props" ] ; then
+	# Not in cache.
+	prop_node=$(ctdb "$prop" -Y 2>/dev/null)
+	if [ $? -eq 0 ] ; then
+	    if [ "$prop" = "natgwlist" ] ; then
+		prop_node="${prop_node%% *}" # 1st word
+		if [ "$prop_node" = "-1" ] ; then
+		    # This works around natgwlist returning 0 even
+		    # when there's no natgw.
+		    prop_node=""
+		fi
+	    else
+		# We only want the first line.
+		local nl="
+"
+		prop_node="${prop_node%%${nl}*}"
+	    fi
+	else
+	    prop_node=""
+	fi
+
+	if [ -n "$prop_node" ] ; then
+	    # Add to cache.
+	    ctdb_props="${ctdb_props}${ctdb_props:+ }:${prop}:${prop_node}"
+	fi
+    else
+	# Get from cache.
+	prop_node="${ctdb_props##:${prop}:}"
+	prop_node="${prop_node%% *}"
+    fi
+
+    if [ -n "$prop_node" ] ; then
+	echo_nth "$prop_node" $all_nodes
+    else
+	echo "${prog}: No ${prop} available" >&2
+	exit 1
+    fi
+}
+
+get_any_available_node ()
+{
+    local all_nodes="$1"
+
+    # We do a recursive onnode to find which nodes are up and running.
+    local out=$($0 -pq all ctdb pnn 2>&1)
+    local line
+    while read line ; do 
+	local pnn="${line#PNN:}"
+	if [ "$pnn" != "$line" ] ; then
+	    echo_nth "$pnn" $all_nodes
+	    return 0
+	fi
+	# Else must be an error message from a down node.
+    done <<<"$out"
+    return 1
+}
+
+get_nodes ()
+{
+    local all_nodes
+
+    if [ -n "$CTDB_NODES_SOCKETS" ] ; then 
+	all_nodes="$CTDB_NODES_SOCKETS"
+    else
+	local f="${ctdb_base}/nodes"
+	if [ -n "$CTDB_NODES_FILE" ] ; then
+	    f="$CTDB_NODES_FILE"
+	    if [ ! -e "$f" -a "${f#/}" = "$f" ] ; then
+		# $f is relative, try in $ctdb_base
+		f="${ctdb_base}/${f}"
+	    fi
+	fi
+
+	if [ ! -r "$f" ] ; then
+	    echo "${prog}: unable to open nodes file  \"${f}\"" >&2
+	    exit 1
+	fi
+
+	all_nodes=$(sed -e 's@#.*@@g' -e 's@ *@@g' -e 's@^$@#DEAD@' "$f")
+    fi
+
+    local nodes=""
+    local n
+    for n in $(parse_nodespec "$1") ; do
+	[ $? != 0 ] && exit 1  # Required to catch exit in above subshell.
+	case "$n" in
+	    all)
+		echo "${all_nodes//#DEAD/}"
+		;;
+	    any)
+		get_any_available_node "$all_nodes" || exit 1
+		;;
+	    ok|healthy) 
+		get_nodes_with_status "$all_nodes" "healthy" || exit 1
+		;;
+	    con|connected) 
+		get_nodes_with_status "$all_nodes" "connected" || exit 1
+		;;
+	    rm|recmaster)
+		get_node_with_property "$all_nodes" "recmaster" || exit 1
+		;;
+	    lvs|lvsmaster)
+		get_node_with_property "$all_nodes" "lvsmaster" || exit 1
+		;;
+	    natgw|natgwlist)
+		get_node_with_property "$all_nodes" "natgwlist" || exit 1
+		;;
+	    [0-9]|[0-9][0-9]|[0-9][0-9][0-9])
+		echo_nth $n $all_nodes
+		;;
+	    *)
+		$names_ok || invalid_nodespec
+		echo $n
+	esac
+    done
+}
+
+fakessh ()
+{
+    CTDB_SOCKET="$1" sh -c "$2" 3>/dev/null
+}
+
+stdout_filter ()
+{
+    if [ -n "$prefix" ] ; then
+	cat >"${prefix}.${n//\//_}"
+    elif $verbose && $parallel ; then
+	sed -e "s@^@[$n] @"
+    else
+	cat
+    fi
+}
+
+stderr_filter ()
+{
+    if $verbose && $parallel ; then
+	sed -e "s@^@[$n] @"
+    else
+	cat
+    fi
+}
+
+######################################################################
+
+parse_options "$@"
+
+$current && command="cd $PWD && $command"
+
+ssh_opts=
+if [ -n "$CTDB_NODES_SOCKETS" ] ; then
+    SSH=fakessh
+    EXTRA_SSH_OPTS=""
+else 
+    # Could "2>/dev/null || true" but want to see errors from typos in file.
+    [ -r "${ctdb_base}/onnode.conf" ] && . "${ctdb_base}/onnode.conf"
+    [ -n "$SSH" ] || SSH=ssh
+    if [ "$SSH" = "ssh" ] ; then
+	ssh_opts="-n"
+    else
+	: # rsh? All bets are off!
+    fi
+fi
+
+######################################################################
+
+nodes=$(get_nodes "$nodespec")
+[ $? != 0 ] && exit 1   # Required to catch exit in above subshell.
+
+if $quiet ; then
+    verbose=false
+else
+    # If $nodes contains a space or a newline then assume multiple nodes.
+    nl="
+"
+    [ "$nodes" != "${nodes%[ ${nl}]*}" ] && verbose=true
+fi
+
+pids=""
+trap 'kill -TERM $pids 2>/dev/null' INT TERM
+# There's a small race here where the kill can fail if no processes
+# have been added to $pids and the script is interrupted.  However,
+# the part of the window where it matter is very small.
+retcode=0
+for n in $nodes ; do
+    set -o pipefail 2>/dev/null
+    if $parallel ; then
+	{ exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS $n "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; } &
+	pids="${pids} $!"
+    else
+	if $verbose ; then
+	    echo >&2 ; echo ">> NODE: $n <<" >&2
+	fi
+
+	{ exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS $n "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; }
+	[ $? = 0 ] || retcode=$?
+    fi
+done
+
+$parallel && {
+    for p in $pids; do
+	wait $p
+	[ $? = 0 ] || retcode=$?
+    done
+}
+
+exit $retcode


Property changes on: branches/ctdb/squeeze-backports/tools/onnode
___________________________________________________________________
Added: svn:executable
   + *

Added: branches/ctdb/squeeze-backports/utils/ping_pong/ping_pong.c
===================================================================
--- branches/ctdb/squeeze-backports/utils/ping_pong/ping_pong.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/ping_pong/ping_pong.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,209 @@
+/*
+   A ping-pong fcntl byte range lock test
+
+   Copyright (C) Andrew Tridgell 2002
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  This measures the ping-pong byte range lock latency. It is
+  especially useful on a cluster of nodes sharing a common lock
+  manager as it will give some indication of the lock managers
+  performance under stress.
+
+  tridge at samba.org, February 2002
+
+*/
+
+#define _XOPEN_SOURCE 500
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+static struct timeval tp1,tp2;
+
+static int do_reads, do_writes, use_mmap;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+/* lock a byte range in a open file */
+static int lock_range(int fd, int offset, int len)
+{
+	struct flock lock;
+
+	lock.l_type = F_WRLCK;
+	lock.l_whence = SEEK_SET;
+	lock.l_start = offset;
+	lock.l_len = len;
+	lock.l_pid = 0;
+	
+	return fcntl(fd,F_SETLKW,&lock);
+}
+
+/* unlock a byte range in a open file */
+static int unlock_range(int fd, int offset, int len)
+{
+	struct flock lock;
+
+	lock.l_type = F_UNLCK;
+	lock.l_whence = SEEK_SET;
+	lock.l_start = offset;
+	lock.l_len = len;
+	lock.l_pid = 0;
+	
+	return fcntl(fd,F_SETLKW,&lock);
+}
+
+/* run the ping pong test on fd */
+static void ping_pong(int fd, int num_locks)
+{
+	unsigned count = 0;
+	int i=0, loops=0;
+	unsigned char *val;
+	unsigned char incr=0, last_incr=0;
+	unsigned char *p = NULL;
+	int ret;
+
+	ret = ftruncate(fd, num_locks+1);
+	if (ret == -1) {
+		printf("ftruncate failed: %s\n", strerror(errno));
+		return;
+	}
+
+	if (use_mmap) {
+		p = mmap(NULL, num_locks+1, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+		if (p == MAP_FAILED) {
+			printf("mmap failed: %s\n", strerror(errno));
+			return;
+		}
+	}
+
+	val = (unsigned char *)calloc(num_locks+1, sizeof(unsigned char));
+	if (val == NULL) {
+		printf("calloc failed\n");
+		return;
+	}
+
+	start_timer();
+
+	lock_range(fd, 0, 1);
+	i = 0;
+
+	while (1) {
+		if (lock_range(fd, (i+1) % num_locks, 1) != 0) {
+			printf("lock at %d failed! - %s\n",
+			       (i+1) % num_locks, strerror(errno));
+		}
+		if (do_reads) {
+			unsigned char c;
+			if (use_mmap) {
+				c = p[i];
+			} else if (pread(fd, &c, 1, i) != 1) {
+				printf("read failed at %d\n", i);
+			}
+			incr = c - val[i];
+			val[i] = c;
+		}
+		if (do_writes) {
+			char c = val[i] + 1;
+			if (use_mmap) {
+				p[i] = c;
+			} else if (pwrite(fd, &c, 1, i) != 1) {
+				printf("write failed at %d\n", i);
+			}
+		}
+		if (unlock_range(fd, i, 1) != 0) {
+			printf("unlock at %d failed! - %s\n",
+			       i, strerror(errno));
+		}
+		i = (i+1) % num_locks;
+		count++;
+		if (loops > num_locks && incr != last_incr) {
+			last_incr = incr;
+			printf("data increment = %u\n", incr);
+			fflush(stdout);
+		}
+		if (end_timer() > 1.0) {
+			printf("%8u locks/sec\r", 
+			       (unsigned)(2*count/end_timer()));
+			fflush(stdout);
+			start_timer();
+			count=0;
+		}
+		loops++;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	char *fname;
+	int fd, num_locks;
+	int c;
+
+	while ((c = getopt(argc, argv, "rwm")) != -1) {
+		switch (c){
+		case 'w':
+			do_writes = 1;
+			break;
+		case 'r':
+			do_reads = 1;
+			break;
+		case 'm':
+			use_mmap = 1;
+			break;
+		default:
+			fprintf(stderr, "Unknown option '%c'\n", c);
+			exit(1);
+		}
+	}
+
+	argv += optind;
+	argc -= optind;
+
+	if (argc < 2) {
+		printf("ping_pong [options] <file> <num_locks>\n");
+		printf("           -r    do reads\n");
+		printf("           -w    do writes\n");
+		printf("           -m    use mmap\n");
+		exit(1);
+	}
+
+	fname = argv[0];
+	num_locks = atoi(argv[1]);
+
+	fd = open(fname, O_CREAT|O_RDWR, 0600);
+	if (fd == -1) exit(1);
+
+	ping_pong(fd, num_locks);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/utils/pmda/Install
===================================================================
--- branches/ctdb/squeeze-backports/utils/pmda/Install	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/pmda/Install	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,36 @@
+#! /bin/sh
+#
+# Copyright (c) 1997 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Install the ctdb PMDA and/or PMNS
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=ctdb
+pmda_interface=2
+
+# runs as daemon and only supports pipe IPC
+daemon_opt=true
+dso_opt=false
+pipe_opt=true
+socket_opt=false
+
+pmdaSetup
+pmdaInstall
+exit 0

Added: branches/ctdb/squeeze-backports/utils/pmda/README
===================================================================
--- branches/ctdb/squeeze-backports/utils/pmda/README	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/pmda/README	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,84 @@
+CTDB PMDA
+===========
+
+This PMDA extracts metrics from the locally running ctdbd daemon for
+export to PMCD.
+
+Note:
+	This PMDA may be remade from source and hence requires IDO (or
+	more specifically a C compiler) to be installed.
+
+	Uses of make(1) may fail (without removing or clobbering files)
+	if the C compiler cannot be found.  This is most likely to
+	happen when running the PMDA ./Install script.
+
+	The only remedial action is to install the C compiler, or
+	hand-craft changes to the Makefile.
+
+Metrics
+=======
+
+The file ./help contains descriptions for all of the metrics exported
+by this PMDA.
+
+Once the PMDA has been installed, the following command will list all
+the available metrics and their explanatory "help" text:
+
+	$ pminfo -fT ctdb
+
+Installation
+============
+
+ +  # cd $PCP_PMDAS_DIR/ctdb
+
+ +  Check that there is no clash in the Performance Metrics Domain
+    defined in ./domain.h and the other PMDAs currently in use (see
+    $PCP_PMCDCONF_PATH).  If there is, edit ./domain.h to choose another
+    domain number.
+
+ +  Then simply use
+
+	# ./Install
+
+    and choose both the "collector" and "monitor" installation
+    configuration options.
+
+    You will be prompted to choose either a daemon implementation
+    or a DSO implementation of the PMDA, and in the case of the daemon
+    variant to select an IPC method -- everything else is automated
+
+De-installation
+===============
+
+ +  Simply use
+
+	# cd $PCP_PMDAS_DIR/ctdb
+	# ./Remove
+
+Troubleshooting
+===============
+
+ +  After installing or restarting the agent, the PMCD log file
+    ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file
+    ($PCP_LOG_DIR/pmcd/pmda_ctdb.log) should be checked for any warnings
+    or errors.
+
+
+Adding a New Metric
+===================
+
+This section walks through the development task of adding a new metric to the
+CTDB PMDA.
+
+  + Define the metric in the pmns file with a unique metric id. See the pmns(4)
+    man page for details.
+
+  + Add a description of the metric to the help file.
+
+  + Taking note of the previously assigned metric id, add a new entry to the
+    metrictab structure in pmda_ctdb.c. See the pmdaInit(3) man page for
+    details.
+
+  + Ensure the counter is already a member of the ctdb_statistics structure.
+    Finally, add code to pmda_ctdb_fetch_cb() to handle fetch requests for the
+    newly defined metric.

Added: branches/ctdb/squeeze-backports/utils/pmda/Remove
===================================================================
--- branches/ctdb/squeeze-backports/utils/pmda/Remove	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/pmda/Remove	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,29 @@
+#! /bin/sh
+#
+# Copyright (c) 1997 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Remove the ctdb PMDA
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=ctdb
+
+pmdaSetup
+pmdaRemove
+exit 0

Added: branches/ctdb/squeeze-backports/utils/pmda/domain.h
===================================================================
--- branches/ctdb/squeeze-backports/utils/pmda/domain.h	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/pmda/domain.h	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,19 @@
+/* domain.h
+ *
+ * Copyright (c) 2004-2009 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define CTDB 110

Added: branches/ctdb/squeeze-backports/utils/pmda/help
===================================================================
--- branches/ctdb/squeeze-backports/utils/pmda/help	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/pmda/help	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,106 @@
+#
+# Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# ctdb PMDA help file in the ASCII format
+#
+# lines beginning with a # are ignored
+# lines beginning @ introduce a new entry of the form
+#  @ metric_name oneline-text
+#  help test goes
+#  here over multiple lines
+#  ...
+#
+# the metric_name is decoded against the default PMNS -- as a special case,
+# a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an
+# instance domain identification, and the text describes the instance domain
+#
+# blank lines before the @ line are ignored
+#
+
+@ ctdb.num_clients number of clients connected to ctdbd
+
+@ ctdb.frozen whether any databases are frozen
+
+@ ctdb.recovering whether recovery is active
+
+@ ctdb.client_packets_sent number of packets sent to all clients
+
+@ ctdb.client_packets_recv number of packets received from all clients
+
+@ ctdb.node_packets_sent number of packets sent to other nodes
+
+@ ctdb.node_packets_recv number of packets received from other nodes
+
+@ ctdb.keepalive_packets_sent number of keepalive packets sent to other nodes
+
+@ ctdb.keepalive_packets_recv number of keepalive packets received from other nodes
+
+@ ctdb.node.req_call number of node CTDB_REQ_CALL packets handled
+
+@ ctdb.node.reply_call number of node CTDB_REPLY_CALL packets handled
+
+@ ctdb.node.req_dmaster number of node CTDB_REQ_DMASTER packets handled
+
+@ ctdb.node.reply_dmaster number of node CTDB_REPLY_DMASTER packets handled
+
+@ ctdb.node.reply_error number of node CTDB_REPLY_ERROR packets handled
+
+@ ctdb.node.req_message number of node CTDB_REQ_MESSAGE packets handled
+
+@ ctdb.node.req_control number of node CTDB_REQ_CONTROL packets handled
+
+@ ctdb.node.reply_control number of node CTDB_REPLY_CONTROL packets handled
+
+@ ctdb.client.req_call number of client CTDB_REQ_CALL packets handled
+
+@ ctdb.client.req_message number of client CTDB_REQ_MESSAGE packets handled
+
+@ ctdb.client.req_control number of client CTDB_REQ_CONTROL packets handled
+
+@ ctdb.timeouts.call (counter not implemented) number of call timeouts
+
+@ ctdb.timeouts.control number of node control message request timeouts awaiting reply
+
+@ ctdb.timeouts.traverse number of database traversal timeouts
+
+@ ctdb.total_calls total number of client ctdb request calls received
+
+@ ctdb.pending_calls total number of client ctdb request calls in progress
+
+@ ctdb.lockwait_calls number of tdb chainlock lockwait calls
+
+@ ctdb.pending_lockwait_calls number of lockwait calls waiting for a lock
+
+@ ctdb.childwrite_calls number of childwrite calls
+
+@ ctdb.pending_childwrite_calls number of childwrite calls in progress
+
+@ ctdb.memory_used total size of the ctdbd null talloc pool
+
+@ ctdb.max_hop_count maximum hops performed by a CTDB_REQ_CALL packet
+
+@ ctdb.max_reclock_ctdbd maximum recovery lock latency during setrecmode
+
+@ ctdb.max_reclock_recd maximum recovery lock latency as reported by the recovery process
+
+@ ctdb.max_call_latency maximum time spent handling a client request call
+
+@ ctdb.max_lockwait_latency maximum time spent waiting for a tdb chainlock
+
+@ ctdb.max_childwrite_latency maximum time spent performing a childwrite
+
+@ ctdb.num_recoveries number of recoveries finished

Added: branches/ctdb/squeeze-backports/utils/pmda/pmda_ctdb.c
===================================================================
--- branches/ctdb/squeeze-backports/utils/pmda/pmda_ctdb.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/pmda/pmda_ctdb.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,596 @@
+/*
+ * CTDB Performance Metrics Domain Agent (PMDA) for Performance Co-Pilot (PCP)
+ *
+ * Copyright (c) 1995,2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2011 David Disseldorp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+#include <pcp/pmda.h>
+#include "../../include/includes.h"
+#include "../../lib/tevent/tevent.h"
+#include "../../include/ctdb.h"
+#include "../../include/ctdb_private.h"
+#include "../../include/ctdb_protocol.h"
+#include "domain.h"
+
+/*
+ * CTDB PMDA
+ *
+ * This PMDA connects to the locally running ctdbd daemon and pulls
+ * statistics for export via PCP. The ctdbd Unix domain socket path can be
+ * specified with the CTDB_SOCKET environment variable, otherwise the default
+ * path is used.
+ */
+
+/*
+ * All metrics supported in this PMDA - one table entry for each.
+ * The 4th field specifies the serial number of the instance domain
+ * for the metric, and must be either PM_INDOM_NULL (denoting a
+ * metric that only ever has a single value), or the serial number
+ * of one of the instance domains declared in the instance domain table
+ * (i.e. in indomtab, above).
+ */
+static pmdaMetric metrictab[] = {
+	/* num_clients */
+	{ NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,0,0,0,0,0) }, },
+	/* frozen */
+	{ NULL, { PMDA_PMID(1,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,0,0,0,0,0) }, },
+	/* recovering */
+	{ NULL, { PMDA_PMID(3,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,0,0,0,0,0) }, },
+	/* client_packets_sent */
+	{ NULL, { PMDA_PMID(4,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* client_packets_recv */
+	{ NULL, { PMDA_PMID(5,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* node_packets_sent */
+	{ NULL, { PMDA_PMID(6,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* node_packets_recv */
+	{ NULL, { PMDA_PMID(7,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* keepalive_packets_sent */
+	{ NULL, { PMDA_PMID(8,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* keepalive_packets_recv */
+	{ NULL, { PMDA_PMID(9,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* req_call */
+	{ NULL, { PMDA_PMID(10,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* reply_call */
+	{ NULL, { PMDA_PMID(10,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* req_dmaster */
+	{ NULL, { PMDA_PMID(10,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* reply_dmaster */
+	{ NULL, { PMDA_PMID(10,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* reply_error */
+	{ NULL, { PMDA_PMID(10,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* req_message */
+	{ NULL, { PMDA_PMID(10,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* req_control */
+	{ NULL, { PMDA_PMID(10,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* reply_control */
+	{ NULL, { PMDA_PMID(10,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* req_call */
+	{ NULL, { PMDA_PMID(11,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* req_message */
+	{ NULL, { PMDA_PMID(11,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* req_control */
+	{ NULL, { PMDA_PMID(11,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* call */
+	{ NULL, { PMDA_PMID(12,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,0) }, },
+	/* control */
+	{ NULL, { PMDA_PMID(12,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,0) }, },
+	/* traverse */
+	{ NULL, { PMDA_PMID(12,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,0) }, },
+	/* total_calls */
+	{ NULL, { PMDA_PMID(13,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* pending_calls */
+	{ NULL, { PMDA_PMID(14,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,0,0,0,0,0) }, },
+	/* lockwait_calls */
+	{ NULL, { PMDA_PMID(15,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* pending_lockwait_calls */
+	{ NULL, { PMDA_PMID(16,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,0,0,0,0,0) }, },
+	/* childwrite_calls */
+	{ NULL, { PMDA_PMID(17,28), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+		PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+	/* pending_childwrite_calls */
+	{ NULL, { PMDA_PMID(18,29), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,0,0,0,0,0) }, },
+	/* memory_used */
+	{ NULL, { PMDA_PMID(19,30), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, },
+	/* max_hop_count */
+	{ NULL, { PMDA_PMID(20,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,0,0,0,0,0) }, },
+	/* max_reclock_ctdbd */
+	{ NULL, { PMDA_PMID(21,32), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, },
+	/* max_reclock_recd */
+	{ NULL, { PMDA_PMID(22,33), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, },
+	/* max_call_latency */
+	{ NULL, { PMDA_PMID(23,34), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, },
+	/* max_lockwait_latency */
+	{ NULL, { PMDA_PMID(24,35), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, },
+	/* max_childwrite_latency */
+	{ NULL, { PMDA_PMID(25,36), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, },
+	/* num_recoveries */
+	{ NULL, { PMDA_PMID(26,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+		PMDA_PMUNITS(0,0,0,0,0,0) }, },
+};
+
+static struct event_context *ev;
+static struct ctdb_context *ctdb;
+static struct ctdb_statistics *stats;
+
+static void
+pmda_ctdb_q_read_cb(uint8_t *data, size_t cnt, void *args)
+{
+	if (cnt == 0) {
+		fprintf(stderr, "ctdbd unreachable\n");
+		/* cleanup on request timeout */
+		return;
+	}
+
+	ctdb_client_read_cb(data, cnt, args);
+}
+
+
+static int
+pmda_ctdb_daemon_connect(void)
+{
+	const char *socket_name;
+	int ret;
+	struct sockaddr_un addr;
+
+	ev = event_context_init(NULL);
+	if (ev == NULL) {
+		fprintf(stderr, "Failed to init event ctx\n");
+		return -1;
+	}
+
+	ctdb = ctdb_init(ev);
+	if (ctdb == NULL) {
+		fprintf(stderr, "Failed to init ctdb\n");
+		goto err_ev;
+	}
+
+	socket_name = getenv("CTDB_SOCKET");
+	if (socket_name == NULL) {
+		socket_name = CTDB_PATH;
+	}
+
+	ret = ctdb_set_socketname(ctdb, socket_name);
+	if (ret == -1) {
+		fprintf(stderr, "ctdb_set_socketname failed - %s\n",
+				ctdb_errstr(ctdb));
+		goto err_ctdb;
+	}
+
+	/*
+	 * ctdb_socket_connect() sets a default queue callback handler that
+	 * calls exit() if ctdbd is unavailable on recv, use our own wrapper to
+	 * work around this
+	 */
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path));
+
+	ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (ctdb->daemon.sd == -1) {
+		fprintf(stderr, "Failed to open client socket\n");
+		goto err_ctdb;
+	}
+
+	set_nonblocking(ctdb->daemon.sd);
+	set_close_on_exec(ctdb->daemon.sd);
+
+	if (connect(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+		fprintf(stderr, "Failed to connect to ctdb daemon via %s\n",
+			ctdb->daemon.name);
+		goto err_sd;
+	}
+
+	ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd,
+					      CTDB_DS_ALIGNMENT,
+					      pmda_ctdb_q_read_cb, ctdb,
+					      "to-ctdbd");
+	if (ctdb->daemon.queue == NULL) {
+		fprintf(stderr, "Failed to setup queue\n");
+		goto err_sd;
+	}
+
+	ctdb->pnn = ctdb_ctrl_getpnn(ctdb, timeval_current_ofs(3, 0),
+				     CTDB_CURRENT_NODE);
+	if (ctdb->pnn == (uint32_t)-1) {
+		fprintf(stderr, "Failed to get ctdb pnn\n");
+		goto err_sd;
+	}
+
+	return 0;
+err_sd:
+	close(ctdb->daemon.sd);
+err_ctdb:
+	talloc_free(ctdb);
+err_ev:
+	talloc_free(ev);
+	ctdb = NULL;
+	return -1;
+}
+
+static void
+pmda_ctdb_daemon_disconnect(void)
+{
+	if (ctdb->methods) {
+		ctdb->methods->shutdown(ctdb);
+	}
+
+	if (ctdb->daemon.sd != -1) {
+		close(ctdb->daemon.sd);
+	}
+
+	talloc_free(ctdb);
+	talloc_free(ev);
+	ctdb = NULL;
+}
+
+static int
+fill_node(unsigned int item, pmAtomValue *atom)
+{
+	switch (item) {
+	case 10:
+		atom->ul = stats->node.req_call;
+		break;
+	case 11:
+		atom->ul = stats->node.reply_call;
+		break;
+	case 12:
+		atom->ul = stats->node.req_dmaster;
+		break;
+	case 13:
+		atom->ul = stats->node.reply_dmaster;
+		break;
+	case 14:
+		atom->ul = stats->node.reply_error;
+		break;
+	case 15:
+		atom->ul = stats->node.req_message;
+		break;
+	case 16:
+		atom->ul = stats->node.req_control;
+		break;
+	case 17:
+		atom->ul = stats->node.reply_control;
+		break;
+	default:
+		return PM_ERR_PMID;
+	}
+
+	return 0;
+}
+
+static int
+fill_client(unsigned int item, pmAtomValue *atom)
+{
+	switch (item) {
+	case 18:
+		atom->ul = stats->client.req_call;
+		break;
+	case 19:
+		atom->ul = stats->client.req_message;
+		break;
+	case 20:
+		atom->ul = stats->client.req_control;
+		break;
+	default:
+		return PM_ERR_PMID;
+	}
+
+	return 0;
+}
+
+static int
+fill_timeout(unsigned int item, pmAtomValue *atom)
+{
+	switch (item) {
+	case 21:
+		atom->ul = stats->timeouts.call;
+		break;
+	case 22:
+		atom->ul = stats->timeouts.control;
+		break;
+	case 23:
+		atom->ul = stats->timeouts.traverse;
+		break;
+	default:
+		return PM_ERR_PMID;
+	}
+
+	return 0;
+}
+
+/*
+ * callback provided to pmdaFetch
+ */
+static int
+pmda_ctdb_fetch_cb(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom)
+{
+	int ret;
+	__pmID_int *id = (__pmID_int *)&(mdesc->m_desc.pmid);
+
+	if (inst != PM_IN_NULL) {
+		return PM_ERR_INST;
+	}
+
+	if (stats == NULL) {
+		fprintf(stderr, "stats not available\n");
+		ret = PM_ERR_VALUE;
+		goto err_out;
+	}
+
+
+	switch (id->cluster) {
+	case 0:
+		atom->ul = stats->num_clients;
+		break;
+	case 1:
+		atom->ul = stats->frozen;
+		break;
+	case 3:
+		atom->ul = stats->recovering;
+		break;
+	case 4:
+		atom->ul = stats->client_packets_sent;
+		break;
+	case 5:
+		atom->ul = stats->client_packets_recv;
+		break;
+	case 6:
+		atom->ul = stats->node_packets_sent;
+		break;
+	case 7:
+		atom->ul = stats->node_packets_recv;
+		break;
+	case 8:
+		atom->ul = stats->keepalive_packets_sent;
+		break;
+	case 9:
+		atom->ul = stats->keepalive_packets_recv;
+		break;
+	case 10:
+		ret = fill_node(id->item, atom);
+		if (ret) {
+			goto err_out;
+		}
+		break;
+	case 11:
+		ret = fill_client(id->item, atom);
+		if (ret) {
+			goto err_out;
+		}
+		break;
+	case 12:
+		ret = fill_timeout(id->item, atom);
+		if (ret) {
+			goto err_out;
+		}
+		break;
+	case 13:
+		atom->ul = stats->total_calls;
+		break;
+	case 14:
+		atom->ul = stats->pending_calls;
+		break;
+	case 15:
+		atom->ul = stats->lockwait_calls;
+		break;
+	case 16:
+		atom->ul = stats->pending_lockwait_calls;
+		break;
+	case 17:
+		atom->ul = stats->childwrite_calls;
+		break;
+	case 18:
+		atom->ul = stats->pending_childwrite_calls;
+		break;
+	case 19:
+		atom->ul = stats->memory_used;
+		break;
+	case 20:
+		atom->ul = stats->max_hop_count;
+		break;
+	case 21:
+		atom->d = stats->reclock.ctdbd.max;
+		break;
+	case 22:
+		atom->d = stats->reclock.recd.max;
+		break;
+	case 23:
+		atom->d = stats->call_latency.max;
+		break;
+	case 24:
+		atom->d = stats->lockwait_latency.max;
+		break;
+	case 25:
+		atom->d = stats->childwrite_latency.max;
+		break;
+	case 26:
+		atom->d = stats->num_recoveries;
+		break;
+	default:
+		return PM_ERR_PMID;
+	}
+
+	ret = 0;
+err_out:
+	return ret;
+}
+
+/*
+ * This routine is called once for each pmFetch(3) operation, so is a
+ * good place to do once-per-fetch functions, such as value caching or
+ * instance domain evaluation.
+ */
+static int
+pmda_ctdb_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda)
+{
+	int ret;
+	TDB_DATA data;
+	int32_t res;
+	struct timeval ctdb_timeout;
+
+	if (ctdb == NULL) {
+		fprintf(stderr, "attempting reconnect to ctdbd\n");
+		ret = pmda_ctdb_daemon_connect();
+		if (ret < 0) {
+			fprintf(stderr, "reconnect failed\n");
+			return PM_ERR_VALUE;
+		}
+	}
+
+	ctdb_timeout = timeval_current_ofs(1, 0);
+	ret = ctdb_control(ctdb, ctdb->pnn, 0,
+			   CTDB_CONTROL_STATISTICS, 0, tdb_null,
+			   ctdb, &data, &res, &ctdb_timeout, NULL);
+
+	if (ret != 0 || res != 0) {
+		fprintf(stderr, "ctdb control for statistics failed, reconnecting\n");
+		pmda_ctdb_daemon_disconnect();
+		ret = PM_ERR_VALUE;
+		goto err_out;
+	}
+
+	stats = (struct ctdb_statistics *)data.dptr;
+
+	if (data.dsize != sizeof(struct ctdb_statistics)) {
+		fprintf(stderr, "incorrect statistics size %zu - not %zu\n",
+			data.dsize, sizeof(struct ctdb_statistics));
+		ret = PM_ERR_VALUE;
+		goto err_stats;
+	}
+
+	ret = pmdaFetch(numpmid, pmidlist, resp, pmda);
+
+err_stats:
+	talloc_free(stats);
+err_out:
+	return ret;
+}
+
+/*
+ * Initialise the agent
+ */
+void
+pmda_ctdb_init(pmdaInterface *dp)
+{
+	if (dp->status != 0) {
+		return;
+	}
+
+	dp->version.two.fetch = pmda_ctdb_fetch;
+	pmdaSetFetchCallBack(dp, pmda_ctdb_fetch_cb);
+
+	pmdaInit(dp, NULL, 0, metrictab,
+		 (sizeof(metrictab) / sizeof(metrictab[0])));
+}
+
+static char *
+helpfile(void)
+{
+	static char buf[MAXPATHLEN];
+
+	if (!buf[0]) {
+		snprintf(buf, sizeof(buf), "%s/ctdb/help",
+			 pmGetConfig("PCP_PMDAS_DIR"));
+	}
+	return buf;
+}
+
+static void
+usage(void)
+{
+	fprintf(stderr, "Usage: %s [options]\n\n", pmProgname);
+	fputs("Options:\n"
+	  "  -d domain        use domain (numeric) for metrics domain of PMDA\n"
+	  "  -l logfile       write log into logfile rather than using default log name\n"
+	  "\nExactly one of the following options may appear:\n"
+	  "  -i port          expect PMCD to connect on given inet port (number or name)\n"
+	  "  -p               expect PMCD to supply stdin/stdout (pipe)\n"
+	  "  -u socket        expect PMCD to connect on given unix domain socket\n",
+	  stderr);
+	exit(1);
+}
+
+/*
+ * Set up the agent if running as a daemon.
+ */
+int
+main(int argc, char **argv)
+{
+	int err = 0;
+	char log_file[] = "pmda_ctdb.log";
+	pmdaInterface dispatch;
+
+	__pmSetProgname(argv[0]);
+
+	pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, CTDB,
+		   log_file, helpfile());
+
+	if (pmdaGetOpt(argc, argv, "d:i:l:pu:?", &dispatch, &err) != EOF) {
+		err++;
+	}
+
+	if (err) {
+		usage();
+	}
+
+	pmdaOpenLog(&dispatch);
+	pmda_ctdb_init(&dispatch);
+	pmdaConnect(&dispatch);
+	pmdaMain(&dispatch);
+
+	exit(0);
+}
+

Added: branches/ctdb/squeeze-backports/utils/pmda/pmns
===================================================================
--- branches/ctdb/squeeze-backports/utils/pmda/pmns	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/pmda/pmns	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,73 @@
+/*
+ * Metrics for CTDB PMDA
+ *
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2011 David Disseldorp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+ctdb {
+	num_clients		CTDB:0:0
+	frozen			CTDB:0:1
+	recovering		CTDB:0:2
+	client_packets_sent	CTDB:0:3
+	client_packets_recv	CTDB:0:4
+	node_packets_sent	CTDB:0:5
+	node_packets_recv	CTDB:0:6
+	keepalive_packets_sent	CTDB:0:7
+	keepalive_packets_recv	CTDB:0:8
+	node
+	client
+	timeouts
+	total_calls		CTDB:0:9
+	pending_calls		CTDB:0:10
+	lockwait_calls		CTDB:0:11
+	pending_lockwait_calls	CTDB:0:12
+	childwrite_calls	CTDB:0:13
+	pending_childwrite_calls CTDB:0:14
+	memory_used		CTDB:0:15
+	max_hop_count		CTDB:0:16
+	max_reclock_ctdbd	CTDB:0:17
+	max_reclock_recd	CTDB:0:18
+	max_call_latency	CTDB:0:19
+	max_lockwait_latency	CTDB:0:20
+	max_childwrite_latency	CTDB:0:21
+	num_recoveries		CTDB:0:22
+}
+
+ctdb.node {
+	req_call	CTDB:1:0
+	reply_call	CTDB:1:1
+	req_dmaster	CTDB:1:2
+	reply_dmaster	CTDB:1:3
+	reply_error	CTDB:1:4
+	req_message	CTDB:1:5
+	req_control	CTDB:1:6
+	reply_control	CTDB:1:7
+}
+
+ctdb.client {
+	req_call	CTDB:2:0
+	req_message	CTDB:2:1
+	req_control	CTDB:2:2
+}
+
+ctdb.timeouts {
+	call		CTDB:3:0
+	control		CTDB:3:1
+	traverse	CTDB:3:2
+}
+

Added: branches/ctdb/squeeze-backports/utils/pmda/root
===================================================================
--- branches/ctdb/squeeze-backports/utils/pmda/root	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/pmda/root	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,10 @@
+/*
+ * fake "root" for validating the local PMNS subtree
+ */
+
+#include <stdpmid>
+
+root { ctdb }
+
+#include "pmns"
+

Added: branches/ctdb/squeeze-backports/utils/scsi_io/scsi_io.c
===================================================================
--- branches/ctdb/squeeze-backports/utils/scsi_io/scsi_io.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/scsi_io/scsi_io.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,1155 @@
+/* a tool to open a scsi device and issue some useful commands
+   such as INQUIRY and helpers to call various PERSISTENT RESERVATION
+   functions
+
+   Copyright   ronnie sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* very incomplete and needs to be enhanced with noice command line options
+   to drive it.
+   we need access to an array that supports the PERSISTENT RESERVATION cdb's
+   before we can proceed
+*/
+/* scsi bugs:
+   INQUIRY takes a 2 byte allocation_length parameter but it appears that 
+   it only looks at the low byte. If you specify 0x00ff all is well
+   but if you specify 0x0100   it gets confused and returnes garbage data
+   for (e.g) SupportedVPDPages. Same goes for UnitSerialNumber and probably all
+   other inq pages as well.
+
+*/
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <scsi/sg.h>
+#include "popt.h"
+
+
+#define SCSI_TIMEOUT 5000 /* ms */
+
+static char *command = NULL;
+static char *device  = NULL;
+static char *key     = NULL;
+static char *rmkey     = NULL;
+static int scope = -1;
+static int type  = -1;
+
+const char *sensetable[16]={
+	"no sense",
+	"recovered error",
+	"not ready",
+	"medium error",
+	"hardware error",
+	"illegal request",
+	"unit attention",
+	"data protect",
+	"blank check",
+	"vendor specific",
+	"copy aborted",
+	"aboreted command",
+	"unknown",
+	"unknown",
+	"unknown",
+	"unknown"
+};
+
+int scsi_io(int fd, unsigned char *cdb, unsigned char cdb_size, int xfer_dir, unsigned char *data, unsigned int *data_size, unsigned char *sense, unsigned int *sense_len)
+{
+	sg_io_hdr_t io_hdr;
+
+	memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+	io_hdr.interface_id = 'S';
+
+	/* CDB */
+	io_hdr.cmdp = cdb;
+	io_hdr.cmd_len = cdb_size;
+
+	/* Where to store the sense_data, if there was an error */
+	io_hdr.sbp = sense;
+	io_hdr.mx_sb_len = *sense_len;
+	*sense_len=0;
+
+	/* Transfer direction, either in or out. Linux does not yet
+	   support bidirectional SCSI transfers ?
+	 */
+	io_hdr.dxfer_direction = xfer_dir;
+
+	/* Where to store the DATA IN/OUT from the device and how big the
+	   buffer is
+	 */
+	io_hdr.dxferp = data;
+	io_hdr.dxfer_len = *data_size;
+
+	/* SCSI timeout in ms */
+	io_hdr.timeout = SCSI_TIMEOUT;
+
+
+	if(ioctl(fd, SG_IO, &io_hdr) < 0){
+		perror("SG_IO ioctl failed");
+		return -1;
+	}
+
+	/* now for the error processing */
+	if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK){
+		if(io_hdr.sb_len_wr > 0){
+			*sense_len=io_hdr.sb_len_wr;
+			return 0;
+		}
+	}
+	if(io_hdr.masked_status){
+		printf("status=0x%x\n", io_hdr.status);
+		printf("masked_status=0x%x\n", io_hdr.masked_status);
+		return -2;
+	}
+	if(io_hdr.host_status){
+		printf("host_status=0x%x\n", io_hdr.host_status);
+		return -3;
+	}
+	if(io_hdr.driver_status){
+		printf("driver_status=0x%x\n", io_hdr.driver_status);
+		return -4;
+	}
+
+#if 0
+{int i;
+printf("CDB:\n");
+for(i=0;i<cdb_size;i++){printf("0x%02x ",cdb[i]);if((i%8)==7)printf("\n");}
+printf("\n");
+}
+{int i;
+printf("DATA:\n");
+for(i=0;i<96;i++){printf("0x%02x ",data[i]);if((i%8)==7)printf("\n");}
+printf("\n");
+}
+#endif
+
+	return 0;
+}
+
+typedef struct _value_string_t {
+	int	value;
+	const char	*string;
+} value_string_t;
+
+
+
+value_string_t peripheral_device_types[] = {
+	{0, "SBC : Direct Access Block device"},
+	{1, "SSC : Sequential Access Device"},
+	{5, "MMC : Multimedia Device"},
+	{17,"OSD : Object Based Storage"},
+	{0,NULL}
+};
+
+value_string_t scsi_versions[] = {
+	{0, "No conformance to any standard claimed"},
+	{3, "SPC"},
+	{4, "SPC-2"},
+	{5, "SPC-3"},
+	{0,NULL}
+};
+
+value_string_t vpd_pages[] = {
+	{0x00, "Supported VPD Pages"},
+	{0x80, "Unit Serial number"},
+	{0x83, "Device Identification"},
+	{0,NULL}
+};
+
+const char *val_to_str(value_string_t *vs, int v)
+{
+	while(vs && vs->string){
+		if(vs->value==v){
+			return vs->string;
+		}
+		vs++;
+	}
+	return "";
+}
+
+void print_sense_data(unsigned char *sense, int sense_len)
+{
+	int i;
+	unsigned char asc, ascq;
+
+	printf("Device returned sense information\n");
+	if(sense[0]==0x70){
+		printf("filemark:%d eom:%d ili:%d  sense-key:0x%02x (%s)\n",
+			!!(sense[2]&0x80),
+			!!(sense[2]&0x40),
+			!!(sense[2]&0x20),
+			sense[2]&0x0f,
+			sensetable[sense[2]&0x0f]);
+		printf("command specific info: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+			sense[8],sense[9],sense[10],sense[11]);
+
+		asc=sense[12];
+		printf("additional sense code:0x%02x\n", asc);
+
+		ascq=sense[13];
+		printf("additional sense code qualifier:0x%02x\n", ascq);
+
+		printf("field replacable unit code:0x%02x\n", sense[14]);
+
+		if((asc==0x20)&&(ascq==0x00))
+			printf("INVALID COMMAND OPERATION CODE\n");
+	}
+
+	printf("Sense data:\n");
+	for(i=0;i<sense_len;i++){
+		printf("0x%02x ", sense[i]);
+		if((i%8)==7)printf("\n");
+	}
+	printf("\n");
+}
+
+int scsi_inquiry(int fd)
+{
+	unsigned char cdb[]={0x12,0,0,0,0,0};
+
+	unsigned int data_size=96;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+
+	int res, alen, i;
+
+	cdb[3]=(data_size>>8)&0xff;
+	cdb[4]=data_size&0xff;
+
+
+	printf("Standard INQUIRY Data:\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	/* Peripheral Qualifier */
+	printf("Peripheral Qualifier:%c%c%cb\n",
+		'0'+!!(data[0]&0x80),
+		'0'+!!(data[0]&0x40),
+		'0'+!!(data[0]&0x20));
+
+	/* Peripheral Device Type */
+	printf("Peripheral Device Type: 0x%02x (%s)\n",
+		data[0]&0x1f,
+		val_to_str(peripheral_device_types, data[0]&0x1f));
+
+	/* RMB */
+	printf("RMB: %s device\n", data[1]&0x80?"REMOVABLE":"NON-REMOVABLE");
+
+	/* SCSI Version */
+	printf("SCSI Version: 0x%02x (%s)\n",
+		data[2],
+		val_to_str(scsi_versions, data[2]));
+
+	/* NormACA, HiSUP, Response Data Format */
+	printf("NormACA:%d HiSup:%d ResponseDataFormat:%d\n",
+		!!(data[3]&0x20),
+		!!(data[3]&0x10),
+		data[3]&0x0f);
+
+	/* Additional Length */
+	alen=data[4];
+ 
+	switch(data[3]&0x0f){
+	/*SPC-2/SPC-3/SPC-4*/
+	case 2:
+	/*SPC (not strictly correct but we print it like 2 anyway)*/
+	case 1:
+		/* SCCS ... */
+		printf("SCCS:%d ACC:%d TPGS:%c%cb 3PC:%d PROTECT:%d\n",
+			!!(data[5]&0x80),
+			!!(data[5]&0x40),
+			'0'+!!(data[5]&0x20),
+			'0'+!!(data[5]&0x10),
+			!!(data[5]&0x08),
+			!!(data[5]&0x01));
+
+		/* Encserv ... */
+		printf("Encserv:%d VS:%d MultiP:%d ADDR16:%d\n",
+			!!(data[6]&0x40),
+			!!(data[6]&0x20),
+			!!(data[6]&0x10),
+			!!(data[6]&0x01));
+
+		/* WBUS16 ... */
+		printf("WBUS16:%d SYNC:%d CmdQue:%d VS:%d\n",
+			!!(data[7]&0x20),
+			!!(data[7]&0x10),
+			!!(data[7]&0x02),
+			!!(data[7]&0x01));
+			
+
+		/* T10 vendor Identification */
+		printf("Vendor:");
+		for(i=0;i<8;i++)printf("%c",data[8+i]);printf("\n");
+ 
+		/* Product Identification */
+		printf("Product:");
+		for(i=0;i<16;i++)printf("%c",data[16+i]);printf("\n");
+
+		/* Product Revision Level */
+		printf("Product Revision:");
+		for(i=0;i<4;i++)printf("%c",data[32+i]);printf("\n");
+
+		break;
+	}
+	
+	return 0;
+}
+
+int scsi_inquiry_supported_vpd_pages(int fd)
+{
+	unsigned char cdb[]={0x12,0x01,0,0,0,0};
+
+	unsigned int data_size=0xff;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+
+	int res, pl, i;
+
+	cdb[3]=(data_size>>8)&0xff;
+	cdb[4]=data_size&0xff;
+
+
+	printf("INQUIRY Supported VPD Pages:\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	/* Page Length */
+	pl=data[3];
+
+	/* Pages */
+	for(i=4;i<(pl+4);i++){
+		printf("Page:%02xh (%s)\n",
+			data[i],
+			val_to_str(vpd_pages, data[i]));
+	}
+
+	return 0;
+}
+
+int scsi_inquiry_unit_serial_number(int fd)
+{
+	unsigned char cdb[]={0x12,0x01,0x80,0,0,0};
+
+	unsigned int data_size=0x00ff;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+
+	int res, pl, i;
+
+	cdb[3]=(data_size>>8)&0xff;
+	cdb[4]=data_size&0xff;
+
+
+	printf("INQUIRY Unit Serial Number:\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	/* Page Length */
+	pl=data[3];
+
+	/* Unit Serial Number */
+	printf("Unit Serial Number:");
+	for(i=4;i<(pl+4);i++)printf("%c",data[i]&0xff);printf("\n");
+
+	return 0;
+}
+
+int scsi_persistent_reserve_in_read_keys(int fd)
+{
+	unsigned char cdb[]={0x5e,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=0x00ff;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=0;
+	int res, i;
+	unsigned long prgeneration, additional_length;
+
+	cdb[1]=service_action;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+
+	printf("PRESISTENT RESERVE IN: READ KEYS\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	/* PRGeneration */
+	prgeneration=data[0];
+	prgeneration<<=8;prgeneration|=data[1];
+	prgeneration<<=8;prgeneration|=data[2];
+	prgeneration<<=8;prgeneration|=data[3];
+	printf("PRGeneration:%lu\n", prgeneration);
+
+	/* Additional Length */
+	additional_length=data[4];
+	additional_length<<=8;additional_length|=data[5];
+	additional_length<<=8;additional_length|=data[6];
+	additional_length<<=8;additional_length|=data[7];
+	printf("Additional Length:%lu\n", additional_length);
+
+	/* print the registered keys */
+	for(i=0;i<additional_length;i+=8){
+		printf("Key:%02x%02x%02x%02x%02x%02x%02x%02x\n",
+			data[i+8],
+			data[i+9],
+			data[i+10],
+			data[i+11],
+			data[i+12],
+			data[i+13],
+			data[i+14],
+			data[i+15]);
+	}
+
+	return 0;
+}
+
+int scsi_persistent_reserve_in_read_reservation(int fd)
+{
+	unsigned char cdb[]={0x5e,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=0x00ff;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=1;
+	int res;
+	unsigned long prgeneration, additional_length;
+
+	cdb[1]=service_action;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+
+	printf("PRESISTENT RESERVE IN: READ RESERVATION\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	/* PRGeneration */
+	prgeneration=data[0];
+	prgeneration<<=8;prgeneration|=data[1];
+	prgeneration<<=8;prgeneration|=data[2];
+	prgeneration<<=8;prgeneration|=data[3];
+	printf("PRGeneration:%lu\n", prgeneration);
+
+	/* Additional Length */
+	additional_length=data[4];
+	additional_length<<=8;additional_length|=data[5];
+	additional_length<<=8;additional_length|=data[6];
+	additional_length<<=8;additional_length|=data[7];
+	printf("Additional Length:%lu\n", additional_length);
+
+	if(additional_length==16){
+		printf("Key:%02x%02x%02x%02x%02x%02x%02x%02x\n",
+			data[8],
+			data[9],
+			data[10],
+			data[11],
+			data[12],
+			data[13],
+			data[14],
+			data[15]);
+		printf("Scope:%xh Type:%xh\n",data[21]>>4,data[21]&0x0f);
+	}
+
+	return 0;
+}
+
+int scsi_persistent_reserve_in_report_capabilities(int fd)
+{
+	unsigned char cdb[]={0x5e,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=0x00ff;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=2;
+	int res;
+	unsigned short length, type_mask;
+
+	cdb[1]=service_action;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+
+	printf("PRESISTENT RESERVE IN: REPORT CAPABILITIES\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	/* Length */
+	length=data[0];
+	length<<=8;length|=data[1];
+	printf("Length:%d\n", length);
+
+	/* CRH ... */
+	printf("CRH:%d SIP_C:%d ATP_C:%d PTPL_C:%d\n",
+		!!(data[2]&0x10),
+		!!(data[2]&0x08),
+		!!(data[2]&0x04),
+		!!(data[2]&0x01));
+
+	/* TMV ... */
+	printf("TMV:%d ALLOW_COMMANDS:%c%c%cb PTPL_A:%d\n",
+		!!(data[3]&0x80),
+		'0'+(!!(data[3]&0x40)),
+		'0'+(!!(data[3]&0x20)),
+		'0'+(!!(data[3]&0x10)),
+		!!(data[3]&0x01));
+
+	/* Persistent Reservation Type Mask */
+	type_mask=data[4];
+	type_mask<<=8;type_mask|=data[5];
+	printf("Presistent Reservation Type Mask:0x%04x\n", type_mask);
+	printf("WR_EX_AR:%d EX_AC_RO:%d WR_EX_RO:%d EX_AC:%d WR_EX:%d EX_AC_AR:%d\n",
+		!!(data[4]&0x80),
+		!!(data[4]&0x40),
+		!!(data[4]&0x20),
+		!!(data[4]&0x08),
+		!!(data[4]&0x02),
+		!!(data[4]&0x01));
+
+	return 0;
+}
+
+int scsi_persistent_reserve_in_read_full_status(int fd)
+{
+	unsigned char cdb[]={0x5e,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=0x00ff;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=3;
+	int res;
+	unsigned long prgeneration, additional_length;
+
+	cdb[1]=service_action;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+
+	printf("PRESISTENT RESERVE IN: READ FULL STATUS\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	/* PRGeneration */
+	prgeneration=data[0];
+	prgeneration<<=8;prgeneration|=data[1];
+	prgeneration<<=8;prgeneration|=data[2];
+	prgeneration<<=8;prgeneration|=data[3];
+	printf("PRGeneration:%lu\n", prgeneration);
+
+	/* Additional Length */
+	additional_length=data[4];
+	additional_length<<=8;additional_length|=data[5];
+	additional_length<<=8;additional_length|=data[6];
+	additional_length<<=8;additional_length|=data[7];
+	printf("Additional Length:%lu\n", additional_length);
+
+/*XXX*/
+
+	return 0;
+}
+
+int scsi_persistent_reserve_out_clear(int fd)
+{
+	unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=24;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=3;
+	int res;
+
+	long long k;
+
+	if (scope==-1) {
+		printf("Must specify scope\n");
+		printf("scsi_io --device=<DEVICE> --command=clear --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+	if (type==-1) {
+		printf("Must specify type\n");
+		printf("scsi_io --device=<DEVICE> --command=clear --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+	if (!key) {
+		printf("Must specify key\n");
+		printf("scsi_io --device=<DEVICE> --command=clear --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+
+	sscanf(key, "%llx", &k);
+	cdb[1]=service_action;
+	cdb[2]=(scope<<4)|type;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+	memset(data, 0, data_size);
+
+	/* Reservation Key */
+	data[0]=(k>>56)&0xff;
+	data[1]=(k>>48)&0xff;
+	data[2]=(k>>40)&0xff;
+	data[3]=(k>>32)&0xff;
+	data[4]=(k>>24)&0xff;
+	data[5]=(k>>16)&0xff;
+	data[6]=(k>> 8)&0xff;
+	data[7]=(k    )&0xff;
+
+	/* Service Action Key */
+	data[8]=0;
+	data[9]=0;
+	data[10]=0;
+	data[11]=0;
+	data[12]=0;
+	data[13]=0;
+	data[14]=0;
+	data[15]=0;
+
+	/* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */
+	data[20]=0x04;
+
+	printf("PRESISTENT RESERVE IN: CLEAR\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	return 0;
+}
+
+int scsi_persistent_reserve_out_reserve(int fd)
+{
+	unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=24;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=1;
+	int res;
+	long long k;
+
+	if (scope==-1) {
+		printf("Must specify scope\n");
+		printf("scsi_io --device=<DEVICE> --command=reserve --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+	if (type==-1) {
+		printf("Must specify type\n");
+		printf("scsi_io --device=<DEVICE> --command=reserve --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+	if (!key) {
+		printf("Must specify key\n");
+		printf("scsi_io --device=<DEVICE> --command=reserve --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+
+	sscanf(key, "%llx", &k);
+
+
+	cdb[1]=service_action;
+	cdb[2]=(scope<<4)|type;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+	memset(data, 0, data_size);
+
+	/* Reservation Key */
+	data[0]=(k>>56)&0xff;
+	data[1]=(k>>48)&0xff;
+	data[2]=(k>>40)&0xff;
+	data[3]=(k>>32)&0xff;
+	data[4]=(k>>24)&0xff;
+	data[5]=(k>>16)&0xff;
+	data[6]=(k>> 8)&0xff;
+	data[7]=(k    )&0xff;
+
+	/* Service Action Key */
+	data[8]=0;
+	data[9]=0;
+	data[10]=0;
+	data[11]=0;
+	data[12]=0;
+	data[13]=0;
+	data[14]=0;
+	data[15]=0;
+
+	/* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */
+	data[20]=0x04;
+
+	printf("PRESISTENT RESERVE IN: RESERVE\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	return 0;
+}
+
+int scsi_persistent_reserve_out_preempt(int fd)
+{
+	unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=24;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=4;
+	int res;
+	long long k;
+
+	if (scope==-1) {
+		printf("Must specify scope\n");
+		printf("scsi_io --device=<DEVICE> --command=preempt --scope=<SCOPE> --type=<TYPE> --key=<KEY> --rmkey=<KEY>\n");
+		_exit(10);
+	}
+	if (type==-1) {
+		printf("Must specify type\n");
+		printf("scsi_io --device=<DEVICE> --command=preempt --scope=<SCOPE> --type=<TYPE> --key=<KEY> --rmkey=<KEY>\n");
+		_exit(10);
+	}
+	if (!key) {
+		printf("Must specify key\n");
+		printf("scsi_io --device=<DEVICE> --command=preempt --scope=<SCOPE> --type=<TYPE> --key=<KEY> --rmkey=<KEY>\n");
+		_exit(10);
+	}
+	if (!rmkey) {
+		printf("Must specify rmkey\n");
+		printf("scsi_io --device=<DEVICE> --command=preempt --scope=<SCOPE> --type=<TYPE> --key=<KEY> --rmkey=<KEY>\n");
+		_exit(10);
+	}
+
+
+
+	cdb[1]=service_action;
+	cdb[2]=(scope<<4)|type;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+	memset(data, 0, data_size);
+
+	/* Reservation Key */
+	sscanf(key, "%llx", &k);
+	data[0]=(k>>56)&0xff;
+	data[1]=(k>>48)&0xff;
+	data[2]=(k>>40)&0xff;
+	data[3]=(k>>32)&0xff;
+	data[4]=(k>>24)&0xff;
+	data[5]=(k>>16)&0xff;
+	data[6]=(k>> 8)&0xff;
+	data[7]=(k    )&0xff;
+
+	/* Service Action Key */
+	sscanf(rmkey, "%llx", &k);
+	data[8] =(k>>56)&0xff;
+	data[9] =(k>>48)&0xff;
+	data[10]=(k>>40)&0xff;
+	data[11]=(k>>32)&0xff;
+	data[12]=(k>>24)&0xff;
+	data[13]=(k>>16)&0xff;
+	data[14]=(k>> 8)&0xff;
+	data[15]=(k    )&0xff;
+
+	/* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */
+	data[20]=0x04;
+
+	printf("PRESISTENT RESERVE IN: RESERVE\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	return 0;
+}
+
+int scsi_persistent_reserve_out_register_and_ignore_existing_key(int fd)
+{
+	unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=24;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=6;
+	int res;
+	long long k;
+
+	if (scope==-1) {
+		printf("Must specify scope\n");
+		printf("scsi_io --device=<DEVICE> --command=registerkey --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+	if (type==-1) {
+		printf("Must specify type\n");
+		printf("scsi_io --device=<DEVICE> --command=registerkey --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+	if (!key) {
+		printf("Must specify key\n");
+		printf("scsi_io --device=<DEVICE> --command=registerkey --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+
+	sscanf(key, "%llx", &k);
+
+	cdb[1]=service_action;
+	cdb[2]=(scope<<4)|type;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+	memset(data, 0, data_size);
+
+	/* Reservation Key */
+	data[0]=0;
+	data[1]=0;
+	data[2]=0;
+	data[3]=0;
+	data[4]=0;
+	data[5]=0;
+	data[6]=0;
+	data[7]=0;
+
+	/* Service Action Key */
+	data[8] =(k>>56)&0xff;
+	data[9] =(k>>48)&0xff;
+	data[10]=(k>>40)&0xff;
+	data[11]=(k>>32)&0xff;
+	data[12]=(k>>24)&0xff;
+	data[13]=(k>>16)&0xff;
+	data[14]=(k>> 8)&0xff;
+	data[15]=(k    )&0xff;
+
+	/* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */
+	data[20]=0x04;
+
+	printf("PRESISTENT RESERVE IN: REGISTER AND IGNORE EXISTING KEY\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	return 0;
+}
+
+int scsi_persistent_reserve_out_unregister_key(int fd)
+{
+	unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0};
+
+	unsigned int data_size=24;
+	unsigned char data[data_size];
+
+	unsigned int sense_len=32;
+	unsigned char sense[sense_len];
+	unsigned char service_action=6;
+	int res;
+	long long k;
+
+	if (scope==-1) {
+		printf("Must specify scope\n");
+		printf("scsi_io --device=<DEVICE> --command=unregisterkey --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+	if (type==-1) {
+		printf("Must specify type\n");
+		printf("scsi_io --device=<DEVICE> --command=unregisterkey --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+	if (!key) {
+		printf("Must specify key\n");
+		printf("scsi_io --device=<DEVICE> --command=unregisterkey --scope=<SCOPE> --type=<TYPE> --key=<KEY>\n");
+		_exit(10);
+	}
+
+	sscanf(key, "%llx", &k);
+
+	cdb[1]=service_action;
+	cdb[2]=(scope<<4)|type;
+	cdb[7]=(data_size>>8)&0xff;
+	cdb[8]=data_size&0xff;
+
+	memset(data, 0, data_size);
+
+	/* Reservation Key */
+	data[0]=(k>>56)&0xff;
+	data[1]=(k>>48)&0xff;
+	data[2]=(k>>40)&0xff;
+	data[3]=(k>>32)&0xff;
+	data[4]=(k>>24)&0xff;
+	data[5]=(k>>16)&0xff;
+	data[6]=(k>> 8)&0xff;
+	data[7]=(k    )&0xff;
+
+	/* Service Action Key */
+	data[8]=0;
+	data[9]=0;
+	data[10]=0;
+	data[11]=0;
+	data[12]=0;
+	data[13]=0;
+	data[14]=0;
+	data[15]=0;
+
+	/* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */
+	data[20]=0x04;
+
+	printf("PRESISTENT RESERVE IN: UNREGISTER KEY\n");
+
+	res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len);
+	if(res){
+		printf("SCSI_IO failed\n");
+		return -1;
+	}
+	if(sense_len){
+		print_sense_data(sense, sense_len);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+
+
+int open_scsi_device(const char *dev)
+{
+	int fd, vers;
+
+	if((fd=open(dev, O_RDWR))<0){
+		printf("ERROR could not open device %s\n", dev);
+		return -1;
+	}
+	if ((ioctl(fd, SG_GET_VERSION_NUM, &vers) < 0) || (vers < 30000)) {
+		printf("/dev is not an sg device, or old sg driver\n");
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+typedef int (*scsi_func_t)(int fd);
+typedef struct _cmds_t {
+	const char *cmd;
+	scsi_func_t func;
+	const char *comment;
+} cmds_t;
+cmds_t cmds[] = {
+	{"inq",		scsi_inquiry,	"Standard INQUIRY output"},
+	{"vpd",		scsi_inquiry_supported_vpd_pages,	"Supported VPD Pages"},
+	{"usn",		scsi_inquiry_unit_serial_number,	"Unit serial number"},
+	{"readkeys",	scsi_persistent_reserve_in_read_keys,	"Read SCSI Reservation Keys"},
+	{"readrsvr",	scsi_persistent_reserve_in_read_reservation, "Read SCSI Reservation Data"},
+	{"reportcap",	scsi_persistent_reserve_in_report_capabilities, "Report reservation Capabilities"},
+	{"registerkey",	scsi_persistent_reserve_out_register_and_ignore_existing_key,	"Register and ignore existing key"},
+	{"unregisterkey", scsi_persistent_reserve_out_unregister_key, "Unregister a key"},
+	{"clear",	scsi_persistent_reserve_out_clear, "Clear all reservations and registrations"},
+	{"reserve",	scsi_persistent_reserve_out_reserve, "Reserve"},
+	{"preempt",	scsi_persistent_reserve_out_preempt, "Preempt (remove someone elses registration)"},
+};
+
+void usage(void)
+{
+	int i;
+	printf("Usage:  scsi_io --command <command> --device <device>\n");
+	printf("Commands:\n");
+	for (i=0;i<sizeof(cmds)/sizeof(cmds[0]);i++){
+		printf("	%s	%s\n", cmds[i].cmd, cmds[i].comment);
+	}	
+}
+
+
+int main(int argc, const char *argv[])
+{
+	int i, fd;
+	int opt;
+	scsi_func_t func=NULL;
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		{ "scope", 's', POPT_ARG_INT, &scope, 0, "scope", "integer" },
+		{ "type", 't', POPT_ARG_INT, &type, 0, "type", "integer" },
+		{ "key",      'k', POPT_ARG_STRING, &key, 0, "key", "key" },
+		{ "rmkey",      'r', POPT_ARG_STRING, &rmkey, 0, "rmkey", "rmkey" },
+		{ "command",      'c', POPT_ARG_STRING, &command, 0, "command", "command" },
+		{ "device",      'd', POPT_ARG_STRING, &device, 0, "device", "device" },
+//		{ "machinereadable", 'Y', POPT_ARG_NONE, &options.machinereadable, 0, "enable machinereadable output", NULL },
+		POPT_TABLEEND
+	};
+	poptContext pc;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			_exit(1);
+		}
+	}
+
+	if (!command) {
+		printf("Must specify the command\n");
+		usage();
+		_exit(10);
+	}
+
+	if (!device) {
+		printf("Must specify the device\n");
+		usage();
+		_exit(10);
+	}
+
+	fd=open_scsi_device(device);
+	if(fd<0){
+		printf("Could not open SCSI device %s\n",device);
+		usage();
+		_exit(10);
+	}
+
+	for (i=0;i<sizeof(cmds)/sizeof(cmds[0]);i++){
+		if(!strcmp(cmds[i].cmd, command)) {
+			func = cmds[i].func;
+			break;
+		}		
+	}
+	if (!func) {
+		printf("Unrecognized command : %s\n", command);
+		usage();
+		_exit(10);
+	}
+
+	func(fd);
+
+#if 0
+	scsi_persistent_reserve_in_read_full_status(fd);
+	scsi_persistent_reserve_out_register_and_ignore_existing_key(fd);
+	scsi_persistent_reserve_in_read_keys(fd);
+
+	scsi_persistent_reserve_out_reserve(fd);
+	scsi_persistent_reserve_in_read_reservation(fd);
+
+	scsi_persistent_reserve_out_clear(fd);
+	scsi_persistent_reserve_in_read_reservation(fd);
+
+	scsi_persistent_reserve_out_unregister_key(fd);
+	scsi_persistent_reserve_in_read_keys(fd);
+#endif
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/utils/smnotify/smnotify.c
===================================================================
--- branches/ctdb/squeeze-backports/utils/smnotify/smnotify.c	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/smnotify/smnotify.c	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,150 @@
+/* 
+   simple smnotify tool
+
+   Copyright (C) Ronnie Sahlberg 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "smnotify.h"
+#include "popt.h"
+
+static char *client       = NULL;
+static const char *ip     = NULL;
+static char *server = NULL;
+static int stateval       = 0;
+static int clientport     = 0;
+static int sendport       = 0;
+
+static void useage(void)
+{
+	exit(0);
+}
+
+static int create_socket(const char *addr, int port)
+{
+	int s;
+        struct sockaddr_in sock_in;
+
+	s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (s == -1) {
+		printf("Failed to open local socket\n");
+		exit(10);
+	}
+
+	bzero(&sock_in, sizeof(sock_in));
+	sock_in.sin_family = PF_INET;
+	sock_in.sin_port   = htons(port);
+	inet_aton(addr, &sock_in.sin_addr);
+	if (bind(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) == -1) {
+		printf("Failed to bind to local socket\n");
+		exit(10);
+	}
+
+	return s;
+}
+
+int main(int argc, const char *argv[])
+{
+	struct poptOption popt_options[] = {
+		POPT_AUTOHELP
+		{ "client", 'c', POPT_ARG_STRING, &client, 0, "remote client to send the notify to", "hostname/ip" },
+		{ "clientport", 0, POPT_ARG_INT, &clientport, 0, "clientport", "integer" },
+		{ "ip", 'i', POPT_ARG_STRING, &ip, 0, "local ip address to send the notification from", "ip" },
+		{ "sendport", 0, POPT_ARG_INT, &sendport, 0, "port to send the notify from", "integer" },
+		{ "server", 's', POPT_ARG_STRING, &server, 0, "servername to use in the notification", "hostname/ip" },
+		{ "stateval", 0, POPT_ARG_INT, &stateval, 0, "stateval", "integer" },
+		POPT_TABLEEND
+	};
+	int opt;
+	poptContext pc;
+	CLIENT *clnt;
+	int s;
+        struct sockaddr_in sock_cl;
+	struct timeval w;
+	struct status st;
+
+	pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+	while ((opt = poptGetNextOpt(pc)) != -1) {
+		switch (opt) {
+		default:
+			fprintf(stderr, "Invalid option %s: %s\n", 
+				poptBadOption(pc, 0), poptStrerror(opt));
+			exit(1);
+		}
+	}
+
+	if (client == NULL) {
+		printf("ERROR: client not specified\n");
+		useage();
+	}
+
+	if (ip == NULL) {
+		printf("ERROR: ip not specified\n");
+		useage();
+	}
+
+	if (server == NULL) {
+		printf("ERROR: server not specified\n");
+		useage();
+	}
+
+	if (stateval == 0) {
+		printf("ERROR: stateval not specified\n");
+		useage();
+	}
+
+
+	/* Since we want to control from which address these packets are
+	   sent we must create the socket ourself and use low-level rpc
+	   calls.
+	*/
+	s = create_socket(ip, sendport);
+
+	/* only wait for at most 3 seconds before giving up */
+	alarm(3);
+
+	/* Setup a sockaddr_in for the client we want to notify */
+	bzero(&sock_cl, sizeof(sock_cl));
+	sock_cl.sin_family = PF_INET;
+	sock_cl.sin_port   = htons(clientport);
+	inet_aton(client, &sock_cl.sin_addr);
+
+	w.tv_sec = 1;
+	w.tv_usec= 0;
+
+	clnt = clntudp_create(&sock_cl, 100024, 1, w, &s);
+	if (clnt == NULL) {
+		printf("ERROR: failed to connect to client\n");
+		exit(10);
+	}
+
+	/* we dont want to wait for any reply */
+	w.tv_sec = 0;
+	w.tv_usec = 0;
+	clnt_control(clnt, CLSET_TIMEOUT, (char *)&w);
+
+	st.mon_name=server;
+	st.state=stateval;
+	sm_notify_1(&st, clnt);
+
+	return 0;
+}

Added: branches/ctdb/squeeze-backports/utils/smnotify/smnotify.x
===================================================================
--- branches/ctdb/squeeze-backports/utils/smnotify/smnotify.x	                        (rev 0)
+++ branches/ctdb/squeeze-backports/utils/smnotify/smnotify.x	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,21 @@
+#ifdef RPC_HDR
+%#ifdef _AIX
+%#include <rpc/rpc.h>
+%#endif /* _AIX */
+#endif /* RPC_HDR */
+
+const SM_MAXSTRLEN = 1024;
+
+struct status {
+	string mon_name<SM_MAXSTRLEN>;
+	int state;
+};
+
+
+program SMNOTIFY {
+	version SMVERSION {
+		void SM_NOTIFY(struct status) = 6;
+	} = 1;	
+} = 100024;
+
+

Added: branches/ctdb/squeeze-backports/web/bar1.jpg
===================================================================
(Binary files differ)


Property changes on: branches/ctdb/squeeze-backports/web/bar1.jpg
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: branches/ctdb/squeeze-backports/web/building.html
===================================================================
--- branches/ctdb/squeeze-backports/web/building.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/building.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,34 @@
+<!--#set var="TITLE" value="Building CTDB" -->
+<!--#include virtual="header.html" -->
+
+<H2 align="center">Building CTDB and Samba</h2>
+
+<h2>CTDB</h2>
+To build a copy of the CTDB code you should do this:
+<pre>
+   cd ctdb
+   ./autogen.sh
+   ./configure
+   make
+   make install
+</pre>
+
+You need to install ctdb on all nodes of your cluster.
+
+
+<h2>Samba3</h2>
+
+To build a copy of Samba3 with clustering and ctdb support you should do this:
+<pre>
+    cd samba_3_0_ctdb/source
+    ./autogen.sh
+    ./configure --with-ctdb=/usr/src/ctdb --with-cluster-support --enable-pie=no
+    make proto
+    make
+</pre>
+
+Once compiled, you should install Samba on all cluster nodes.<br><br>
+
+The /usr/src/ctdb path should be replaced with the path to the ctdb sources that you downloaded above.
+
+<!--#include virtual="footer.html" -->

Added: branches/ctdb/squeeze-backports/web/clamd.html
===================================================================
--- branches/ctdb/squeeze-backports/web/clamd.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/clamd.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,78 @@
+<!--#set var="TITLE" value="CTDB and ClamAV Daemon" -->
+<!--#include virtual="header.html" -->
+
+<h1>Setting up ClamAV with CTDB</h1>
+
+<h2>Prereqs</h2>
+Configure CTDB as above and set it up to use public ipaddresses.<br>
+Verify that the CTDB cluster works.
+
+<h2>Configuration</h2>
+
+Configure clamd on each node on the cluster.<br><br>
+For details how to configure clamd check its documentation.
+
+<h2>/etc/sysconfig/ctdb</h2>
+
+Add the following lines to the /etc/sysconfig/ctdb configuration file.
+<pre>
+  CTDB_MANAGES_CLAMD=yes
+  CTDB_CLAMD_SOCKET="/path/to/clamd.sock"
+</pre>
+
+Disable clamd in chkconfig so that it does not start by default. Instead CTDB will start/stop clamd as required.
+<pre>
+  chkconfig clamd off
+</pre>
+
+<h2>Events script</h2>
+
+The CTDB distribution already comes with an events script for clamd in the file /etc/ctdb/events.d/31.clamd<br><br>
+There should not be any need to edit this file.
+What you need is to set it as executable, with command like this:
+<pre>
+  chmod +x /etc/ctdb/events.d/31.clamd
+</pre>
+To check if ctdb monitoring and handling with clamd, you can check outpout of command:
+<pre>
+  ctdb scriptstatus
+</pre>
+
+<h2>Restart your cluster</h2>
+Next time your cluster restarts, CTDB will start managing the clamd service.<br><br>
+If the cluster is already in production you may not want to restart the entire cluster since this would disrupt services.<br>
+
+Insted you can just disable/enable the nodes one by one. Once a node becomes enabled again it will start the clamd service.<br><br>
+
+Follow the procedure below for each node, one node at a time :
+
+<h3>1 Disable the node</h3>
+Use the ctdb command to disable the node :
+<pre>
+  ctdb -n NODE disable
+</pre>
+
+<h3>2 Wait until the cluster has recovered</h3>
+
+Use the ctdb tool to monitor until the cluster has recovered, i.e. Recovery mode is NORMAL. This should happen within seconds of when you disabled the node.
+<pre>
+  ctdb status
+</pre>
+
+<h3>3 Enable the node again</h3>
+
+Re-enable the node again which will start the newly configured vsftp service.
+<pre>
+  ctdb -n NODE enable
+</pre>
+
+<h2>See also</h2>
+
+The CLAMAV section in the ctdbd manpage.
+
+<pre>
+  man ctdbd
+</pre>
+
+<!--#include virtual="footer.html" -->
+

Added: branches/ctdb/squeeze-backports/web/configuring.html
===================================================================
--- branches/ctdb/squeeze-backports/web/configuring.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/configuring.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,204 @@
+<!--#set var="TITLE" value="Configuring CTDB" -->
+<!--#include virtual="header.html" -->
+
+<H2 align="center">Configuring CTDB</H2>
+
+<h2>Clustering Model</h2>
+
+The setup instructions on this page are modelled on setting up a cluster of N 
+nodes that function in nearly all respects as a single multi-homed node. 
+So the cluster will export N IP interfaces, each of which is equivalent 
+(same shares) and which offers coherent CIFS file access across all 
+nodes.<p>
+
+The clustering model utilizes IP takeover techniques to ensure that
+the full set of public IP addresses assigned to services on the
+cluster will always be available to the clients even when some nodes
+have failed and become unavailable.
+
+<h2>CTDB Cluster Configuration</h2>
+
+These are the primary configuration files for CTDB.<p>
+
+When CTDB is installed, it will install template versions of these
+files which you need to edit to suit your system.  The current set of
+config files for CTDB are also available from
+<a href="http://samba.org/~tridge/ctdb/config">http://samba.org/~tridge/ctdb/config</a>
+
+<h3>/etc/sysconfig/ctdb</h3>
+
+This file contains the startup parameters for ctdb.<p>
+
+When you installed ctdb, a template config file should have been
+installed in /etc/sysconfig/ctdb.<p>
+
+Edit this file, following the instructions in the template.<p>
+
+The most important options are:
+<ul>
+<li>CTDB_NODES
+<li>CTDB_RECOVERY_LOCK
+<li>CTDB_PUBLIC_ADDRESSES
+</ul>
+
+Please verify these parameters carefully.
+
+<h4>CTDB_RECOVERY_LOCK</h4>
+
+This parameter specifies the lock file that the CTDB daemons use to arbitrate 
+which node is acting as a recovery master.<br>
+
+This file MUST be held on shared storage so that all CTDB daemons in the cluster will access/lock the same file.<br><br>
+
+You <strong>must</strong> specify this parameter.<br>
+There is no default for this parameter.
+
+<h3>CTDB_NODES</h3>
+
+This file needs to be created and should contain a list of the private
+IP addresses that the CTDB daemons will use in your cluster. One IP
+address for each node in the cluster.<p>
+
+This should be a private non-routable subnet which is only used for
+internal cluster traffic. This file must be the same on all nodes in
+the cluster.<p>
+
+Make sure that these IP addresses are automatically started when the
+cluster node boots and that each node can ping each other node.<p>
+
+Example 4 node cluster:
+<pre>
+  CTDB_NODES=/etc/ctdb/nodes
+</pre>
+Content of /etc/ctdb/nodes:
+<pre>
+ 10.1.1.1
+ 10.1.1.2
+ 10.1.1.3
+ 10.1.1.4
+</pre>
+
+The default for this file is /etc/ctdb/nodes.
+
+
+<h3>CTDB_PUBLIC_ADDRESSES</h3>
+
+Each node in a CTDB cluster contains a list of public addresses which that 
+particular node can host.<p>
+
+While running the CTDB cluster will assign each public address that exists in the entire cluster to one node that will host that public address.<p>
+
+These are the addresses that the SMBD daemons and other services will
+bind to and which clients will use to connect to the cluster.<p>
+
+<h3>Example 4 node cluster:</h3>
+<pre>
+  CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses
+</pre>
+Content of /etc/ctdb/public_addresses:
+<pre>
+ 192.168.1.1/24 eth0
+ 192.168.1.2/24 eth0
+ 192.168.2.1/24 eth1
+ 192.168.2.2/24 eth1
+</pre>
+
+These are the IP addresses that you should configure in DNS for the
+name of the clustered samba server and are the addresses that CIFS
+clients will connect to.<p>
+
+Configure it as one DNS A record (==name) with multiple IP addresses
+and let round-robin DNS distribute the clients across the nodes of the
+cluster.<p>
+
+The CTDB cluster utilizes IP takeover techniques to ensure that as long as at least one node in the cluster is available, all the public IP addresses will always be available to clients.<p>
+
+This means that if one physical node fails, the public addresses that
+node was serving will be taken over by a different node in the cluster. This
+provides a guarantee that all ip addresses exposed to clients will
+always be reachable by clients as long as at least one node still remains available in the cluster with the capability to host that public address (i.e. the public address exists in that nodes public_addresses file).
+
+Do not assign these addresses to any of the interfaces on the
+host. CTDB will add and remove these addresses automatically at
+runtime.<p>
+
+This parameter is used when CTDB operated in takeover ip mode.<p>
+
+The usual location for this file is /etc/ctdb/public_addresses.<p><p>
+
+<h3>Example 2:</h3>
+By using different public_addresses files on different nodes it is possible to 
+partition the cluster into subsets of nodes.
+
+<pre>
+Node 0 : /etc/ctdb/public_addresses
+10.1.1.1/24 eth0
+10.1.2.1/24 eth1
+</pre>
+
+<pre>
+Node 1 : /etc/ctdb/public_addresses
+10.1.2.1/24 eth1
+10.1.3.1/24 eth2
+</pre>
+
+<pre>
+Node 2 : /etc/ctdb/public_addresses
+10.1.3.2/24 eth2
+</pre>
+
+In this example we have three nodes but a total of 4 public addresses.<p>
+
+10.1.2.1 can be hosted by either node 0 or node 1 and will be available to clients as long as at least one of these nodes are available. Only if both nodes 0 and 1 fails will this public address become unavailable to clients.<p>
+
+All other public addresses can only be served by one single node respectively and will therefore only be avialable if the respective node is also available.
+
+
+<h2>Event scripts</h2>
+
+CTDB comes with a number of application specific event scripts that
+are used to do service specific tasks when the cluster has been
+reconfigured. These scripts are stored in /etc/ctdb/events.d/<p>
+
+You do not need to modify these scripts if you just want to use
+clustered Samba or NFS but they serve as examples in case you want to
+add clustering support for other application servers we do not yet
+proivide event scripts for.<p>
+
+Please see the service scripts that installed by ctdb in
+/etc/ctdb/events.d for examples of how to configure other services to
+be aware of the HA features of CTDB.<p>
+
+Also see /etc/ctdb/events.d/README for additional documentation on how to
+create and manage event scripts.
+
+<h2>TCP port to use for CTDB</h2>
+
+CTDB defaults to use TCP port 4379 for its traffic.<p>
+
+Configuring a different port to use for CTDB traffic is done by adding
+a ctdb entry to the /etc/services file.<p>
+
+Example: for change CTDB to use port 9999 add the following line to /etc/services
+<pre>
+ ctdb  9999/tcp
+</pre>
+
+Note: all nodes in the cluster MUST use the same port or else CTDB
+will not start correctly.
+
+<h2>Name resolution</h2>
+
+You need to setup some method for your Windows and NFS clients to find
+the nodes of the cluster, and automatically balance the load between
+the nodes.<p>
+
+We recommend that you use public ip addresses using
+CTDB_PUBLIC_INTERFACE/CTDB_PUBLIC_ADDRESSES and that you setup a
+round-robin DNS entry for your cluster, listing all the public IP
+addresses that CTDB will be managing as a single DNS A record.<p>
+
+You may also wish to setup a static WINS server entry listing all of
+your cluster nodes IP addresses.
+
+<!--#include virtual="footer.html" -->

Added: branches/ctdb/squeeze-backports/web/ctdblogo.png
===================================================================
(Binary files differ)


Property changes on: branches/ctdb/squeeze-backports/web/ctdblogo.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: branches/ctdb/squeeze-backports/web/documentation.html
===================================================================
--- branches/ctdb/squeeze-backports/web/documentation.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/documentation.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<!--#set var="TITLE" value="CTDB Documentation" -->
+<!--#include virtual="header.html" -->
+
+<h1>CTDB Documentation</h1>
+
+The following documentation should get you started with CTDB. 
+
+<ul>
+<li><a href="prerequisites.html">Prerequisites</a>
+<li><a href="download.html">Downloading CTDB</a>
+<li><a href="building.html">Building CTDB</a>
+<li><a href="configuring.html">Configuring CTDB</a>
+<li><a href="configuring.html">Testing CTDB</a>
+<li><a href="samba.html">Setting up Samba with CTDB</a>
+<li><a href="ftp.html">Setting up FTP with CTDB</a>
+<li><a href="nfs.html">Setting up NFS with CTDB</a>
+<li><a href="iscsi.html">Setting up iSCSI with CTDB</a>
+<li><a href="clamd.html">Setting up CLAMD with CTDB</a>
+<li><a href="http://wiki.samba.org/index.php/CTDB_Setup">CTDB Wiki</a>
+</ul>
+
+Man pages:
+<ul>
+<li><a href="http://ctdb.samba.org/~tridge/ctdb/doc/ctdb.1.html">ctdb manual page</a>
+<li><a href="http://ctdb.samba.org/~tridge/ctdb/doc/ctdbd.1.html">ctdbd manual page</a>
+<li><a href="http://ctdb.samba.org/~tridge/ctdb/doc/onnode.1.html">onnode manual page</a>
+</ul>
+
+Articles:
+<ul>
+<li><a href="http://samba.org/~obnox/presentations/sambaXP-2009/">Michael
+    Adam's clustered NAS articles</a>
+</ul>
+
+<!--#include virtual="footer.html" -->

Added: branches/ctdb/squeeze-backports/web/download.html
===================================================================
--- branches/ctdb/squeeze-backports/web/download.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/download.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,47 @@
+<!--#set var="TITLE" value="Downloading CTDB" -->
+<!--#include virtual="header.html" -->
+
+<H2 align="center">Getting the code</h2>
+
+You need two source trees, one is a copy of Samba3 with clustering
+patches, and the other is the ctdb code itself.<p>
+
+Both source trees are stored in git repositories.<p>
+
+<h2>CTDB</h2>
+To get an initial checkout of the ctdb code do this:
+<pre>
+   git clone git://git.samba.org/ctdb.git ctdb
+</pre>
+
+To update this tree when improvements are made in the upstream code do this:
+<pre>
+    cd ctdb
+    git pull
+</pre>
+
+If you don't have git and can't easily install it, then you can
+instead use the following command to fetch ctdb or update it:
+<pre>
+    rsync -avz samba.org::ftp/unpacked/ctdb .
+</pre>
+
+
+<h2>Samba3 ctdb version</h2>
+<p>
+With Samba version 3.3 all cluster-relevant changes have been merged
+to the mainstream Samba code. Please refer to the <a
+href="http://www.samba.org/">Samba website</a> for the current release
+information.
+</p>
+
+<h2>Binary Packages</h2>
+
+Note that packages are so far only available for RHEL5. Other packages
+may come later. <p>
+
+See <a href="packages/">packages</a> directory for package
+downloads.
+
+
+<!--#include virtual="footer.html" -->

Added: branches/ctdb/squeeze-backports/web/footer.html
===================================================================
--- branches/ctdb/squeeze-backports/web/footer.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/footer.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,39 @@
+</td>
+</tr>
+
+  <TR ALIGN="center">
+    <TD><BR><a name="search"></a><img src="/bar1.jpg" WIDTH="493" HEIGHT="26" BORDER="0" alt="=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=">
+
+<!-- SiteSearch Google -->
+<form method="get" action="http://www.google.com/custom">
+<table border="0">
+<tr><td nowrap="nowrap" valign="top" align="left" height="32">
+<a href="http://www.google.com/"><img src="http://www.google.com/logos/Logo_25wht.gif" border="0" alt="Google" /></a>
+</td><td nowrap="nowrap">
+<input type="hidden" name="domains" value="samba.org" />
+<input type="text" name="q" size="31" maxlength="255" value="CTDB " />
+<input type="submit" name="sa" value="Search" />
+</td></tr><tr><td> </td>
+<td nowrap="nowrap">
+<table><tr><td>
+<input type="radio" name="sitesearch" value="" />
+<font size="-1" color="#000000">Search WWW</font>
+</td><td>
+<input type="radio" name="sitesearch" value="samba.org" checked="checked" />
+<font size="-1" color="#000000">Search samba.org</font>
+</td></tr></table>
+<input type="hidden" name="client" value="pub-1444957896811922" />
+<input type="hidden" name="forid" value="1" />
+<input type="hidden" name="ie" value="ISO-8859-1" />
+<input type="hidden" name="oe" value="ISO-8859-1" />
+<input type="hidden" name="cof"
+       value="GALT:#008000;GL:1;DIV:#336699;VLC:663399;AH:center;BGC:FFFFFF;LBGC:FFFFFF;ALC:0000FF;LC:0000FF;T:000000;GFNT:0000FF;GIMP:0000FF;LH:60;LW:470;L:http://samba.org/samba/images/samba_banner.gif;S:http://samba.org/;FORID:1;"
+       />
+<input type="hidden" name="hl" value="en" />
+</td></tr></table>
+</form>
+<!-- SiteSearch Google -->
+
+  </TD>
+  </TR>
+</TABLE>

Added: branches/ctdb/squeeze-backports/web/ftp.html
===================================================================
--- branches/ctdb/squeeze-backports/web/ftp.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/ftp.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,102 @@
+<!--#set var="TITLE" value="CTDB and ftp" -->
+<!--#include virtual="header.html" -->
+
+<h1>Setting up clustered FTP</h1>
+
+<h2>Prereqs</h2>
+Configure CTDB as above and set it up to use public ipaddresses.<br>
+Verify that the CTDB cluster works.
+
+<h2>Configuration</h2>
+
+Setting up a vsftpd cluster is really easy.<br>
+Configure vsftpd on each node on the cluster.<br><br>
+Set up vsftpd to export directories from the shared cluster filesystem.
+
+<h2>/etc/sysconfig/ctdb</h2>
+
+Add the following line to the /etc/sysconfig/ctdb configuration file.
+<pre>
+  CTDB_MANAGES_VSFTPD=yes
+</pre>
+
+Disable vsftpd in chkconfig so that it does not start by default. Instead CTDB will start/stop vsftdp as required.
+<pre>
+  chkconfig vsftpd off
+</pre>
+
+<h2>PAM configuration</h2>
+PAM must be configured to allow authentication of CIFS users so that the ftp 
+daemon can authenticate the users logging in.
+
+Make sure the following line is present in /etc/pam.d/system-auth
+<pre>
+auth        sufficient    pam_winbind.so use_first_pass
+
+</pre>
+If this line is missing you must enable winbind authentication by running 
+<pre>
+authconfig  --enablewinbindauth --update
+authconfig  --enablewinbind --update
+</pre>
+
+<h2>Default shell</h2>
+To log in to the ftp server, the user must have a shell configured in smb.conf.
+
+Add the following line to the globals section of /etc/samba/smb.conf 
+<pre>
+	template shell = /bin/bash
+</pre>
+
+<h2>Home directory</h2>
+FTP users must have a home directory configured so they can log in.
+Configure samba to provide home directories for domain users. These home 
+directories should be stored on shared storage so they are available from
+all nodes in the cluster.<br>
+
+
+A simple way to create homedirectories are to add
+<pre>
+	template homedir = /<shared storage>/homedir/%D/%U
+</pre>
+to /etc/samba/smb.conf .<br>
+
+The homedirectory must exist or the user will not be able to log in with FTP.
+
+
+<h2>Events script</h2>
+
+The CTDB distribution already comes with an events script for vsftp in the file /etc/ctdb/events.d/40.vsftpd<br><br>
+There should not be any need to edit this file.
+
+
+<h2>Restart your cluster</h2>
+Next time your cluster restarts, CTDB will start managing the vsftp service.<br><br>
+If the cluster is already in production you may not want to restart the entire cluster since this would disrupt services.<br>
+
+Insted you can just disable/enable the nodes one by one. Once a node becomes enabled again it will start the vsftp service.<br><br>
+
+Follow the procedure below for each node, one node at a time :
+
+<h3>1 Disable the node</h3>
+Use the ctdb command to disable the node :
+<pre>
+  ctdb -n NODE disable
+</pre>
+
+<h3>2 Wait until the cluster has recovered</h3>
+
+Use the ctdb tool to monitor until the cluster has recovered, i.e. Recovery mode is NORMAL. This should happen within seconds of when you disabled the node.
+<pre>
+  ctdb status
+</pre>
+
+<h3>3 Enable the node again</h3>
+
+Re-enable the node again which will start the newly configured vsftp service.
+<pre>
+  ctdb -n NODE enable
+</pre>
+
+<!--#include virtual="footer.html" -->
+

Added: branches/ctdb/squeeze-backports/web/header.html
===================================================================
--- branches/ctdb/squeeze-backports/web/header.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/header.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE><!--#echo var="TITLE" --></TITLE>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555"
+      ALINK="#cc0033">
+<TABLE BORDER=0 WIDTH="75%" ALIGN="CENTER">
+  <tr VALIGN="middle">
+    <td ALIGN="left">
+	<ul>
+      <li><small><a href="/">home</a></small>
+      <li><small><a href="/documentation.html">documentation</a></small>
+      <li><small><a href="/configuring.html">configuring</a></small>
+      <li><small><a href="/building.html">building</a></small>
+	</ul>
+    </td>
+    <td align="center">
+      <a href="."><img src="/ctdblogo.png" border="0" alt="CTDB"></a>
+    </td>
+    <td align="left">
+      <ul>
+      <li><small><a href="/download.html">download</a></small>
+      <li><small><a href="/testing.html">testing</a></small>
+      <li><small><a href="http://wiki.samba.org/index.php/CTDB_Setup">wiki</a></small>
+      <li><small><a href="http://bugzilla.samba.org/">bug-tracking</a></small>
+      </ul>
+    </td>
+  </tr>
+
+  <TR ALIGN="center">
+    <TD COLSPAN="3">
+    <img src="/bar1.jpg" WIDTH="493" HEIGHT="26"
+    BORDER="0"
+    alt="=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=">
+    </TD>
+  </TR>
+</TABLE>
+
+<TABLE BORDER=0 WIDTH="60%" ALIGN="CENTER">
+  <tr VALIGN="middle">
+    <td ALIGN="left">

Added: branches/ctdb/squeeze-backports/web/index.html
===================================================================
--- branches/ctdb/squeeze-backports/web/index.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/index.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,140 @@
+<!--#set var="TITLE" value="CTDB" -->
+<!--#include virtual="header.html" -->
+
+<H2 align="center">Welcome to the CTDB web pages</H2>
+
+CTDB is a cluster implementation of the TDB database used by Samba and
+other projects to store temporary data. If an application is already
+using TDB for temporary data it is very easy to convert that
+application to be cluster aware and use CTDB instead.
+
+<p>CTDB provides the same types of functions as TDB but in a clustered
+  fashion, providing a TDB-style database that spans multiple physical
+  hosts in a cluster.
+
+<p>Features include:
+<ul>
+<li>CTDB provides a TDB that has consistent data and consistent locking across
+all nodes in a cluster.
+<li>CTDB is very fast.
+<li>In case of node failures, CTDB will automatically recover and
+  repair all TDB databases that it manages.
+<li>CTDB is the core component that provides <strong>pCIFS</strong>
+("parallel CIFS") with Samba3/4.
+<li>CTDB provides HA features such as node monitoring, node failover,
+  and IP takeover.
+<li>CTDB provides a reliable messaging transport to allow applications
+ linked with CTDB to communicate to other instances of the application
+ running on different nodes in the cluster.
+<li>CTDB has pluggable transport backends. Currently implemented backends are TCP
+ and Infiniband.
+<li>CTDB supports a system of application specific management scripts,
+  allowing applications that depend on network or filesystem resources
+  to be managed in a highly available manner on a cluster.
+</ul>
+
+<h2>Requirements</h2>
+
+CTDB relies on a clustered filesystem being available and shared on
+all nodes that participate in the CTDB cluster. This filesystem must
+be mounted and available on all nodes in the CTDB cluster.
+
+<p>On top of this cluster filesystem, CTDB then provides clustered HA
+features so that data from the clustered filesystem can be exported
+through multiple nodes in the CTDB cluster using various
+services. Currently included with CTDB are the necessary hooks for Samba, NFS
+  and ftp exports. Support for new service types can easily be added.
+
+<h2>TDB</h2>
+
+TDB is a very fast simple database that was originally developed for
+use in Samba. Today several other projects use TDB to store their data.
+
+<p>See the <a
+href="http://samba.org/ftp/unpacked/tdb/docs/README">TDB
+README file</a> for a description of how TDB is used.
+
+<h2>Documentation</h2>
+
+<a href="./documentation.html">CTDB documentation</a><br><br>
+
+Additional documentation on how to install and configure CTDB is available in the
+<a href="http://wiki.samba.org/index.php/CTDB_Setup">CTDB
+  Wiki</a>. Please read all of the documentation carefully.
+
+<h2>High Availability Features</h2>
+
+The CTDB nodes in a cluster designates one node as a recovery master
+through an election process. If the recovery master node fails a
+new election is initiated so that the cluster will always guarantee
+there will be a recovery master. The recovery master will
+continuously monitor the cluster to verify that all nodes contain a
+consistent configuration and view of the cluster and will initiate a
+recovery process when required.
+
+<p>During the recovery phase, the recovery master will automatically
+rebuild/recover all clustered TDB database to ensure that the
+databases are consistent. Recovery typically takes between 1 and 3
+seconds. During the recovery period the databases are 'frozen', and
+all database IO operations by ctdb clients are suspended.
+
+<h3>Is CTDB a HA solution?</h3>
+
+Yes and no.<p>
+
+CTDB alone is not a HA solution, but when you combine CTDB with a clustered 
+filesystem it becomes one.<p>
+
+CTDB is primarily developed around the concept of having a shared
+cluster filesystem across all the nodes in the cluster to provide the
+features required for building a NAS cluster.<p>
+
+Thus CTDB relies on an external component (the cluster filesystem) to
+provide the mechanisms for avoiding split-brain and other core
+clustering tasks.<p>
+
+However, if you do have a clustered filesystem for all the nodes, in
+that scenario CTDB will provide a very easy to install and manage
+solution for your clustering HA needs.
+
+<h3>IP Takeover</h3>
+
+When a node in a cluster fails, CTDB will arrange that a different
+node takes over the IP address of the failed node to ensure that the
+IP addresses for the services provided are always available.
+
+<p>To speed up the process of IP takeover and when clients attached to
+a failed node recovers as fast as possible, CTDB will automatically
+generate gratuitous ARP packets to inform all nodes of the changed MAC
+address for that IP.  CTDB will also send "tickle ACK" packets to all
+attached clients to trigger the clients to immediately recognize that
+the TCP connection needs to be re-established and to shortcut any TCP
+retransmission timeouts that may be active in the clients.
+
+<h2>Discussion and bug reports</h2>
+
+For discussions please use
+the <a href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list. To submit a bug report, please use
+the <a href="http://bugzilla.samba.org/">Samba bugzilla</a> bug
+tracking system.
+
+<p>We would be very interested in hearing from and work with other
+projects that want to make their services cluster aware using CTDB.
+
+<p>CTDB discussions also happen on the #ctdb IRC channel on freenode.net
+
+
+<hr>
+<h2>Developers</h2>
+<ul>
+<li><a href="http://samba.org/~tridge/">Andrew Tridgell</a></li>
+<li><a href="http://samba.org/~sahlberg/">Ronnie Sahlberg</a></li>
+<li><a href="http://samba.org/~obnox/">Michael Adam</a></li>
+<li>Peter Somogyi</li>
+<li><a href="http://sernet.de/Samba/">Volker Lendecke</a></li>
+<li>Stefan Metzmacher</li>
+<li><a href="http://meltin.net/people/martin/">Martin Schwenke</a></li>
+</ul>
+
+<!--#include virtual="footer.html" -->

Added: branches/ctdb/squeeze-backports/web/iscsi.html
===================================================================
--- branches/ctdb/squeeze-backports/web/iscsi.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/iscsi.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,113 @@
+<!--#set var="TITLE" value="CTDB and iSCSI" -->
+<!--#include virtual="header.html" -->
+
+<h1>Setting up HA iSCSI with CTDB</h1>
+
+<p>
+You can use CTDB to create a HA iSCSI Target.
+</p>
+
+<p>
+Since the iSCSI Target is not
+clusterized nor integrated with CTDB in the same sense Samba is, this
+implementation will only create a HA solution for iSCSI where each public address is assinged its own iscsi target name and the LUNs that are created are only accessible through one specific target (i.e. one public address at a time).
+
+</p>
+
+<p>
+! This feature ONLY works when public addresses are used. It is not supported, nor does it work, if you use the LVS feature to present the entire cluster as one single ip address. !
+
+</p>
+
+<h2>Prereqs</h2>
+Configure CTDB as above and set it up to use public ipaddresses.<br>
+Verify that the CTDB cluster works.
+
+<h2>Install the iSCSI target software on all nodes</h2>
+On RHEL5 this package is called "scsi-target-utils" and it needs to be installed
+on all nodes in the cluster. The easiest way to install this package is by using :
+
+<pre>
+onnode all yum install scsi-target-utils -y
+</pre>
+
+Make sure that the service is not started automatically when booting, we want CTDB to start/stop this service :
+<pre>
+onnode all chkconfig tgtd off
+</pre>
+
+<h2>/etc/sysconfig/iscsi</h2>
+
+Create this file and add the following three lines to it :
+
+<pre>
+   CTDB_START_ISCSI_SCRIPTS=/gpfs/iscsi/
+</pre>
+
+<p>
+CTDB_START_ISCSI_SCRIPTS=<directory on shared storage>
+This is a directory on shared storage where the scripts to start and configure the iscsi service are held. There is one script for each public address named <public address>.sh .
+</p>
+
+
+<h2>/etc/sysconfig/ctdb</h2>
+
+Add the following line to /etc/sysconfig/ctdb :
+
+<pre>
+   CTDB_MANAGES_ISCSI=yes
+</pre>
+
+<p>
+CTDB_MANAGES_ISCSI=yes just tells CTDB event script for iSCSI that CTDB should start and stop the iSCSI target service as required.
+</p>
+
+
+<h2>Example: create a LUN that will be hosted on public ip address 10.1.1.1</h2>
+<p>
+Before you cna export a LUN you must create it as a file in the shared filesystem. When doing so, make sure you create it as a real file and not a sparse file!<br />
+While it is much quicker to create a sparse file if you want a file with filesize 100Gb, SCSI has no concept of "disk full" so if you run out of backing space for the sparse file, the scsi initiators will be "surprised" and "unhappy".
+</p>
+<pre>
+dd if=/dev/zero of=/gpfs/iscsi/10.1.1.1.lun.1 bs=1024 count=102400
+</pre>
+<p>
+to create a 100MByte file to export as an iSCSI LUN.
+</p>
+
+<h2>Example: 10.1.1.1.sh</h2>
+<p>
+This example shellscript is used to configure the iscsi target that is hosted onthe public address 10.1.1.1
+</p>
+<pre>
+#!/bin/sh
+# script to set up the iscsi target and luns hosted by public address
+# 10.1.1.1
+
+
+#create a target
+tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.2007-11.com.ctdb:iscsi.target.10.1.1.1
+
+#attach a lun
+tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun 1 -b /gpfs/iscsi/10.1.1.1.lun.1
+
+# no security, allow everyone to access this lun
+tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
+</pre>
+
+
+<p>
+iqn.2007-11.com.ctdb:iscsi.target.10.1.1.1 in the example above is the iscsi name that is assigned to the target. Dont use this name, pick your own name!
+</p>
+
+<p>
+See the documentation for the tgtadm command for more information on how you want to set up your environment.
+</p>
+
+<h2>Perform a ctdb recovery to start the iscsi service</h2>
+<pre>
+ctdb recover
+</pre>
+
+<!--#include virtual="footer.html" -->
+

Added: branches/ctdb/squeeze-backports/web/nfs.html
===================================================================
--- branches/ctdb/squeeze-backports/web/nfs.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/nfs.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,96 @@
+<!--#set var="TITLE" value="CTDB and NFS" -->
+<!--#include virtual="header.html" -->
+
+<h1>Setting up clustered NFS</h1>
+
+NFS v2/v3 has been successfully tested with exporting the same
+data/network share from multiple nodes in a CTDB cluster with correct
+file locking behaviour and lock recovery.<br><br>
+
+Also see <a href="http://wiki.samba.org/index.php/CTDB_Setup#Setting_up_CTDB_for_clustered_NFS">Configuring
+NFS for CTDB clustering</a> at samba.org for additional information.
+
+<h2>Prereqs</h2>
+Configure CTDB as above and set it up to use public ipaddresses.<br>
+Verify that the CTDB cluster works.
+
+<h2>/etc/exports</h2>
+
+Export the same directory from all nodes.<br>
+Make sure to specify the fsid export option so that all nodes will present the same fsid to clients.<br>
+
+Clients can get "upset" if the fsid on a mount suddenly changes.<br>
+Example /etc/exports :
+<pre>
+  /gpfs0/data *(rw,fsid=1235)
+</pre>
+
+<h2>/etc/sysconfig/nfs</h2>
+
+This file must be edited to point statd to keep its state directory on 
+shared storage instead of in a local directory.<br><br>
+
+We must also make statd use a fixed port to listen on that is the same for 
+all nodes in the cluster.<br>
+
+If we don't specify a fixed port, the statd port will change during failover 
+which causes problems on some clients.<br>
+(some clients are very slow to realize when the port has changed)<br><br>
+
+This file should look something like :
+<pre>
+  NFS_HOSTNAME=ctdb
+  STATD_PORT=595
+  STATD_OUTGOING_PORT=596
+  MOUNTD_PORT=597
+  RQUOTAD_PORT=598
+  LOCKD_TCPPORT=599
+  LOCKD_UDPPORT=599
+  STATD_HOSTNAME="$NFS_HOSTNAME -H /etc/ctdb/statd-callout -p 97"
+  RPCNFSDARGS="-N 4"
+
+</pre>
+
+You need to make sure that the lock manager runs on the same port on all nodes in the cluster since some clients will have "issues" and take very long to recover if the port suddenly changes.<br>
+599 above is only an example. You can run the lock manager on any available port as long as you use the same port on all nodes.<br><br>
+
+NFS_HOSTNAME is the dns name for the ctdb cluster and which is used when clients map nfs shares. This name must be in DNS and resolve back into the public ip addresses of the cluster.<br>
+Always use the same name here as you use for the samba hostname.
+
+RPCNFSDARGS is used to disable support for NFSv4 which is not yet supported by CTDB.
+
+<h2>/etc/sysconfig/ctdb</h2>
+Add the following line to /etc/sysconfig/ctdb :
+
+<pre>
+  CTDB_MANAGES_NFS=yes
+</pre>
+The CTDB_MANAGES_NFS line tells the events scripts that CTDB is to manage startup and shutdown of the NFS and NFSLOCK services.<br>
+
+With this set to yes, CTDB will start/stop/restart these services as required.<br><br>
+
+
+<h2>chkconfig</h2>
+
+Since CTDB will manage and start/stop/restart the nfs and the nfslock services, you must disable them using chkconfig.
+<pre>
+  chkconfig nfs off
+  chkconfig nfslock off
+</pre>
+
+
+<h2>Event scripts</h2>
+
+CTDB clustering for NFS relies on two event scripts /etc/ctdb/events.d/60.nfs and /etc/ctdb/events.d/61.nfstickle.<br>
+
+These two scripts are provided by the RPM package and there should not be any need to change them.
+
+<h2><strong>IMPORTANT</strong></h2>
+
+Never ever mount the same nfs share on a client from two different nodes in the cluster at the same time!<br><br>
+
+The client side caching in NFS is very fragile and assumes/relies on that an object can only be accessed through one single path at a time.
+
+
+<!--#include virtual="footer.html" -->
+

Added: branches/ctdb/squeeze-backports/web/prerequisites.html
===================================================================
--- branches/ctdb/squeeze-backports/web/prerequisites.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/prerequisites.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,18 @@
+<!--#set var="TITLE" value="CTDB prerequisites" -->
+<!--#include virtual="header.html" -->
+
+<h1>Prerequisites</h1>
+
+Before you can start using CTDB you must first install and configure a bunch of linux boxes.<br><br>
+
+After that you need to install and configure a cluster filesystem and mount that cluster filesystem on all the linux boxes that will form your cluster.<br><br>
+
+We have primarily used the GPFS filesystem for our testing but any cluster filesystem should work as long as it provides correct file locking.<br>
+
+<h1>Other cluster filesystems</h1>
+While we primarily test with GPFS, CTDB should work with almost any other cluster filesystem as well.<br><br>
+Please let us know your experiences in using other cluster filesystems.
+
+
+<!--#include virtual="footer.html" -->
+

Added: branches/ctdb/squeeze-backports/web/samba.html
===================================================================
--- branches/ctdb/squeeze-backports/web/samba.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/samba.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,103 @@
+<!--#set var="TITLE" value="CTDB and Samba" -->
+<!--#include virtual="header.html" -->
+
+<h1>Setting up clustered samba</h1>
+
+It is assumed tou have already installed the ctdb version of samba and also installed, configured and tested CTDB.
+
+<h2>Create a user account</h2>
+
+First you need to initialise the Samba password database so that you have some user that can authenticate to the samba service.<br>
+Do this by running:
+<pre>
+  smbpasswd -a root
+</pre>
+
+Samba with clustering must use the tdbsam or ldap SAM passdb backends (it must not use the default smbpasswd backend), or must be configured to be a member of a domain.<br>
+The rest of the configuration of Samba is exactly as it is done on a normal system.<br><br>
+See the docs on http://samba.org/ for details.
+
+<h2>Critical smb.conf parameters</h2>
+
+A clustered Samba install must set some specific configuration parameters
+<pre>
+  clustering = yes
+  idmap backend = tdb2
+  private dir = /a/directory/on/your/cluster/filesystem
+</pre>
+
+It is vital that the private directory is on shared storage. 
+
+<h2>Using smbcontrol</h2>
+
+You can check for connectivity to the smbd daemons on each node using smbcontrol
+<pre>
+  smbcontrol smbd ping
+</pre>
+
+<h2>Using Samba4 smbtorture</h2>
+
+The Samba4 version of smbtorture has several tests that can be used to benchmark a CIFS cluster.<br>
+You can download Samba4 like this:
+<pre>
+  svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0
+</pre>
+Then configure and compile it as usual.<br>
+The particular tests that are helpful for cluster benchmarking are the RAW-BENCH-OPEN, RAW-BENCH-LOCK and BENCH-NBENCH tests.<br>
+These tests take a unclist that allows you to spread the workload out over more than one node. For example:
+
+<pre>
+  smbtorture //localhost/data -Uuser%password  RAW-BENCH-LOCK --unclist=unclist.txt --num-progs=32 -t60
+</pre>
+
+The file unclist.txt should contain a list of server names in your cluster prefixed by //. For example
+<pre>
+ //192.168.1.1
+ //192.168.1.2
+ //192.168.2.1
+ //192.168.2.2
+</pre>
+
+For NBENCH testing you need a client.txt file.<br>
+A suitable file can be found in the dbench distribution at http://samba.org/ftp/tridge/dbench/
+
+
+<h3>CTDB_MANAGES_SAMBA</h3>
+This is a parameter in /etc/sysconfig/ctdb<br><br>
+When this parameter is set to "yes" CTDB will start/stop/restart the local samba daemon as the cluster configuration changes.<br><br>
+When this parameter is set you should also make sure that samba is NOT started by default by the linux system when it boots, e.g.
+<pre>
+  chkconfig smb off
+</pre>
+on a Redhat system and
+<pre>
+  chkconfig smb off
+  chkconfig nmb off
+</pre>
+on a SuSE system.
+
+Example:
+<pre>
+  CTDB_MANAGES_SAMBA="yes"
+</pre>
+
+It is strongly recommended that you set this parameter to "yes" if you intend to use clustered samba.
+
+<h3>CTDB_MANAGES_WINBIND</h3>
+This is a parameter in /etc/sysconfig/ctdb<br><br>
+When this parameter is set to "yes" CTDB will start/stop/restart the local winbind daemon as the cluster configuration changes.<br><br>
+When this parameter is set you should also make sure that winbind is NOT started by default by the linux system when it boots:
+<pre>
+  chkconfig winbind off
+</pre>
+
+Example:
+<pre>
+  CTDB_MANAGES_WINBIND="yes"
+</pre>
+
+It is strongly recommended that you set this parameter to "yes" if you
+intend to use clustered samba in DOMAIN or ADS security mode.
+
+<!--#include virtual="footer.html" -->
+

Added: branches/ctdb/squeeze-backports/web/testing.html
===================================================================
--- branches/ctdb/squeeze-backports/web/testing.html	                        (rev 0)
+++ branches/ctdb/squeeze-backports/web/testing.html	2012-01-15 21:10:16 UTC (rev 3989)
@@ -0,0 +1,112 @@
+<!--#set var="TITLE" value="CTDB Testing" -->
+<!--#include virtual="header.html" -->
+
+<H2 align="center">Starting and testing CTDB</h2>
+
+The CTDB log is in /var/log/log.ctdb so look in this file if something
+did not start correctly.<p>
+
+You can ensure that ctdb is running on all nodes using
+<pre>
+  onnode all service ctdb start
+</pre>
+Verify that the CTDB daemon started properly. There should normally be at least 2 processes started for CTDB, one for the main daemon and one for the recovery daemon.
+<pre>
+  onnode all pidof ctdbd
+</pre>
+
+Once all CTDB nodes have started, verify that they are correctly
+talking to each other.<p>
+
+There should be one TCP connection from the private ip address on each
+node to TCP port 4379 on each of the other nodes in the cluster.
+<pre>
+  onnode all netstat -tn | grep 4379
+</pre>
+
+
+<h2>Automatically restarting CTDB</h2>
+
+If you wish to cope with software faults in ctdb, or want ctdb to
+automatically restart when an administration kills it, then you may
+wish to add a cron entry for root like this:
+
+<pre>
+ * * * * * /etc/init.d/ctdb cron > /dev/null 2>&1
+</pre>
+
+
+<h2>Testing CTDB</h2>
+
+Once your cluster is up and running, you may wish to know how to test that it is functioning correctly. The following tests may help with that
+
+<h3>The ctdb tool</h3>
+
+The ctdb package comes with a utility called ctdb that can be used to
+view the behaviour of the ctdb cluster.<p>
+
+If you run it with no options it will provide some terse usage information. The most commonly used commands are:
+<pre>
+ ctdb status
+ ctdb ip
+ ctdb ping
+</pre>
+
+<h3>ctdb status</h3>
+
+The status command provides basic information about the cluster and the status of the nodes. when you run it you will get some output like:
+
+<pre>
+<strong>Number of nodes:4
+vnn:0 10.1.1.1       OK (THIS NODE)
+vnn:1 10.1.1.2       OK
+vnn:2 10.1.1.3       OK
+vnn:3 10.1.1.4       OK</strong>
+Generation:1362079228
+Size:4
+hash:0 lmaster:0
+hash:1 lmaster:1
+hash:2 lmaster:2
+hash:3 lmaster:3
+<strong>Recovery mode:NORMAL (0)</strong>
+Recovery master:0
+</pre>
+
+The important parts are in bold. This tells us that all 4 nodes are in
+a healthy state.<p>
+
+It also tells us that recovery mode is normal, which means that the
+cluster has finished a recovery and is running in a normal fully
+operational state.<p>
+
+Recovery state will briefly change to "RECOVERY" when there ahs been a
+node failure or something is wrong with the cluster.<p>
+
+If the cluster remains in RECOVERY state for very long (many seconds)
+there might be something wrong with the configuration. See
+/var/log/log.ctdb.
+
+<h3>ctdb ip</h3>
+
+This command prints the current status of the public ip addresses and which physical node is currently serving that ip.
+
+<pre>
+Number of nodes:4
+192.168.1.1         0
+192.168.1.2         1
+192.168.2.1         2
+192.168.2.1         3
+</pre>
+
+<h3>ctdb ping</h3>
+this command tries to "ping" each of the CTDB daemons in the cluster.
+<pre>
+  ctdb ping -n all
+
+  response from 0 time=0.000050 sec  (13 clients)
+  response from 1 time=0.000154 sec  (27 clients)
+  response from 2 time=0.000114 sec  (17 clients)
+  response from 3 time=0.000115 sec  (59 clients)
+</pre>
+
+<!--#include virtual="footer.html" -->





More information about the Pkg-samba-maint mailing list