From 23b61265b85f321ae2ceddc6c75771f8881566d8 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 5 Sep 2008 10:13:10 -0400 Subject: Initial Import --- events/Makefile.in | 77 + events/autogen.sh | 16 + events/build_macros.m4 | 14 + events/config.guess | 1464 ++++++ events/config.mk | 58 + events/config.sub | 1577 ++++++ events/configure.ac | 40 + events/events.c | 310 ++ events/events.h | 98 + events/events.i | 54 + events/events.mk | 59 + events/events.pc.in | 11 + events/events.py | 94 + events/events_aio.c | 567 +++ events/events_debug.c | 83 + events/events_epoll.c | 482 ++ events/events_internal.h | 158 + events/events_liboop.c | 288 ++ events/events_s4.c | 108 + events/events_select.c | 302 ++ events/events_signal.c | 291 ++ events/events_standard.c | 607 +++ events/events_timed.c | 230 + events/events_util.c | 85 + events/events_util.h | 117 + events/events_wrap.c | 3343 +++++++++++++ events/install-sh | 238 + events/libevents.m4 | 49 + events/libtalloc.m4 | 7 + events/pkg.m4 | 156 + events/rules.mk | 21 + events/tests.py | 31 + events/testsuite.c | 145 + ldb/Doxyfile | 26 + ldb/Makefile.in | 183 + ldb/README_gcov.txt | 29 + ldb/aclocal.m4 | 1 + ldb/autogen.sh | 18 + ldb/build_macros.m4 | 14 + ldb/common/attrib_handlers.c | 378 ++ ldb/common/ldb.c | 1261 +++++ ldb/common/ldb_attributes.c | 227 + ldb/common/ldb_controls.c | 577 +++ ldb/common/ldb_debug.c | 103 + ldb/common/ldb_dn.c | 1463 ++++++ ldb/common/ldb_ldif.c | 757 +++ ldb/common/ldb_match.c | 428 ++ ldb/common/ldb_modules.c | 625 +++ ldb/common/ldb_msg.c | 899 ++++ ldb/common/ldb_parse.c | 819 +++ ldb/common/ldb_utf8.c | 136 + ldb/common/qsort.c | 251 + ldb/config.guess | 1464 ++++++ ldb/config.mk | 151 + ldb/config.sub | 1577 ++++++ ldb/configure.ac | 102 + ldb/docs/builddocs.sh | 52 + ldb/docs/design.txt | 41 + ldb/docs/installdocs.sh | 17 + ldb/examples.dox | 16 + ldb/examples/ldbreader.c | 123 + ldb/examples/ldifreader.c | 127 + ldb/external/libevents.m4 | 7 + ldb/external/libpopt.m4 | 7 + ldb/external/libtalloc.m4 | 7 + ldb/external/libtdb.m4 | 7 + ldb/external/pkg.m4 | 156 + ldb/include/dlinklist.h | 110 + ldb/include/ldb.h | 1698 +++++++ ldb/include/ldb_errors.h | 310 ++ ldb/include/ldb_handlers.h | 67 + ldb/include/ldb_includes.h | 29 + ldb/include/ldb_private.h | 251 + ldb/install-sh | 238 + ldb/ldap.m4 | 90 + ldb/ldb.i | 931 ++++ ldb/ldb.mk | 86 + ldb/ldb.pc | 16 + ldb/ldb.pc.in | 16 + ldb/ldb.py | 477 ++ ldb/ldb_ildap/config.mk | 13 + ldb/ldb_ildap/ldb_ildap.c | 843 ++++ ldb/ldb_ldap/ldb_ldap.c | 842 ++++ ldb/ldb_map/ldb_map.c | 1380 ++++++ ldb/ldb_map/ldb_map.h | 173 + ldb/ldb_map/ldb_map_inbound.c | 723 +++ ldb/ldb_map/ldb_map_outbound.c | 1289 +++++ ldb/ldb_map/ldb_map_private.h | 110 + ldb/ldb_sqlite3/README | 7 + ldb/ldb_sqlite3/base160.c | 154 + ldb/ldb_sqlite3/ldb_sqlite3.c | 1876 +++++++ ldb/ldb_sqlite3/schema | 328 ++ ldb/ldb_sqlite3/trees.ps | 1760 +++++++ ldb/ldb_tdb/ldb_cache.c | 458 ++ ldb/ldb_tdb/ldb_index.c | 1273 +++++ ldb/ldb_tdb/ldb_pack.c | 289 ++ ldb/ldb_tdb/ldb_search.c | 616 +++ ldb/ldb_tdb/ldb_tdb.c | 1140 +++++ ldb/ldb_tdb/ldb_tdb.h | 130 + ldb/ldb_tdb/ldb_tdb_wrap.c | 153 + ldb/ldb_wrap.c | 6586 +++++++++++++++++++++++++ ldb/libldb.m4 | 7 + ldb/mainpage.dox | 80 + ldb/man/ad2oLschema.1.xml | 87 + ldb/man/ldb.3.xml | 262 + ldb/man/ldbadd.1.xml | 105 + ldb/man/ldbdel.1.xml | 105 + ldb/man/ldbedit.1.xml | 200 + ldb/man/ldbmodify.1.xml | 93 + ldb/man/ldbrename.1.xml | 107 + ldb/man/ldbsearch.1.xml | 119 + ldb/man/oLschema2ldif.1.xml | 79 + ldb/modules/asq.c | 481 ++ ldb/modules/operational.c | 305 ++ ldb/modules/paged_results.c | 557 +++ ldb/modules/paged_searches.c | 463 ++ ldb/modules/rdn_name.c | 335 ++ ldb/modules/skel.c | 131 + ldb/modules/sort.c | 458 ++ ldb/nssldb/README.txt | 34 + ldb/nssldb/ldb-grp.c | 425 ++ ldb/nssldb/ldb-nss.c | 395 ++ ldb/nssldb/ldb-nss.h | 84 + ldb/nssldb/ldb-pwd.c | 239 + ldb/python.mk | 10 + ldb/rules.mk | 30 + ldb/sqlite3.m4 | 62 + ldb/standalone.sh | 28 + ldb/tests/init.ldif | 40 + ldb/tests/init_slapd.sh | 41 + ldb/tests/kill_slapd.sh | 12 + ldb/tests/ldapi_url.sh | 11 + ldb/tests/photo.ldif | 5 + ldb/tests/python/api.py | 463 ++ ldb/tests/python/ldap.py | 1017 ++++ ldb/tests/samba4.png | Bin 0 -> 6239 bytes ldb/tests/sample_module.c | 38 + ldb/tests/schema-tests/schema-add-test.ldif | 66 + ldb/tests/schema-tests/schema-mod-test-1.ldif | 5 + ldb/tests/schema-tests/schema-mod-test-2.ldif | 5 + ldb/tests/schema-tests/schema-mod-test-3.ldif | 5 + ldb/tests/schema-tests/schema-mod-test-4.ldif | 5 + ldb/tests/schema-tests/schema-mod-test-5.ldif | 5 + ldb/tests/schema-tests/schema.ldif | 100 + ldb/tests/slapd.conf | 26 + ldb/tests/start_slapd.sh | 14 + ldb/tests/test-attribs.ldif | 6 + ldb/tests/test-config.ldif | 67 + ldb/tests/test-default-config.ldif | 17 + ldb/tests/test-extended.sh | 69 + ldb/tests/test-generic.sh | 128 + ldb/tests/test-index.ldif | 7 + ldb/tests/test-ldap.sh | 54 + ldb/tests/test-modify.ldif | 23 + ldb/tests/test-schema.sh | 34 + ldb/tests/test-soloading.sh | 32 + ldb/tests/test-sqlite3.sh | 25 + ldb/tests/test-tdb-features.sh | 160 + ldb/tests/test-tdb.sh | 31 + ldb/tests/test-wildcard.ldif | 5 + ldb/tests/test-wrong_attributes.ldif | 3 + ldb/tests/test.ldif | 411 ++ ldb/tests/testdata.txt | 8 + ldb/tests/testsearch.txt | 5 + ldb/tools/cmdline.c | 397 ++ ldb/tools/cmdline.h | 54 + ldb/tools/config.mk | 90 + ldb/tools/ldbadd.c | 116 + ldb/tools/ldbdel.c | 115 + ldb/tools/ldbedit.c | 329 ++ ldb/tools/ldbmodify.c | 116 + ldb/tools/ldbrename.c | 90 + ldb/tools/ldbsearch.c | 320 ++ ldb/tools/ldbtest.c | 418 ++ ldb/web/index.html | 86 + replace/.checker_innocent | 4 + replace/Makefile.in | 70 + replace/README | 113 + replace/aclocal.m4 | 1 + replace/autoconf-2.60.m4 | 210 + replace/autogen.sh | 13 + replace/build_macros.m4 | 14 + replace/config.guess | 1464 ++++++ replace/config.sub | 1577 ++++++ replace/configure.ac | 33 + replace/dlfcn.c | 75 + replace/dlfcn.m4 | 31 + replace/getaddrinfo.c | 497 ++ replace/getaddrinfo.h | 89 + replace/getifaddrs.c | 361 ++ replace/getpass.c | 225 + replace/getpass.ho | Bin 0 -> 14104 bytes replace/getpass.m4 | 24 + replace/inet_aton.c | 33 + replace/inet_ntoa.c | 39 + replace/inet_ntop.c | 191 + replace/inet_pton.c | 213 + replace/install-sh | 238 + replace/libreplace.m4 | 303 ++ replace/libreplace_cc.m4 | 172 + replace/libreplace_ld.m4 | 319 ++ replace/libreplace_macros.m4 | 332 ++ replace/libreplace_network.m4 | 377 ++ replace/repdir.m4 | 78 + replace/repdir_getdents.c | 166 + replace/repdir_getdirentries.c | 183 + replace/replace.c | 616 +++ replace/replace.h | 582 +++ replace/replace.ho | Bin 0 -> 5712 bytes replace/samba.m4 | 35 + replace/snprintf.c | 1530 ++++++ replace/snprintf.ho | Bin 0 -> 3800 bytes replace/socket.c | 35 + replace/socketpair.c | 46 + replace/strptime.c | 990 ++++ replace/strptime.m4 | 13 + replace/system/README | 4 + replace/system/aio.h | 32 + replace/system/capability.h | 55 + replace/system/config.m4 | 130 + replace/system/dir.h | 67 + replace/system/filesys.h | 182 + replace/system/glob.h | 37 + replace/system/iconv.h | 57 + replace/system/kerberos.h | 137 + replace/system/locale.h | 38 + replace/system/network.h | 332 ++ replace/system/passwd.h | 110 + replace/system/readline.h | 52 + replace/system/select.h | 41 + replace/system/shmem.h | 59 + replace/system/syslog.h | 70 + replace/system/terminal.h | 46 + replace/system/time.h | 69 + replace/system/wait.h | 55 + replace/test/getifaddrs.c | 100 + replace/test/os2_delete.c | 124 + replace/test/shared_mmap.c | 68 + replace/test/strptime.c | 172 + replace/test/testsuite.c | 1081 ++++ replace/timegm.c | 78 + replace/timegm.m4 | 1 + replace/win32.m4 | 20 + replace/win32_replace.h | 159 + talloc/Makefile.in | 53 + talloc/NEWS | 13 + talloc/aclocal.m4 | 1 + talloc/autogen.sh | 14 + talloc/build_macros.m4 | 14 + talloc/config.guess | 1464 ++++++ talloc/config.mk | 7 + talloc/config.sub | 1577 ++++++ talloc/configure.ac | 27 + talloc/install-sh | 238 + talloc/libtalloc.m4 | 33 + talloc/rules.mk | 18 + talloc/talloc.3.xml | 738 +++ talloc/talloc.c | 1724 +++++++ talloc/talloc.h | 183 + talloc/talloc.i | 31 + talloc/talloc.mk | 37 + talloc/talloc.pc.in | 11 + talloc/talloc_guide.txt | 685 +++ talloc/testsuite.c | 1152 +++++ talloc/web/index.html | 46 + tdb/Makefile.in | 70 + tdb/aclocal.m4 | 1 + tdb/autogen.sh | 16 + tdb/build_macros.m4 | 14 + tdb/common/dump.c | 137 + tdb/common/error.c | 57 + tdb/common/freelist.c | 382 ++ tdb/common/freelistcheck.c | 107 + tdb/common/io.c | 471 ++ tdb/common/lock.c | 553 +++ tdb/common/open.c | 488 ++ tdb/common/tdb.c | 802 +++ tdb/common/tdb_private.h | 213 + tdb/common/transaction.c | 1119 +++++ tdb/common/traverse.c | 348 ++ tdb/config.guess | 1464 ++++++ tdb/config.mk | 57 + tdb/config.sub | 1577 ++++++ tdb/configure.ac | 34 + tdb/docs/README | 238 + tdb/docs/tdb.magic | 10 + tdb/include/tdb.h | 168 + tdb/install-sh | 238 + tdb/libtdb.m4 | 30 + tdb/python.mk | 10 + tdb/python/tdbdump.py | 12 + tdb/python/tests/simple.py | 152 + tdb/rules.mk | 21 + tdb/tdb.i | 323 ++ tdb/tdb.mk | 86 + tdb/tdb.pc.in | 11 + tdb/tdb.py | 341 ++ tdb/tdb_wrap.c | 4307 ++++++++++++++++ tdb/tools/tdbbackup.c | 300 ++ tdb/tools/tdbdump.c | 116 + tdb/tools/tdbtest.c | 265 + tdb/tools/tdbtool.c | 659 +++ tdb/tools/tdbtorture.c | 318 ++ tdb/web/index.html | 42 + 304 files changed, 96337 insertions(+) create mode 100644 events/Makefile.in create mode 100755 events/autogen.sh create mode 100644 events/build_macros.m4 create mode 100755 events/config.guess create mode 100644 events/config.mk create mode 100755 events/config.sub create mode 100644 events/configure.ac create mode 100644 events/events.c create mode 100644 events/events.h create mode 100644 events/events.i create mode 100644 events/events.mk create mode 100644 events/events.pc.in create mode 100644 events/events.py create mode 100644 events/events_aio.c create mode 100644 events/events_debug.c create mode 100644 events/events_epoll.c create mode 100644 events/events_internal.h create mode 100644 events/events_liboop.c create mode 100644 events/events_s4.c create mode 100644 events/events_select.c create mode 100644 events/events_signal.c create mode 100644 events/events_standard.c create mode 100644 events/events_timed.c create mode 100644 events/events_util.c create mode 100644 events/events_util.h create mode 100644 events/events_wrap.c create mode 100755 events/install-sh create mode 100644 events/libevents.m4 create mode 100644 events/libtalloc.m4 create mode 100644 events/pkg.m4 create mode 100644 events/rules.mk create mode 100644 events/tests.py create mode 100644 events/testsuite.c create mode 100644 ldb/Doxyfile create mode 100644 ldb/Makefile.in create mode 100644 ldb/README_gcov.txt create mode 100644 ldb/aclocal.m4 create mode 100755 ldb/autogen.sh create mode 100644 ldb/build_macros.m4 create mode 100644 ldb/common/attrib_handlers.c create mode 100644 ldb/common/ldb.c create mode 100644 ldb/common/ldb_attributes.c create mode 100644 ldb/common/ldb_controls.c create mode 100644 ldb/common/ldb_debug.c create mode 100644 ldb/common/ldb_dn.c create mode 100644 ldb/common/ldb_ldif.c create mode 100644 ldb/common/ldb_match.c create mode 100644 ldb/common/ldb_modules.c create mode 100644 ldb/common/ldb_msg.c create mode 100644 ldb/common/ldb_parse.c create mode 100644 ldb/common/ldb_utf8.c create mode 100644 ldb/common/qsort.c create mode 100755 ldb/config.guess create mode 100644 ldb/config.mk create mode 100755 ldb/config.sub create mode 100644 ldb/configure.ac create mode 100755 ldb/docs/builddocs.sh create mode 100644 ldb/docs/design.txt create mode 100755 ldb/docs/installdocs.sh create mode 100644 ldb/examples.dox create mode 100644 ldb/examples/ldbreader.c create mode 100644 ldb/examples/ldifreader.c create mode 100644 ldb/external/libevents.m4 create mode 100644 ldb/external/libpopt.m4 create mode 100644 ldb/external/libtalloc.m4 create mode 100644 ldb/external/libtdb.m4 create mode 100644 ldb/external/pkg.m4 create mode 100644 ldb/include/dlinklist.h create mode 100644 ldb/include/ldb.h create mode 100644 ldb/include/ldb_errors.h create mode 100644 ldb/include/ldb_handlers.h create mode 100644 ldb/include/ldb_includes.h create mode 100644 ldb/include/ldb_private.h create mode 100755 ldb/install-sh create mode 100644 ldb/ldap.m4 create mode 100644 ldb/ldb.i create mode 100644 ldb/ldb.mk create mode 100644 ldb/ldb.pc create mode 100644 ldb/ldb.pc.in create mode 100644 ldb/ldb.py create mode 100644 ldb/ldb_ildap/config.mk create mode 100644 ldb/ldb_ildap/ldb_ildap.c create mode 100644 ldb/ldb_ldap/ldb_ldap.c create mode 100644 ldb/ldb_map/ldb_map.c create mode 100644 ldb/ldb_map/ldb_map.h create mode 100644 ldb/ldb_map/ldb_map_inbound.c create mode 100644 ldb/ldb_map/ldb_map_outbound.c create mode 100644 ldb/ldb_map/ldb_map_private.h create mode 100644 ldb/ldb_sqlite3/README create mode 100644 ldb/ldb_sqlite3/base160.c create mode 100644 ldb/ldb_sqlite3/ldb_sqlite3.c create mode 100644 ldb/ldb_sqlite3/schema create mode 100644 ldb/ldb_sqlite3/trees.ps create mode 100644 ldb/ldb_tdb/ldb_cache.c create mode 100644 ldb/ldb_tdb/ldb_index.c create mode 100644 ldb/ldb_tdb/ldb_pack.c create mode 100644 ldb/ldb_tdb/ldb_search.c create mode 100644 ldb/ldb_tdb/ldb_tdb.c create mode 100644 ldb/ldb_tdb/ldb_tdb.h create mode 100644 ldb/ldb_tdb/ldb_tdb_wrap.c create mode 100644 ldb/ldb_wrap.c create mode 100644 ldb/libldb.m4 create mode 100644 ldb/mainpage.dox create mode 100644 ldb/man/ad2oLschema.1.xml create mode 100644 ldb/man/ldb.3.xml create mode 100644 ldb/man/ldbadd.1.xml create mode 100644 ldb/man/ldbdel.1.xml create mode 100644 ldb/man/ldbedit.1.xml create mode 100644 ldb/man/ldbmodify.1.xml create mode 100644 ldb/man/ldbrename.1.xml create mode 100644 ldb/man/ldbsearch.1.xml create mode 100644 ldb/man/oLschema2ldif.1.xml create mode 100644 ldb/modules/asq.c create mode 100644 ldb/modules/operational.c create mode 100644 ldb/modules/paged_results.c create mode 100644 ldb/modules/paged_searches.c create mode 100644 ldb/modules/rdn_name.c create mode 100644 ldb/modules/skel.c create mode 100644 ldb/modules/sort.c create mode 100644 ldb/nssldb/README.txt create mode 100644 ldb/nssldb/ldb-grp.c create mode 100644 ldb/nssldb/ldb-nss.c create mode 100644 ldb/nssldb/ldb-nss.h create mode 100644 ldb/nssldb/ldb-pwd.c create mode 100644 ldb/python.mk create mode 100644 ldb/rules.mk create mode 100644 ldb/sqlite3.m4 create mode 100755 ldb/standalone.sh create mode 100644 ldb/tests/init.ldif create mode 100755 ldb/tests/init_slapd.sh create mode 100755 ldb/tests/kill_slapd.sh create mode 100755 ldb/tests/ldapi_url.sh create mode 100644 ldb/tests/photo.ldif create mode 100755 ldb/tests/python/api.py create mode 100755 ldb/tests/python/ldap.py create mode 100644 ldb/tests/samba4.png create mode 100644 ldb/tests/sample_module.c create mode 100644 ldb/tests/schema-tests/schema-add-test.ldif create mode 100644 ldb/tests/schema-tests/schema-mod-test-1.ldif create mode 100644 ldb/tests/schema-tests/schema-mod-test-2.ldif create mode 100644 ldb/tests/schema-tests/schema-mod-test-3.ldif create mode 100644 ldb/tests/schema-tests/schema-mod-test-4.ldif create mode 100644 ldb/tests/schema-tests/schema-mod-test-5.ldif create mode 100644 ldb/tests/schema-tests/schema.ldif create mode 100644 ldb/tests/slapd.conf create mode 100755 ldb/tests/start_slapd.sh create mode 100644 ldb/tests/test-attribs.ldif create mode 100644 ldb/tests/test-config.ldif create mode 100644 ldb/tests/test-default-config.ldif create mode 100755 ldb/tests/test-extended.sh create mode 100755 ldb/tests/test-generic.sh create mode 100644 ldb/tests/test-index.ldif create mode 100755 ldb/tests/test-ldap.sh create mode 100644 ldb/tests/test-modify.ldif create mode 100755 ldb/tests/test-schema.sh create mode 100755 ldb/tests/test-soloading.sh create mode 100755 ldb/tests/test-sqlite3.sh create mode 100644 ldb/tests/test-tdb-features.sh create mode 100755 ldb/tests/test-tdb.sh create mode 100644 ldb/tests/test-wildcard.ldif create mode 100644 ldb/tests/test-wrong_attributes.ldif create mode 100644 ldb/tests/test.ldif create mode 100644 ldb/tests/testdata.txt create mode 100644 ldb/tests/testsearch.txt create mode 100644 ldb/tools/cmdline.c create mode 100644 ldb/tools/cmdline.h create mode 100644 ldb/tools/config.mk create mode 100644 ldb/tools/ldbadd.c create mode 100644 ldb/tools/ldbdel.c create mode 100644 ldb/tools/ldbedit.c create mode 100644 ldb/tools/ldbmodify.c create mode 100644 ldb/tools/ldbrename.c create mode 100644 ldb/tools/ldbsearch.c create mode 100644 ldb/tools/ldbtest.c create mode 100644 ldb/web/index.html create mode 100644 replace/.checker_innocent create mode 100644 replace/Makefile.in create mode 100644 replace/README create mode 100644 replace/aclocal.m4 create mode 100644 replace/autoconf-2.60.m4 create mode 100755 replace/autogen.sh create mode 100644 replace/build_macros.m4 create mode 100755 replace/config.guess create mode 100755 replace/config.sub create mode 100644 replace/configure.ac create mode 100644 replace/dlfcn.c create mode 100644 replace/dlfcn.m4 create mode 100644 replace/getaddrinfo.c create mode 100644 replace/getaddrinfo.h create mode 100644 replace/getifaddrs.c create mode 100644 replace/getpass.c create mode 100644 replace/getpass.ho create mode 100644 replace/getpass.m4 create mode 100644 replace/inet_aton.c create mode 100644 replace/inet_ntoa.c create mode 100644 replace/inet_ntop.c create mode 100644 replace/inet_pton.c create mode 100755 replace/install-sh create mode 100644 replace/libreplace.m4 create mode 100644 replace/libreplace_cc.m4 create mode 100644 replace/libreplace_ld.m4 create mode 100644 replace/libreplace_macros.m4 create mode 100644 replace/libreplace_network.m4 create mode 100644 replace/repdir.m4 create mode 100644 replace/repdir_getdents.c create mode 100644 replace/repdir_getdirentries.c create mode 100644 replace/replace.c create mode 100644 replace/replace.h create mode 100644 replace/replace.ho create mode 100644 replace/samba.m4 create mode 100644 replace/snprintf.c create mode 100644 replace/snprintf.ho create mode 100644 replace/socket.c create mode 100644 replace/socketpair.c create mode 100644 replace/strptime.c create mode 100644 replace/strptime.m4 create mode 100644 replace/system/README create mode 100644 replace/system/aio.h create mode 100644 replace/system/capability.h create mode 100644 replace/system/config.m4 create mode 100644 replace/system/dir.h create mode 100644 replace/system/filesys.h create mode 100644 replace/system/glob.h create mode 100644 replace/system/iconv.h create mode 100644 replace/system/kerberos.h create mode 100644 replace/system/locale.h create mode 100644 replace/system/network.h create mode 100644 replace/system/passwd.h create mode 100644 replace/system/readline.h create mode 100644 replace/system/select.h create mode 100644 replace/system/shmem.h create mode 100644 replace/system/syslog.h create mode 100644 replace/system/terminal.h create mode 100644 replace/system/time.h create mode 100644 replace/system/wait.h create mode 100644 replace/test/getifaddrs.c create mode 100644 replace/test/os2_delete.c create mode 100644 replace/test/shared_mmap.c create mode 100644 replace/test/strptime.c create mode 100644 replace/test/testsuite.c create mode 100644 replace/timegm.c create mode 100644 replace/timegm.m4 create mode 100644 replace/win32.m4 create mode 100644 replace/win32_replace.h create mode 100644 talloc/Makefile.in create mode 100644 talloc/NEWS create mode 100644 talloc/aclocal.m4 create mode 100755 talloc/autogen.sh create mode 100644 talloc/build_macros.m4 create mode 100755 talloc/config.guess create mode 100644 talloc/config.mk create mode 100755 talloc/config.sub create mode 100644 talloc/configure.ac create mode 100755 talloc/install-sh create mode 100644 talloc/libtalloc.m4 create mode 100644 talloc/rules.mk create mode 100644 talloc/talloc.3.xml create mode 100644 talloc/talloc.c create mode 100644 talloc/talloc.h create mode 100644 talloc/talloc.i create mode 100644 talloc/talloc.mk create mode 100644 talloc/talloc.pc.in create mode 100644 talloc/talloc_guide.txt create mode 100644 talloc/testsuite.c create mode 100644 talloc/web/index.html create mode 100644 tdb/Makefile.in create mode 100644 tdb/aclocal.m4 create mode 100755 tdb/autogen.sh create mode 100644 tdb/build_macros.m4 create mode 100644 tdb/common/dump.c create mode 100644 tdb/common/error.c create mode 100644 tdb/common/freelist.c create mode 100644 tdb/common/freelistcheck.c create mode 100644 tdb/common/io.c create mode 100644 tdb/common/lock.c create mode 100644 tdb/common/open.c create mode 100644 tdb/common/tdb.c create mode 100644 tdb/common/tdb_private.h create mode 100644 tdb/common/transaction.c create mode 100644 tdb/common/traverse.c create mode 100755 tdb/config.guess create mode 100644 tdb/config.mk create mode 100755 tdb/config.sub create mode 100644 tdb/configure.ac create mode 100644 tdb/docs/README create mode 100644 tdb/docs/tdb.magic create mode 100644 tdb/include/tdb.h create mode 100755 tdb/install-sh create mode 100644 tdb/libtdb.m4 create mode 100644 tdb/python.mk create mode 100644 tdb/python/tdbdump.py create mode 100644 tdb/python/tests/simple.py create mode 100644 tdb/rules.mk create mode 100644 tdb/tdb.i create mode 100644 tdb/tdb.mk create mode 100644 tdb/tdb.pc.in create mode 100644 tdb/tdb.py create mode 100644 tdb/tdb_wrap.c create mode 100644 tdb/tools/tdbbackup.c create mode 100644 tdb/tools/tdbdump.c create mode 100644 tdb/tools/tdbtest.c create mode 100644 tdb/tools/tdbtool.c create mode 100644 tdb/tools/tdbtorture.c create mode 100644 tdb/web/index.html diff --git a/events/Makefile.in b/events/Makefile.in new file mode 100644 index 000000000..5548e46e0 --- /dev/null +++ b/events/Makefile.in @@ -0,0 +1,77 @@ +#!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@ +buildinstdir = @buildinstdir@ +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@ +SWIG = swig +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@ +eventsdir = @eventsdir@ + +TALLOC_CFLAGS = @TALLOC_CFLAGS@ +TALLOC_LDFLAGS = @TALLOC_CFLAGS@ +TALLOC_LIBS = @TALLOC_LIBS@ + +CFLAGS = $(CPPFLAGS) $(TALLOC_CFLAGS) @CFLAGS@ +LDFLAGS = $(TALLOC_LDFLAGS) @LDFLAGS@ +LIBS = $(TALLOC_LIBS) @LIBS@ + +EVENTS_OBJ = @EVENTS_OBJ@ @LIBREPLACEOBJ@ + +default: all + +include $(eventsdir)/events.mk +include $(eventsdir)/rules.mk + +all:: showflags dirs $(PROGS) $(EVENTS_SOLIB) libevents.a $(PYTHON_BUILD_TARGET) + +install:: all +$(EVENTS_SOLIB): $(EVENTS_OBJ) + $(SHLD) $(SHLD_FLAGS) $(LDFLAGS) $(LIBS) -o $@ $(EVENTS_OBJ) @SONAMEFLAG@$(EVENTS_SONAME) + +build-install: all + ${INSTALLCMD} -d $(buildinstdir)/lib + ${INSTALLCMD} -m 755 libevents.a $(buildinstdir)/lib + ${INSTALLCMD} -m 755 $(EVENTS_SOLIB) $(buildinstdir)/lib + ln -sf $(EVENTS_SOLIB) $(buildinstdir)/lib/$(EVENTS_SONAME) + ln -sf $(EVENTS_SOLIB) $(buildinstdir)/lib/libevents.so + ${INSTALLCMD} -d $(buildinstdir)/include + ${INSTALLCMD} -m 644 $(srcdir)/events.h $(buildinstdir)/include + +check: test + +test:: $(PYTHON_CHECK_TARGET) +installcheck:: test install + +clean:: + rm -f *.o *.a */*.o + +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 diff --git a/events/autogen.sh b/events/autogen.sh new file mode 100755 index 000000000..a3bb9bdd0 --- /dev/null +++ b/events/autogen.sh @@ -0,0 +1,16 @@ +#!/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 + +swig -O -Wall -python -keyword events.i # Ignore errors for now + +echo "Now run ./configure and then make." +exit 0 + diff --git a/events/build_macros.m4 b/events/build_macros.m4 new file mode 100644 index 000000000..bb05a5822 --- /dev/null +++ b/events/build_macros.m4 @@ -0,0 +1,14 @@ +AC_DEFUN(BUILD_WITH_BUILD_INST_DIR, + [ AC_ARG_WITH([build-install-dir], + [AC_HELP_STRING([--with-build-install-dir=DIR], + [temporary build directory where libraries are installed [$srcdir/buildinst]])]) + + buildinstdir="$srcdir/buildinst" + if test x"$with_build_install_dir" != x; then + buildinstdir=$with_build_install_dir + CFLAGS="$CFLAGS -I$with_build_install_dir/include" + CPPFLAGS="$CPPFLAGS -I$with_build_install_dir/include" + LIBS="$LIBS -L$with_build_install_dir/lib" + fi + AC_SUBST(buildinstdir) + ]) diff --git a/events/config.guess b/events/config.guess new file mode 100755 index 000000000..354dbe175 --- /dev/null +++ b/events/config.guess @@ -0,0 +1,1464 @@ +#! /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 Free Software Foundation, Inc. + +timestamp='2005-08-03' + +# 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 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 . +# +# 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 . +# Please send patches to . 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 ." + +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 +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 -q "$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@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 ;; + *) 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 ;; + macppc:MirBSD:*:*) + echo powerppc-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@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 ;; + 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.*:*) + echo i386-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 /* 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 + + 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:*:[45]) + 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 + #include + + 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 + 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:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*: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 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [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:*:*) + 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 | grep ^CPU=` + 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 | grep ^CPU=` + 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 ;; + 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 ;; + x86_64:Linux:*:*) + echo x86_64-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 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + 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 + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + 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' /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 i386. + echo i386-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; } ;; + 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 + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@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 ;; + 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 ;; + 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 + *86) UNAME_PROCESSOR=i686 ;; + 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 ;; +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 < +# include +#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 + 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 +# 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 < 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: diff --git a/events/config.mk b/events/config.mk new file mode 100644 index 000000000..127d96477 --- /dev/null +++ b/events/config.mk @@ -0,0 +1,58 @@ +############################## +[MODULE::EVENTS_AIO] +PRIVATE_DEPENDENCIES = LIBAIO_LINUX +SUBSYSTEM = LIBEVENTS +INIT_FUNCTION = s4_events_aio_init +############################## + +EVENTS_AIO_OBJ_FILES = $(libeventssrcdir)/events_aio.o + +############################## +[MODULE::EVENTS_EPOLL] +SUBSYSTEM = LIBEVENTS +INIT_FUNCTION = s4_events_epoll_init +############################## + +EVENTS_EPOLL_OBJ_FILES = $(libeventssrcdir)/events_epoll.o + +############################## +[MODULE::EVENTS_SELECT] +SUBSYSTEM = LIBEVENTS +INIT_FUNCTION = s4_events_select_init +############################## + +EVENTS_SELECT_OBJ_FILES = $(libeventssrcdir)/events_select.o + +############################## +[MODULE::EVENTS_STANDARD] +SUBSYSTEM = LIBEVENTS +INIT_FUNCTION = s4_events_standard_init +############################## + +EVENTS_STANDARD_OBJ_FILES = $(libeventssrcdir)/events_standard.o + +################################################ +# Start SUBSYSTEM LIBEVENTS +[LIBRARY::LIBEVENTS] +PUBLIC_DEPENDENCIES = LIBTALLOC +OUTPUT_TYPE = MERGED_OBJ +CFLAGS = -Ilib/events +# +# End SUBSYSTEM LIBEVENTS +################################################ + +LIBEVENTS_OBJ_FILES = $(addprefix $(libeventssrcdir)/, events.o events_timed.o events_signal.o events_debug.o events_util.o events_s4.o) + +PUBLIC_HEADERS += $(addprefix $(libeventssrcdir)/, events.h events_internal.h) + +[PYTHON::swig_events] +LIBRARY_REALNAME = samba/_events.$(SHLIBEXT) +PRIVATE_DEPENDENCIES = LIBEVENTS LIBSAMBA-HOSTCONFIG LIBSAMBA-UTIL + +swig_events_OBJ_FILES = $(libeventssrcdir)/events_wrap.o + +$(eval $(call python_py_module_template,samba/events.py,$(libeventssrcdir)/events.py)) + +$(swig_events_OBJ_FILES): CFLAGS+=$(CFLAG_NO_UNUSED_MACROS) $(CFLAG_NO_CAST_QUAL) + +PC_FILES += $(libeventssrcdir)/events.pc diff --git a/events/config.sub b/events/config.sub new file mode 100755 index 000000000..23cd6fd75 --- /dev/null +++ b/events/config.sub @@ -0,0 +1,1577 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-08' + +# 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 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 . +# +# 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 . 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 ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +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-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-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 + ;; + -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/'` + ;; + -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 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + 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) + ;; + + # 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-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | 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[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # 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 + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + 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 + ;; + cr16c) + basic_machine=cr16c-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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + 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 + ;; + 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 + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + 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 + ;; + 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 + ;; + 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[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + 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* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -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* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -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*) + # 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 + ;; + -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 + *-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 + ;; + 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: diff --git a/events/configure.ac b/events/configure.ac new file mode 100644 index 000000000..0ee3bf869 --- /dev/null +++ b/events/configure.ac @@ -0,0 +1,40 @@ +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_DEFUN([SMB_EXT_LIB], [echo -n ""]) +AC_INIT(events, 1.0.0) +AC_CONFIG_SRCDIR([events.c]) +AC_CONFIG_HEADER(config.h) +AC_LIBREPLACE_ALL_CHECKS + +AC_LD_EXPORT_DYNAMIC +AC_LD_SONAMEFLAG +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_BUILD_INST_DIR + +m4_include(pkg.m4) +m4_include(libtalloc.m4) + +m4_include(libevents.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_OUTPUT(Makefile events.pc) diff --git a/events/events.c b/events/events.c new file mode 100644 index 000000000..52699d968 --- /dev/null +++ b/events/events.c @@ -0,0 +1,310 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + Copyright (C) Andrew Tridgell 2003 + + 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 . +*/ + +/* + 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 event_context_init(); This returns a + 'struct event_context' that you use in all subsequent calls. + + After that you can add/remove events that you are interested in + using event_add_*() and talloc_free() + + Finally, you call event_loop_wait_once() to block waiting for one of the + events to occor or event_loop_wait() which will loop + forever. + +*/ +#include "replace.h" +#include "events.h" +#include "events_internal.h" +#include "events_util.h" + +struct event_ops_list { + struct event_ops_list *next, *prev; + const char *name; + const struct event_ops *ops; +}; + +/* list of registered event backends */ +static struct event_ops_list *event_backends = NULL; +static char *event_default_backend = NULL; + +/* + register an events backend +*/ +bool event_register_backend(const char *name, const struct event_ops *ops) +{ + struct event_ops_list *e; + + for (e = event_backends; e != NULL; e = e->next) { + if (0 == strcmp(e->name, name)) { + /* already registered, skip it */ + return true; + } + } + + e = talloc(talloc_autofree_context(), struct event_ops_list); + if (e == NULL) return false; + + e->name = name; + e->ops = ops; + DLIST_ADD(event_backends, e); + + return true; +} + +/* + set the default event backend + */ +void event_set_default_backend(const char *backend) +{ + if (event_default_backend) free(event_default_backend); + event_default_backend = strdup(backend); +} + +/* + initialise backends if not already done +*/ +static void event_backend_init(void) +{ + events_select_init(); + events_standard_init(); +#if HAVE_EVENTS_EPOLL + events_epoll_init(); +#endif +#if HAVE_LINUX_AIO + events_aio_init(); +#endif +} + +/* + list available backends +*/ +const char **event_backend_list(TALLOC_CTX *mem_ctx) +{ + const char **list = NULL; + struct event_ops_list *e; + + event_backend_init(); + + for (e=event_backends;e;e=e->next) { + list = ev_str_list_add(list, e->name); + } + + talloc_steal(mem_ctx, list); + + return list; +} + +/* + 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 event_context_init() inside of samba! +*/ +static struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, + const struct event_ops *ops) +{ + struct event_context *ev; + int ret; + + ev = talloc_zero(mem_ctx, struct event_context); + if (!ev) return NULL; + + 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 event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name) +{ + struct event_ops_list *e; + + event_backend_init(); + + if (name == NULL) { + name = event_default_backend; + } + if (name == NULL) { + name = "standard"; + } + + for (e=event_backends;e;e=e->next) { + if (strcmp(name, e->name) == 0) { + return event_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 event_context *event_context_init(TALLOC_CTX *mem_ctx) +{ + return event_context_init_byname(mem_ctx, NULL); +} + +/* + add a fd based event + return NULL on failure (memory allocation error) + + if flags contains EVENT_FD_AUTOCLOSE then the fd will be closed when + the returned fd_event context is freed +*/ +struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, event_fd_handler_t handler, + void *private_data) +{ + return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data); +} + +/* + add a disk aio event +*/ +struct aio_event *event_add_aio(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct iocb *iocb, + event_aio_handler_t handler, + void *private_data) +{ + if (ev->ops->add_aio == NULL) return NULL; + return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data); +} + +/* + return the fd event flags +*/ +uint16_t event_get_fd_flags(struct fd_event *fde) +{ + if (!fde) return 0; + return fde->event_ctx->ops->get_fd_flags(fde); +} + +/* + set the fd event flags +*/ +void event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + if (!fde) return; + fde->event_ctx->ops->set_fd_flags(fde, flags); +} + +/* + add a timed event + return NULL on failure +*/ +struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data) +{ + return ev->ops->add_timed(ev, mem_ctx, next_event, handler, private_data); +} + +/* + add a signal event + + sa_flags are flags to sigaction(2) + + return NULL on failure +*/ +struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx, + int signum, + int sa_flags, + event_signal_handler_t handler, + void *private_data) +{ + return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data); +} + +/* + do a single event loop using the events defined in ev +*/ +int event_loop_once(struct event_context *ev) +{ + return ev->ops->loop_once(ev); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +int event_loop_wait(struct event_context *ev) +{ + return ev->ops->loop_wait(ev); +} + +/* + find an event context that is a parent of the given memory context, + or create a new event context as a child of the given context if + none is found + + This should be used in preference to event_context_init() in places + where you would prefer to use the existing event context if possible + (which is most situations) +*/ +struct event_context *event_context_find(TALLOC_CTX *mem_ctx) +{ + struct event_context *ev = talloc_find_parent_bytype(mem_ctx, struct event_context); + if (ev == NULL) { + ev = event_context_init(mem_ctx); + } + return ev; +} diff --git a/events/events.h b/events/events.h new file mode 100644 index 000000000..1ece49697 --- /dev/null +++ b/events/events.h @@ -0,0 +1,98 @@ +/* + Unix SMB/CIFS implementation. + + generalised event loop handling + + 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 . +*/ + +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +#include +#include + +struct event_context; +struct event_ops; +struct fd_event; +struct timed_event; +struct aio_event; +struct signal_event; + +/* event handler types */ +typedef void (*event_fd_handler_t)(struct event_context *, struct fd_event *, + uint16_t , void *); +typedef void (*event_timed_handler_t)(struct event_context *, struct timed_event *, + struct timeval , void *); +typedef void (*event_signal_handler_t)(struct event_context *, struct signal_event *, + int , int, void *, void *); +typedef void (*event_aio_handler_t)(struct event_context *, struct aio_event *, + int, void *); + +#ifdef _SAMBA_BUILD_ +struct event_context *s4_event_context_init(TALLOC_CTX *mem_ctx); +#endif + +struct event_context *event_context_init(TALLOC_CTX *mem_ctx); +struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name); +const char **event_backend_list(TALLOC_CTX *mem_ctx); +void event_set_default_backend(const char *backend); + +struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, event_fd_handler_t handler, + void *private_data); + +struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data); + +struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx, + int signum, int sa_flags, + event_signal_handler_t handler, + void *private_data); + +struct iocb; +struct aio_event *event_add_aio(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct iocb *iocb, + event_aio_handler_t handler, + void *private_data); + +int event_loop_once(struct event_context *ev); +int event_loop_wait(struct event_context *ev); + +uint16_t event_get_fd_flags(struct fd_event *fde); +void event_set_fd_flags(struct fd_event *fde, uint16_t flags); + +struct event_context *event_context_find(TALLOC_CTX *mem_ctx); + +/* bits for file descriptor event flags */ +#define EVENT_FD_READ 1 +#define EVENT_FD_WRITE 2 +#define EVENT_FD_AUTOCLOSE 4 + +#define EVENT_FD_WRITEABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE) +#define EVENT_FD_READABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_READ) + +#define EVENT_FD_NOT_WRITEABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE) +#define EVENT_FD_NOT_READABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_READ) + +#endif /* __EVENTS_H__ */ diff --git a/events/events.i b/events/events.i new file mode 100644 index 000000000..5f790aeac --- /dev/null +++ b/events/events.i @@ -0,0 +1,54 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Jelmer Vernooij 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 . +*/ + +%module(docstring="Event management.",package="samba.events") events; + +%import "../talloc/talloc.i"; + +%{ +#include "events.h" +typedef struct event_context event; +%} + +typedef struct event_context { + %extend { + %feature("docstring") event "S.__init__()"; + event(TALLOC_CTX *mem_ctx) { return event_context_init(mem_ctx); } + %feature("docstring") loop_once "S.loop_once() -> int"; + int loop_once(void); + %feature("docstring") loop_wait "S.loop_wait() -> int"; + int loop_wait(void); + } +} event; +%talloctype(event); + +%typemap(default,noblock=1) struct event_context * { + $1 = event_context_init(NULL); +} + +%typemap(default,noblock=1) struct event_context * { + $1 = event_context_init(NULL); +} + +struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name); + +%feature("docstring") event_backend_list "event_backend_list() -> list"; +const char **event_backend_list(TALLOC_CTX *mem_ctx); +%feature("docstring") event_set_default_backend "event_set_default_backend(name) -> None"; +%rename(set_default_backend) event_set_default_backend; +void event_set_default_backend(const char *backend); diff --git a/events/events.mk b/events/events.mk new file mode 100644 index 000000000..2bc622168 --- /dev/null +++ b/events/events.mk @@ -0,0 +1,59 @@ + +EVENTS_SONAME = libevents.$(SHLIBEXT).0 +EVENTS_SOLIB = libevents.$(SHLIBEXT).$(PACKAGE_VERSION) + +libevents.a: $(EVENTS_OBJ) + ar -rv libevents.a $(EVENTS_OBJ) + +libevents.$(SHLIBEXT): $(EVENTS_SOLIB) + ln -fs $< $@ + +$(EVENTS_SONAME): $(EVENTS_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)/events.h $(DESTDIR)$(includedir) + +installlibs:: installdirs + cp events.pc $(DESTDIR)$(libdir)/pkgconfig + cp libevents.a $(EVENTS_SOLIB) $(DESTDIR)$(libdir) + +install:: all installdirs installheaders installlibs $(PYTHON_INSTALL_TARGET) + +clean:: + rm -f $(EVENTS_SONAME) $(EVENTS_SOLIB) libevents.a libevents.$(SHLIBEXT) + rm -f events.pc + rm -f _libevents.$(SHLIBEXT) + + +#python stuff + +check-python:: build-python + $(LIB_PATH_VAR)=. PYTHONPATH=".:$(eventsdir)" $(PYTHON) $(eventsdir)/python/tests/simple.py + +install-swig:: + mkdir -p $(DESTDIR)`$(SWIG) -swiglib` + cp events.i $(DESTDIR)`$(SWIG) -swiglib` + +build-python:: _libevents.$(SHLIBEXT) + +events_wrap.o: $(eventsdir)/events_wrap.c + $(CC) $(PICFLAG) -c $(eventsdir)/events_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` + +_libevents.$(SHLIBEXT): libevents.$(SHLIBEXT) events_wrap.o + $(SHLD) $(SHLD_FLAGS) -o $@ events_wrap.o -L. -levents `$(PYTHON_CONFIG) --libs` + +install-python:: build-python + mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \ + $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` + cp $(eventsdir)/events.py $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` + cp _libevents.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` + diff --git a/events/events.pc.in b/events/events.pc.in new file mode 100644 index 000000000..4a4c012d7 --- /dev/null +++ b/events/events.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: events +Description: An event system library +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -levents +Cflags: -I${includedir} +URL: http://samba.org/ diff --git a/events/events.py b/events/events.py new file mode 100644 index 000000000..f217c29d7 --- /dev/null +++ b/events/events.py @@ -0,0 +1,94 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 1.3.33 +# +# Don't modify this file, modify the SWIG interface instead. + +""" +Event management. +""" + +import _events +import new +new_instancemethod = new.instancemethod +try: + _swig_property = property +except NameError: + pass # Python < 2.2 doesn't have 'property'. +def _swig_setattr_nondynamic(self,class_type,name,value,static=1): + if (name == "thisown"): return self.this.own(value) + if (name == "this"): + if type(value).__name__ == 'PySwigObject': + self.__dict__[name] = value + return + method = class_type.__swig_setmethods__.get(name,None) + if method: return method(self,value) + if (not static) or hasattr(self,name): + self.__dict__[name] = value + else: + raise AttributeError("You cannot add attributes to %s" % self) + +def _swig_setattr(self,class_type,name,value): + return _swig_setattr_nondynamic(self,class_type,name,value,0) + +def _swig_getattr(self,class_type,name): + if (name == "thisown"): return self.this.own() + method = class_type.__swig_getmethods__.get(name,None) + if method: return method(self) + raise AttributeError,name + +def _swig_repr(self): + try: strthis = "proxy of " + self.this.__repr__() + except: strthis = "" + return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) + +import types +try: + _object = types.ObjectType + _newclass = 1 +except AttributeError: + class _object : pass + _newclass = 0 +del types + + +def _swig_setattr_nondynamic_method(set): + def set_attr(self,name,value): + if (name == "thisown"): return self.this.own(value) + if hasattr(self,name) or (name == "this"): + set(self,name,value) + else: + raise AttributeError("You cannot add attributes to %s" % self) + return set_attr + + +class event(object): + thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') + __repr__ = _swig_repr + def __init__(self, *args, **kwargs): + """S.__init__()""" + _events.event_swiginit(self,_events.new_event(*args, **kwargs)) + def loop_once(*args, **kwargs): + """S.loop_once() -> int""" + return _events.event_loop_once(*args, **kwargs) + + def loop_wait(*args, **kwargs): + """S.loop_wait() -> int""" + return _events.event_loop_wait(*args, **kwargs) + + __swig_destroy__ = _events.delete_event +event.loop_once = new_instancemethod(_events.event_loop_once,None,event) +event.loop_wait = new_instancemethod(_events.event_loop_wait,None,event) +event_swigregister = _events.event_swigregister +event_swigregister(event) + +event_context_init_byname = _events.event_context_init_byname + +def event_backend_list(*args): + """event_backend_list() -> list""" + return _events.event_backend_list(*args) + +def set_default_backend(*args, **kwargs): + """event_set_default_backend(name) -> None""" + return _events.set_default_backend(*args, **kwargs) + + diff --git a/events/events_aio.c b/events/events_aio.c new file mode 100644 index 000000000..e30213acb --- /dev/null +++ b/events/events_aio.c @@ -0,0 +1,567 @@ +/* + Unix SMB/CIFS implementation. + + main select loop and event handling - aio/epoll hybrid implementation + + Copyright (C) Andrew Tridgell 2006 + + based on events_standard.c + + 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 . +*/ +/* + this is a very strange beast. The Linux AIO implementation doesn't + yet integrate properly with epoll, but there is a kernel patch that + allows the aio wait primitives to be used to wait for epoll events, + and this can be used to give us a unified event system incorporating + both aio events and epoll events + + this is _very_ experimental code +*/ + +#include "system/filesys.h" +#include "replace.h" +#include "events.h" +#include "events_internal.h" +#include "events_util.h" +#include +#include + +#define MAX_AIO_QUEUE_DEPTH 100 +#ifndef IOCB_CMD_EPOLL_WAIT +#define IOCB_CMD_EPOLL_WAIT 9 +#endif + +struct aio_event_context { + /* a pointer back to the generic event_context */ + struct event_context *ev; + + /* list of filedescriptor events */ + struct fd_event *fd_events; + + /* number of registered fd event handlers */ + int num_fd_events; + + uint32_t destruction_count; + + io_context_t ioctx; + + struct epoll_event epevent[MAX_AIO_QUEUE_DEPTH]; + + struct iocb *epoll_iocb; + + int epoll_fd; + int is_epoll_set; + pid_t pid; +}; + +struct aio_event { + struct event_context *event_ctx; + struct iocb iocb; + void *private_data; + event_aio_handler_t handler; +}; + +/* + map from EVENT_FD_* to EPOLLIN/EPOLLOUT +*/ +static uint32_t epoll_map_flags(uint16_t flags) +{ + uint32_t ret = 0; + if (flags & EVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP); + if (flags & EVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP); + return ret; +} + +/* + free the epoll fd +*/ +static int aio_ctx_destructor(struct aio_event_context *aio_ev) +{ + io_queue_release(aio_ev->ioctx); + close(aio_ev->epoll_fd); + aio_ev->epoll_fd = -1; + return 0; +} + +static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *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 aio_event_context *aio_ev) +{ + struct fd_event *fde; + + if (aio_ev->pid == getpid()) { + return; + } + + close(aio_ev->epoll_fd); + aio_ev->epoll_fd = epoll_create(MAX_AIO_QUEUE_DEPTH); + if (aio_ev->epoll_fd == -1) { + ev_debug(aio_ev->ev, EV_DEBUG_FATAL, "Failed to recreate epoll handle after fork\n"); + return; + } + aio_ev->pid = getpid(); + for (fde=aio_ev->fd_events;fde;fde=fde->next) { + epoll_add_event(aio_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 aio_event_context *aio_ev, struct fd_event *fde) +{ + struct epoll_event event; + if (aio_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 aio_event */ + if (fde->flags == 0) return; + + memset(&event, 0, sizeof(event)); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + epoll_ctl(aio_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event); + 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 & EVENT_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 aio_event_context *aio_ev, struct fd_event *fde) +{ + struct epoll_event event; + + DLIST_REMOVE(aio_ev->fd_events, fde); + + if (aio_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* if there's no aio_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(aio_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 aio_event_context *aio_ev, struct fd_event *fde) +{ + struct epoll_event event; + if (aio_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; + epoll_ctl(aio_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event); + + /* only if we want to read we want to tell the event handler about errors */ + if (fde->flags & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +static void epoll_change_event(struct aio_event_context *aio_ev, struct fd_event *fde) +{ + bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR); + bool want_read = (fde->flags & EVENT_FD_READ); + bool want_write= (fde->flags & EVENT_FD_WRITE); + + if (aio_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(aio_ev, fde); + return; + } + epoll_del_event(aio_ev, fde); + return; + } + + /* there's no aio_event attached to the fde */ + if (want_read || (want_write && !got_error)) { + DLIST_ADD(aio_ev->fd_events, fde); + epoll_add_event(aio_ev, fde); + return; + } +} + +static int setup_epoll_wait(struct aio_event_context *aio_ev) +{ + if (aio_ev->is_epoll_set) { + return 0; + } + memset(aio_ev->epoll_iocb, 0, sizeof(*aio_ev->epoll_iocb)); + aio_ev->epoll_iocb->aio_fildes = aio_ev->epoll_fd; + aio_ev->epoll_iocb->aio_lio_opcode = IOCB_CMD_EPOLL_WAIT; + aio_ev->epoll_iocb->aio_reqprio = 0; + + aio_ev->epoll_iocb->u.c.nbytes = MAX_AIO_QUEUE_DEPTH; + aio_ev->epoll_iocb->u.c.offset = -1; + aio_ev->epoll_iocb->u.c.buf = aio_ev->epevent; + + if (io_submit(aio_ev->ioctx, 1, &aio_ev->epoll_iocb) != 1) { + return -1; + } + aio_ev->is_epoll_set = 1; + + return 0; +} + + +/* + event loop handling using aio/epoll hybrid +*/ +static int aio_event_loop(struct aio_event_context *aio_ev, struct timeval *tvalp) +{ + int ret, i; + uint32_t destruction_count = ++aio_ev->destruction_count; + struct timespec timeout; + struct io_event events[8]; + + if (aio_ev->epoll_fd == -1) return -1; + + if (aio_ev->ev->num_signal_handlers && + common_event_check_signal(aio_ev->ev)) { + return 0; + } + + if (tvalp) { + timeout.tv_sec = tvalp->tv_sec; + timeout.tv_nsec = tvalp->tv_usec; + timeout.tv_nsec *= 1000; + } + + if (setup_epoll_wait(aio_ev) < 0) + return -1; + + ret = io_getevents(aio_ev->ioctx, 1, 8, + events, tvalp?&timeout:NULL); + + if (ret == -EINTR) { + if (aio_ev->ev->num_signal_handlers) { + common_event_check_signal(aio_ev->ev); + } + return 0; + } + + if (ret == 0 && tvalp) { + /* we don't care about a possible delay here */ + common_event_loop_timer_delay(aio_ev->ev); + return 0; + } + + for (i=0;iobj; + + switch (finished->aio_lio_opcode) { + case IO_CMD_PWRITE: + case IO_CMD_PREAD: { + struct aio_event *ae = talloc_get_type(finished->data, + struct aio_event); + if (ae) { + talloc_set_destructor(ae, NULL); + ae->handler(ae->event_ctx, ae, + event->res, ae->private_data); + talloc_free(ae); + } + break; + } + case IOCB_CMD_EPOLL_WAIT: { + struct epoll_event *ep = (struct epoll_event *)finished->u.c.buf; + struct fd_event *fde; + uint16_t flags = 0; + int j; + + aio_ev->is_epoll_set = 0; + + for (j=0; jres; j++, ep++) { + fde = talloc_get_type(ep->data.ptr, + struct fd_event); + if (fde == NULL) { + return -1; + } + if (ep->events & (EPOLLHUP|EPOLLERR)) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; + if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) { + epoll_del_event(aio_ev, fde); + continue; + } + flags |= EVENT_FD_READ; + } + if (ep->events & EPOLLIN) flags |= EVENT_FD_READ; + if (ep->events & EPOLLOUT) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(aio_ev->ev, fde, flags, fde->private_data); + } + } + break; + } + } + if (destruction_count != aio_ev->destruction_count) { + return 0; + } + } + + return 0; +} + +/* + create a aio_event_context structure. +*/ +static int aio_event_context_init(struct event_context *ev) +{ + struct aio_event_context *aio_ev; + + aio_ev = talloc_zero(ev, struct aio_event_context); + if (!aio_ev) return -1; + + aio_ev->ev = ev; + aio_ev->epoll_iocb = talloc(aio_ev, struct iocb); + + if (io_queue_init(MAX_AIO_QUEUE_DEPTH, &aio_ev->ioctx) != 0) { + talloc_free(aio_ev); + return -1; + } + + aio_ev->epoll_fd = epoll_create(MAX_AIO_QUEUE_DEPTH); + if (aio_ev->epoll_fd == -1) { + talloc_free(aio_ev); + return -1; + } + aio_ev->pid = getpid(); + + talloc_set_destructor(aio_ev, aio_ctx_destructor); + + ev->additional_data = aio_ev; + + if (setup_epoll_wait(aio_ev) < 0) { + talloc_free(aio_ev); + return -1; + } + + return 0; +} + +/* + destroy an fd_event +*/ +static int aio_event_fd_destructor(struct fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + + epoll_check_reopen(aio_ev); + + aio_ev->num_fd_events--; + aio_ev->destruction_count++; + + epoll_del_event(aio_ev, fde); + + 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 fd_event *aio_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + struct fd_event *fde; + + epoll_check_reopen(aio_ev); + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + 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; + + aio_ev->num_fd_events++; + talloc_set_destructor(fde, aio_event_fd_destructor); + + DLIST_ADD(aio_ev->fd_events, fde); + epoll_add_event(aio_ev, fde); + + return fde; +} + + +/* + return the fd event flags +*/ +static uint16_t aio_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void aio_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct event_context *ev; + struct aio_event_context *aio_ev; + + if (fde->flags == flags) return; + + ev = fde->event_ctx; + aio_ev = talloc_get_type(ev->additional_data, struct aio_event_context); + + fde->flags = flags; + + epoll_check_reopen(aio_ev); + + epoll_change_event(aio_ev, fde); +} + +/* + do a single event loop using the events defined in ev +*/ +static int aio_event_loop_once(struct event_context *ev) +{ + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + struct timeval tval; + + tval = common_event_loop_timer_delay(ev); + if (ev_timeval_is_zero(&tval)) { + return 0; + } + + epoll_check_reopen(aio_ev); + + return aio_event_loop(aio_ev, &tval); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int aio_event_loop_wait(struct event_context *ev) +{ + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + while (aio_ev->num_fd_events) { + if (aio_event_loop_once(ev) != 0) { + break; + } + } + + return 0; +} + +/* + called when a disk IO event needs to be cancelled +*/ +static int aio_destructor(struct aio_event *ae) +{ + struct event_context *ev = ae->event_ctx; + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + struct io_event result; + io_cancel(aio_ev->ioctx, &ae->iocb, &result); + /* TODO: handle errors from io_cancel()! */ + return 0; +} + +/* submit an aio disk IO event */ +static struct aio_event *aio_event_add_aio(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct iocb *iocb, + event_aio_handler_t handler, + void *private_data) +{ + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + struct iocb *iocbp; + struct aio_event *ae = talloc(mem_ctx?mem_ctx:ev, struct aio_event); + if (ae == NULL) return NULL; + + ae->event_ctx = ev; + ae->iocb = *iocb; + ae->handler = handler; + ae->private_data = private_data; + iocbp = &ae->iocb; + + if (io_submit(aio_ev->ioctx, 1, &iocbp) != 1) { + talloc_free(ae); + return NULL; + } + ae->iocb.data = ae; + talloc_set_destructor(ae, aio_destructor); + + return ae; +} + +static const struct event_ops aio_event_ops = { + .context_init = aio_event_context_init, + .add_fd = aio_event_add_fd, + .add_aio = aio_event_add_aio, + .get_fd_flags = aio_event_get_fd_flags, + .set_fd_flags = aio_event_set_fd_flags, + .add_timed = common_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = aio_event_loop_once, + .loop_wait = aio_event_loop_wait, +}; + +bool events_aio_init(void) +{ + return event_register_backend("aio", &aio_event_ops); +} + diff --git a/events/events_debug.c b/events/events_debug.c new file mode 100644 index 000000000..233844f02 --- /dev/null +++ b/events/events_debug.c @@ -0,0 +1,83 @@ +/* + 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 . +*/ + +#include "replace.h" +#include "events.h" +#include "events_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 ev_set_debug(struct event_context *ev, + void (*debug)(void *context, enum ev_debug_level level, + const char *fmt, va_list ap), + void *context) +{ + ev->debug_ops.debug = debug; + ev->debug_ops.context = context; + return 0; +} + +/* + debug function for ev_set_debug_stderr +*/ +void ev_debug_stderr(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); +void ev_debug_stderr(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) +{ + if (level <= EV_DEBUG_WARNING) { + vfprintf(stderr, fmt, ap); + } +} + +/* + convenience function to setup debug messages on stderr + messages of level EV_DEBUG_WARNING and higher are printed +*/ +int ev_set_debug_stderr(struct event_context *ev) +{ + return ev_set_debug(ev, ev_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 ev_debug(struct event_context *ev, enum ev_debug_level level, const char *fmt, ...) +{ + va_list ap; + 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); +} + diff --git a/events/events_epoll.c b/events/events_epoll.c new file mode 100644 index 000000000..d46d5c2bb --- /dev/null +++ b/events/events_epoll.c @@ -0,0 +1,482 @@ +/* + Unix SMB/CIFS implementation. + + main select loop and event handling - epoll implementation + + Copyright (C) Andrew Tridgell 2003-2005 + Copyright (C) Stefan Metzmacher 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 . +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/network.h" +#include "events.h" +#include "events_internal.h" +#include "events_util.h" +#include + +struct epoll_event_context { + /* a pointer back to the generic event_context */ + struct event_context *ev; + + /* list of filedescriptor events */ + struct fd_event *fd_events; + + /* number of registered fd event handlers */ + int num_fd_events; + + /* this is changed by the destructors for the fd event + type. It is used to detect event destruction by event + handlers, which means the code that is calling the event + handler needs to assume that the linked list is no longer + valid + */ + uint32_t destruction_count; + + /* 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) +{ + ev_debug(epoll_ev->ev, EV_DEBUG_FATAL, + "%s (%s) - calling abort()\n", reason, strerror(errno)); + abort(); +} + +/* + map from EVENT_FD_* to EPOLLIN/EPOLLOUT +*/ +static uint32_t epoll_map_flags(uint16_t flags) +{ + uint32_t ret = 0; + if (flags & EVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP); + if (flags & EVENT_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 fd_event *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 fd_event *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) { + ev_debug(epoll_ev->ev, EV_DEBUG_FATAL, + "Failed to recreate epoll handle after fork\n"); + return; + } + epoll_ev->pid = getpid(); + for (fde=epoll_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 fd_event *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 & EVENT_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 fd_event *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) { + ev_debug(epoll_ev->ev, EV_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 fd_event *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 & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +static void epoll_change_event(struct epoll_event_context *epoll_ev, struct fd_event *fde) +{ + bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR); + bool want_read = (fde->flags & EVENT_FD_READ); + bool want_write= (fde->flags & EVENT_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; + } +} + +/* + event loop handling using epoll +*/ +static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp) +{ + int ret, i; +#define MAXEVENTS 32 + struct epoll_event events[MAXEVENTS]; + uint32_t destruction_count = ++epoll_ev->destruction_count; + 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->num_signal_handlers && + common_event_check_signal(epoll_ev->ev)) { + return 0; + } + + ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout); + + if (ret == -1 && errno == EINTR && epoll_ev->ev->num_signal_handlers) { + if (common_event_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 */ + common_event_loop_timer_delay(epoll_ev->ev); + return 0; + } + + for (i=0;iadditional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; + /* + * if we only wait for EVENT_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 |= EVENT_FD_READ; + } + if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ; + if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(epoll_ev->ev, fde, flags, fde->private_data); + if (destruction_count != epoll_ev->destruction_count) { + break; + } + } + } + + return 0; +} + +/* + create a epoll_event_context structure. +*/ +static int epoll_event_context_init(struct event_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 fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, + struct epoll_event_context); + + epoll_check_reopen(epoll_ev); + + epoll_ev->num_fd_events--; + epoll_ev->destruction_count++; + + DLIST_REMOVE(epoll_ev->fd_events, fde); + + epoll_del_event(epoll_ev, fde); + + 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 fd_event *epoll_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, + struct epoll_event_context); + struct fd_event *fde; + + epoll_check_reopen(epoll_ev); + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + 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; + + epoll_ev->num_fd_events++; + talloc_set_destructor(fde, epoll_event_fd_destructor); + + DLIST_ADD(epoll_ev->fd_events, fde); + epoll_add_event(epoll_ev, fde); + + return fde; +} + + +/* + return the fd event flags +*/ +static uint16_t epoll_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void epoll_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct event_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 event_context *ev) +{ + struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, + struct epoll_event_context); + struct timeval tval; + + tval = common_event_loop_timer_delay(ev); + if (ev_timeval_is_zero(&tval)) { + return 0; + } + + epoll_check_reopen(epoll_ev); + + return epoll_event_loop(epoll_ev, &tval); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int epoll_event_loop_wait(struct event_context *ev) +{ + struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, + struct epoll_event_context); + while (epoll_ev->num_fd_events) { + if (epoll_event_loop_once(ev) != 0) { + break; + } + } + + return 0; +} + +static const struct event_ops epoll_event_ops = { + .context_init = epoll_event_context_init, + .add_fd = epoll_event_add_fd, + .get_fd_flags = epoll_event_get_fd_flags, + .set_fd_flags = epoll_event_set_fd_flags, + .add_timed = common_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = epoll_event_loop_once, + .loop_wait = epoll_event_loop_wait, +}; + +bool events_epoll_init(void) +{ + return event_register_backend("epoll", &epoll_event_ops); +} diff --git a/events/events_internal.h b/events/events_internal.h new file mode 100644 index 000000000..0d0755f29 --- /dev/null +++ b/events/events_internal.h @@ -0,0 +1,158 @@ +/* + Unix SMB/CIFS implementation. + + generalised event loop handling + + Internal structs + + Copyright (C) Stefan Metzmacher 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 . +*/ + +struct event_ops { + /* conntext init */ + int (*context_init)(struct event_context *ev); + + /* fd_event functions */ + struct fd_event *(*add_fd)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data); + uint16_t (*get_fd_flags)(struct fd_event *fde); + void (*set_fd_flags)(struct fd_event *fde, uint16_t flags); + + /* timed_event functions */ + struct timed_event *(*add_timed)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data); + /* disk aio event functions */ + struct aio_event *(*add_aio)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct iocb *iocb, + event_aio_handler_t handler, + void *private_data); + /* signal functions */ + struct signal_event *(*add_signal)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int signum, int sa_flags, + event_signal_handler_t handler, + void *private_data); + + /* loop functions */ + int (*loop_once)(struct event_context *ev); + int (*loop_wait)(struct event_context *ev); +}; + +struct fd_event { + struct fd_event *prev, *next; + struct event_context *event_ctx; + int fd; + uint16_t flags; /* see EVENT_FD_* flags */ + event_fd_handler_t handler; + /* this is private for the specific handler */ + void *private_data; + /* this is private for the events_ops implementation */ + uint16_t additional_flags; + void *additional_data; +}; + +struct timed_event { + struct timed_event *prev, *next; + struct event_context *event_ctx; + struct timeval next_event; + event_timed_handler_t handler; + /* this is private for the specific handler */ + void *private_data; + /* this is private for the events_ops implementation */ + void *additional_data; +}; + +struct signal_event { + struct signal_event *prev, *next; + struct event_context *event_ctx; + event_signal_handler_t handler; + void *private_data; + int signum; + int sa_flags; +}; + +/* DEBUG */ +enum ev_debug_level {EV_DEBUG_FATAL, EV_DEBUG_ERROR, + EV_DEBUG_WARNING, EV_DEBUG_TRACE}; + +struct ev_debug_ops { + void (*debug)(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); + void *context; +}; + +int ev_set_debug(struct event_context *ev, + void (*debug)(void *context, enum ev_debug_level level, + const char *fmt, va_list ap), + void *context); +int ev_set_debug_stderr(struct event_context *ev); +void ev_debug(struct event_context *ev, enum ev_debug_level level, const char *fmt, ...); + +/* aio event is private to the aio backend */ +struct aio_event; + +struct event_context { + /* the specific events implementation */ + const struct event_ops *ops; + + /* list of timed events - used by common code */ + struct timed_event *timed_events; + + /* this is private for the events_ops implementation */ + void *additional_data; + + /* number of signal event handlers */ + int num_signal_handlers; + + /* pipe hack used with signal handlers */ + struct fd_event *pipe_fde; + + /* debugging operations */ + struct ev_debug_ops debug_ops; +}; + + +bool event_register_backend(const char *name, const struct event_ops *ops); + +bool ev_timeval_is_zero(const struct timeval *tv); +struct timed_event *common_event_add_timed(struct event_context *, TALLOC_CTX *, + struct timeval, event_timed_handler_t, void *); +struct timeval common_event_loop_timer_delay(struct event_context *); + +struct signal_event *common_event_add_signal(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int signum, + int sa_flags, + event_signal_handler_t handler, + void *private_data); +int common_event_check_signal(struct event_context *ev); + + +bool events_standard_init(void); +bool events_select_init(void); +#if HAVE_EVENTS_EPOLL +bool events_epoll_init(void); +#endif +#if HAVE_LINUX_AIO +bool events_aio_init(void); +#endif diff --git a/events/events_liboop.c b/events/events_liboop.c new file mode 100644 index 000000000..339297a3c --- /dev/null +++ b/events/events_liboop.c @@ -0,0 +1,288 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + wrapper for http://liboop.org/ + + Copyright (C) Stefan Metzmacher 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 . +*/ + +#include "events.h" +#include "events_internal.h" + +#include + +/* + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + NOTE: this code compiles fine, but is completly *UNTESTED* + and is only commited as example + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +*/ + +static int oop_event_context_destructor(struct event_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 event_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 fd_event *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 fd_event *fde) +{ + struct event_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 fd_event *oop_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct fd_event *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 fd_event); + 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 fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void oop_event_set_fd_flags(struct fd_event *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 timed_event *te); + +static int oop_event_timed_deny_destructor(struct timed_event *te) +{ + return -1; +} + +static void *oop_event_timed_handler(oop_source *oop, struct timeval t, void *ptr) +{ + struct timed_event *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 timed_event *te) +{ + struct event_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 timed_event *oop_event_add_timed(struct event_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 timed_event *te; + + te = talloc(mem_ctx?mem_ctx:ev, struct timed_event); + 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 event_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 event_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_timed = 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; +} diff --git a/events/events_s4.c b/events/events_s4.c new file mode 100644 index 000000000..134f899cf --- /dev/null +++ b/events/events_s4.c @@ -0,0 +1,108 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Andrew Tridgell 2003 + + 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 . +*/ + +#include "includes.h" +#include "events.h" +#include "events_internal.h" + +NTSTATUS s4_events_standard_init(void) +{ + if (!events_standard_init()) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} + +NTSTATUS s4_events_select_init(void) +{ + if (!events_select_init()) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} + +#if HAVE_EVENTS_EPOLL +NTSTATUS s4_events_epoll_init(void) +{ + if (!events_epoll_init()) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} +#endif + +#if HAVE_LINUX_AIO +NTSTATUS s4_events_aio_init(void) +{ + if (!events_aio_init()) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} +#endif + +/* + this is used to catch debug messages from events +*/ +static void ev_wrap_debug(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); + +static void ev_wrap_debug(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) +{ + int samba_level = -1; + char *s = NULL; + switch (level) { + case EV_DEBUG_FATAL: + samba_level = 0; + break; + case EV_DEBUG_ERROR: + samba_level = 1; + break; + case EV_DEBUG_WARNING: + samba_level = 2; + break; + case EV_DEBUG_TRACE: + samba_level = 5; + break; + + }; + vasprintf(&s, fmt, ap); + if (!s) return; + DEBUG(samba_level, ("events: %s\n", s)); + free(s); +} + +/* + 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. + + This samba4 specific call sets the samba4 debug handler. +*/ +struct event_context *s4_event_context_init(TALLOC_CTX *mem_ctx) +{ + struct event_context *ev; + + ev = event_context_init_byname(mem_ctx, NULL); + if (ev) { + ev_set_debug(ev, ev_wrap_debug, NULL); + } + return ev; +} + diff --git a/events/events_select.c b/events/events_select.c new file mode 100644 index 000000000..54d32204f --- /dev/null +++ b/events/events_select.c @@ -0,0 +1,302 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + Copyright (C) Andrew Tridgell 2003-2005 + Copyright (C) Stefan Metzmacher 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 . +*/ + +/* + This is SAMBA's default event loop code + +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/select.h" +#include "events.h" +#include "events_util.h" +#include "events_internal.h" + +struct select_event_context { + /* a pointer back to the generic event_context */ + struct event_context *ev; + + /* list of filedescriptor events */ + struct fd_event *fd_events; + + /* list of timed events */ + struct timed_event *timed_events; + + /* the maximum file descriptor number in fd_events */ + int maxfd; + + /* information for exiting from the event loop */ + int exit_code; + + /* this is incremented when the loop over events causes something which + could change the events yet to be processed */ + uint32_t destruction_count; +}; + +/* + create a select_event_context structure. +*/ +static int select_event_context_init(struct event_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 fd_event *fde; + + select_ev->maxfd = 0; + for (fde = select_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 fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + struct select_event_context *select_ev = talloc_get_type(ev->additional_data, + struct select_event_context); + + if (select_ev->maxfd == fde->fd) { + select_ev->maxfd = EVENT_INVALID_MAXFD; + } + + DLIST_REMOVE(select_ev->fd_events, fde); + select_ev->destruction_count++; + + 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 fd_event *select_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct select_event_context *select_ev = talloc_get_type(ev->additional_data, + struct select_event_context); + struct fd_event *fde; + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + 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; + + DLIST_ADD(select_ev->fd_events, fde); + if (fde->fd > select_ev->maxfd) { + select_ev->maxfd = fde->fd; + } + talloc_set_destructor(fde, select_event_fd_destructor); + + return fde; +} + + +/* + return the fd event flags +*/ +static uint16_t select_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void select_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct event_context *ev; + struct select_event_context *select_ev; + + if (fde->flags == flags) return; + + ev = fde->event_ctx; + select_ev = talloc_get_type(ev->additional_data, struct select_event_context); + + fde->flags = flags; +} + +/* + 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 fd_event *fde; + int selrtn; + uint32_t destruction_count = ++select_ev->destruction_count; + + /* 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->fd_events; fde; fde = fde->next) { + if (fde->flags & EVENT_FD_READ) { + FD_SET(fde->fd, &r_fds); + } + if (fde->flags & EVENT_FD_WRITE) { + FD_SET(fde->fd, &w_fds); + } + } + + if (select_ev->ev->num_signal_handlers && + common_event_check_signal(select_ev->ev)) { + return 0; + } + + selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); + + if (selrtn == -1 && errno == EINTR && + select_ev->ev->num_signal_handlers) { + common_event_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. */ + ev_debug(select_ev->ev, EV_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 */ + common_event_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->fd_events; fde; fde = fde->next) { + uint16_t flags = 0; + + if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ; + if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(select_ev->ev, fde, flags, fde->private_data); + if (destruction_count != select_ev->destruction_count) { + break; + } + } + } + } + + return 0; +} + +/* + do a single event loop using the events defined in ev +*/ +static int select_event_loop_once(struct event_context *ev) +{ + struct select_event_context *select_ev = talloc_get_type(ev->additional_data, + struct select_event_context); + struct timeval tval; + + tval = common_event_loop_timer_delay(ev); + if (ev_timeval_is_zero(&tval)) { + return 0; + } + + return select_event_loop_select(select_ev, &tval); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int select_event_loop_wait(struct event_context *ev) +{ + struct select_event_context *select_ev = talloc_get_type(ev->additional_data, + struct select_event_context); + select_ev->exit_code = 0; + + while (select_ev->fd_events && select_ev->exit_code == 0) { + if (select_event_loop_once(ev) != 0) { + break; + } + } + + return select_ev->exit_code; +} + +static const struct event_ops select_event_ops = { + .context_init = select_event_context_init, + .add_fd = select_event_add_fd, + .get_fd_flags = select_event_get_fd_flags, + .set_fd_flags = select_event_set_fd_flags, + .add_timed = common_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = select_event_loop_once, + .loop_wait = select_event_loop_wait, +}; + +bool events_select_init(void) +{ + return event_register_backend("select", &select_event_ops); +} + diff --git a/events/events_signal.c b/events/events_signal.c new file mode 100644 index 000000000..652df53d4 --- /dev/null +++ b/events/events_signal.c @@ -0,0 +1,291 @@ +/* + Unix SMB/CIFS implementation. + + common events code for signal events + + 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 . +*/ + +#include +#include "replace.h" +#include "system/filesys.h" +#include "system/select.h" +#include "events.h" +#include "events_internal.h" +#include "events_util.h" + +#define NUM_SIGNALS 64 + +/* maximum number of SA_SIGINFO signals to hold in the queue */ +#define SA_INFO_QUEUE_COUNT 10 + +struct sigcounter { + uint32_t count; + uint32_t seen; +}; + +#define SIG_INCREMENT(s) (s).count++ +#define SIG_SEEN(s, n) (s).seen += (n) +#define SIG_PENDING(s) ((s).seen != (s).count) + + +/* + the poor design of signals means that this table must be static global +*/ +static struct sig_state { + struct signal_event *sig_handlers[NUM_SIGNALS+1]; + struct sigaction *oldact[NUM_SIGNALS+1]; + struct sigcounter signal_count[NUM_SIGNALS+1]; + struct sigcounter got_signal; + int pipe_hack[2]; +#ifdef SA_SIGINFO + /* with SA_SIGINFO we get quite a lot of info per signal */ + siginfo_t *sig_info[NUM_SIGNALS+1]; + struct sigcounter sig_blocked[NUM_SIGNALS+1]; +#endif +} *sig_state; + +/* + return number of sigcounter events not processed yet +*/ +static uint32_t sig_count(struct sigcounter s) +{ + if (s.count >= s.seen) { + return s.count - s.seen; + } + return 1 + (0xFFFFFFFF & ~(s.seen - s.count)); +} + +/* + signal handler - redirects to registered signals +*/ +static void signal_handler(int signum) +{ + char c = 0; + SIG_INCREMENT(sig_state->signal_count[signum]); + SIG_INCREMENT(sig_state->got_signal); + /* doesn't matter if this pipe overflows */ + write(sig_state->pipe_hack[1], &c, 1); +} + +#ifdef SA_SIGINFO +/* + signal handler with SA_SIGINFO - redirects to registered signals +*/ +static void signal_handler_info(int signum, siginfo_t *info, void *uctx) +{ + uint32_t count = sig_count(sig_state->signal_count[signum]); + sig_state->sig_info[signum][count] = *info; + + signal_handler(signum); + + /* handle SA_SIGINFO */ + if (count+1 == 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); + SIG_INCREMENT(sig_state->sig_blocked[signum]); + } +} +#endif + +/* + destroy a signal event +*/ +static int signal_event_destructor(struct signal_event *se) +{ + se->event_ctx->num_signal_handlers--; + DLIST_REMOVE(sig_state->sig_handlers[se->signum], se); + if (sig_state->sig_handlers[se->signum] == NULL) { + /* restore old handler, if any */ + sigaction(se->signum, sig_state->oldact[se->signum], NULL); + sig_state->oldact[se->signum] = NULL; +#ifdef SA_SIGINFO + if (se->sa_flags & SA_SIGINFO) { + 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 event_context *ev, struct fd_event *fde, + uint16_t flags, void *private) +{ + char c[16]; + /* its non-blocking, doesn't matter if we read too much */ + read(sig_state->pipe_hack[0], c, sizeof(c)); +} + +/* + add a signal event + return NULL on failure (memory allocation error) +*/ +struct signal_event *common_event_add_signal(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int signum, + int sa_flags, + event_signal_handler_t handler, + void *private_data) +{ + struct signal_event *se; + + if (signum >= NUM_SIGNALS) { + 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 sig_state); + if (sig_state == NULL) { + return NULL; + } + } + + se = talloc(mem_ctx?mem_ctx:ev, struct signal_event); + if (se == NULL) return NULL; + + se->event_ctx = ev; + se->handler = handler; + se->private_data = private_data; + se->signum = signum; + se->sa_flags = sa_flags; + + /* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */ + if (!talloc_reference(se, sig_state)) { + 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 = signal_handler; + act.sa_flags = sa_flags; +#ifdef SA_SIGINFO + if (sa_flags & SA_SIGINFO) { + act.sa_handler = NULL; + act.sa_sigaction = signal_handler_info; + if (sig_state->sig_info[signum] == NULL) { + sig_state->sig_info[signum] = talloc_array(sig_state, siginfo_t, 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(sig_state->sig_handlers[signum], se); + + talloc_set_destructor(se, signal_event_destructor); + + /* we need to setup the pipe hack handler if not already + setup */ + if (ev->pipe_fde == NULL) { + if (sig_state->pipe_hack[0] == 0 && + sig_state->pipe_hack[1] == 0) { + pipe(sig_state->pipe_hack); + ev_set_blocking(sig_state->pipe_hack[0], false); + ev_set_blocking(sig_state->pipe_hack[1], false); + } + ev->pipe_fde = event_add_fd(ev, ev, sig_state->pipe_hack[0], + EVENT_FD_READ, signal_pipe_handler, NULL); + } + ev->num_signal_handlers++; + + return se; +} + + +/* + check if a signal is pending + return != 0 if a signal was pending +*/ +int common_event_check_signal(struct event_context *ev) +{ + int i; + + if (!sig_state || !SIG_PENDING(sig_state->got_signal)) { + return 0; + } + + for (i=0;isignal_count[i]; + uint32_t count = sig_count(counter); + + if (count == 0) { + continue; + } + for (se=sig_state->sig_handlers[i];se;se=next) { + next = se->next; +#ifdef SA_SIGINFO + if (se->sa_flags & SA_SIGINFO) { + int j; + for (j=0;jhandler(ev, se, i, 1, + (void*)&sig_state->sig_info[i][ofs], + se->private_data); + } + if (SIG_PENDING(sig_state->sig_blocked[i])) { + /* we'd filled the queue, unblock the + signal now */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, i); + SIG_SEEN(sig_state->sig_blocked[i], + sig_count(sig_state->sig_blocked[i])); + sigprocmask(SIG_UNBLOCK, &set, NULL); + } + 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); + } + } + SIG_SEEN(sig_state->signal_count[i], count); + SIG_SEEN(sig_state->got_signal, count); + } + + return 1; +} diff --git a/events/events_standard.c b/events/events_standard.c new file mode 100644 index 000000000..11128d762 --- /dev/null +++ b/events/events_standard.c @@ -0,0 +1,607 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + Copyright (C) Andrew Tridgell 2003-2005 + Copyright (C) Stefan Metzmacher 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 . +*/ + +/* + 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/network.h" +#include "system/select.h" /* needed for HAVE_EVENTS_EPOLL */ +#include "events.h" +#include "events_util.h" +#include "events_internal.h" + +struct std_event_context { + /* a pointer back to the generic event_context */ + struct event_context *ev; + + /* list of filedescriptor events */ + struct fd_event *fd_events; + + /* the maximum file descriptor number in fd_events */ + int maxfd; + + /* information for exiting from the event loop */ + int exit_code; + + /* this is changed by the destructors for the fd event + type. It is used to detect event destruction by event + handlers, which means the code that is calling the event + handler needs to assume that the linked list is no longer + valid + */ + uint32_t destruction_count; + + /* 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_EVENTS_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) +{ + ev_debug(std_ev->ev, EV_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 EVENT_FD_* to EPOLLIN/EPOLLOUT +*/ +static uint32_t epoll_map_flags(uint16_t flags) +{ + uint32_t ret = 0; + if (flags & EVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP); + if (flags & EVENT_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 fd_event *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 fd_event *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) { + ev_debug(std_ev->ev, EV_DEBUG_FATAL, + "Failed to recreate epoll handle after fork\n"); + return; + } + std_ev->pid = getpid(); + for (fde=std_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 fd_event *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 & EVENT_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 fd_event *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 fd_event *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 & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +static void epoll_change_event(struct std_event_context *std_ev, struct fd_event *fde) +{ + bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR); + bool want_read = (fde->flags & EVENT_FD_READ); + bool want_write= (fde->flags & EVENT_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; + } +} + +/* + event loop handling using epoll +*/ +static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp) +{ + int ret, i; +#define MAXEVENTS 8 + struct epoll_event events[MAXEVENTS]; + uint32_t destruction_count = ++std_ev->destruction_count; + 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->num_signal_handlers && + common_event_check_signal(std_ev->ev)) { + return 0; + } + + ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout); + + if (ret == -1 && errno == EINTR && std_ev->ev->num_signal_handlers) { + if (common_event_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 */ + common_event_loop_timer_delay(std_ev->ev); + return 0; + } + + for (i=0;iadditional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; + /* + * if we only wait for EVENT_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 |= EVENT_FD_READ; + } + if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ; + if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(std_ev->ev, fde, flags, fde->private_data); + if (destruction_count != std_ev->destruction_count) { + 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 event_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 fd_event *fde; + + std_ev->maxfd = 0; + for (fde = std_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 fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + struct std_event_context *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; + } + + DLIST_REMOVE(std_ev->fd_events, fde); + std_ev->destruction_count++; + + epoll_del_event(std_ev, fde); + + 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 fd_event *std_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + struct fd_event *fde; + + epoll_check_reopen(std_ev); + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + 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; + + DLIST_ADD(std_ev->fd_events, fde); + 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; +} + + +/* + return the fd event flags +*/ +static uint16_t std_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void std_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct event_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 fd_event *fde; + int selrtn; + uint32_t destruction_count = ++std_ev->destruction_count; + + /* 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->fd_events; fde; fde = fde->next) { + if (fde->flags & EVENT_FD_READ) { + FD_SET(fde->fd, &r_fds); + } + if (fde->flags & EVENT_FD_WRITE) { + FD_SET(fde->fd, &w_fds); + } + } + + if (std_ev->ev->num_signal_handlers && + common_event_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->num_signal_handlers) { + common_event_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. */ + ev_debug(std_ev->ev, EV_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 */ + common_event_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->fd_events; fde; fde = fde->next) { + uint16_t flags = 0; + + if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ; + if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(std_ev->ev, fde, flags, fde->private_data); + if (destruction_count != std_ev->destruction_count) { + break; + } + } + } + } + + return 0; +} + +/* + do a single event loop using the events defined in ev +*/ +static int std_event_loop_once(struct event_context *ev) +{ + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + struct timeval tval; + + tval = common_event_loop_timer_delay(ev); + if (ev_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); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int std_event_loop_wait(struct event_context *ev) +{ + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + std_ev->exit_code = 0; + + while (std_ev->fd_events && std_ev->exit_code == 0) { + if (std_event_loop_once(ev) != 0) { + break; + } + } + + return std_ev->exit_code; +} + +static const struct event_ops std_event_ops = { + .context_init = std_event_context_init, + .add_fd = std_event_add_fd, + .get_fd_flags = std_event_get_fd_flags, + .set_fd_flags = std_event_set_fd_flags, + .add_timed = common_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = std_event_loop_once, + .loop_wait = std_event_loop_wait, +}; + + +bool events_standard_init(void) +{ + return event_register_backend("standard", &std_event_ops); +} + diff --git a/events/events_timed.c b/events/events_timed.c new file mode 100644 index 000000000..c58c898c6 --- /dev/null +++ b/events/events_timed.c @@ -0,0 +1,230 @@ +/* + Unix SMB/CIFS implementation. + + common events code for timed events + + Copyright (C) Andrew Tridgell 2003-2006 + Copyright (C) Stefan Metzmacher 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 . +*/ + +#include +#include +#include "replace.h" +#include "system/filesys.h" +#include "system/select.h" +#include "events.h" +#include "events_internal.h" +#include "events_util.h" + +/** + compare two timeval structures. + Return -1 if tv1 < tv2 + Return 0 if tv1 == tv2 + Return 1 if tv1 > tv2 +*/ +static int ev_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 +*/ +static struct timeval ev_timeval_zero(void) +{ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + return tv; +} + +/** + return a timeval for the current time +*/ +static struct timeval ev_timeval_current(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv; +} + +/** + return a timeval struct with the given elements +*/ +static struct timeval ev_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) +*/ +static struct timeval ev_timeval_until(const struct timeval *tv1, + const struct timeval *tv2) +{ + struct timeval t; + if (ev_timeval_compare(tv1, tv2) >= 0) { + return ev_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 ev_timeval_is_zero(const struct timeval *tv) +{ + return tv->tv_sec == 0 && tv->tv_usec == 0; +} + +/* + destroy a timed event +*/ +static int common_event_timed_destructor(struct timed_event *te) +{ + struct event_context *ev = talloc_get_type(te->event_ctx, + struct event_context); + DLIST_REMOVE(ev->timed_events, te); + return 0; +} + +static int common_event_timed_deny_destructor(struct timed_event *te) +{ + return -1; +} + +/* + add a timed event + return NULL on failure (memory allocation error) +*/ +struct timed_event *common_event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data) +{ + struct timed_event *te, *last_te, *cur_te; + + te = talloc(mem_ctx?mem_ctx:ev, struct timed_event); + 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; + + /* keep the list ordered */ + last_te = NULL; + for (cur_te = ev->timed_events; cur_te; cur_te = cur_te->next) { + /* if the new event comes before the current one break */ + if (ev_timeval_compare(&te->next_event, &cur_te->next_event) < 0) { + break; + } + + last_te = cur_te; + } + + DLIST_ADD_AFTER(ev->timed_events, te, last_te); + + talloc_set_destructor(te, common_event_timed_destructor); + + 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 common_event_loop_timer_delay(struct event_context *ev) +{ + struct timeval current_time = ev_timeval_zero(); + struct timed_event *te = ev->timed_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 ev_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 (!ev_timeval_is_zero(&te->next_event)) { + struct timeval delay; + + current_time = ev_timeval_current(); + + delay = ev_timeval_until(¤t_time, &te->next_event); + if (!ev_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, common_event_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->timed_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); + + talloc_free(te); + + return ev_timeval_zero(); +} + diff --git a/events/events_util.c b/events/events_util.c new file mode 100644 index 000000000..93f649256 --- /dev/null +++ b/events/events_util.c @@ -0,0 +1,85 @@ +/* + 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 . +*/ + +#include "replace.h" +#include "talloc.h" +#include "events.h" +#include "events_internal.h" +#include + +/** + return the number of elements in a string list +*/ +static 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 +*/ +const char **ev_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; +} + + +/** + 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 +} diff --git a/events/events_util.h b/events/events_util.h new file mode 100644 index 000000000..052b302aa --- /dev/null +++ b/events/events_util.h @@ -0,0 +1,117 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 1998-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 . +*/ + +/* To use these macros you must have a structure containing a next and + prev pointer */ + +#ifndef _DLINKLIST_H +#define _DLINKLIST_H + + +/* hook into the front of the list */ +#define DLIST_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 DLIST_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) != (list)) (p)->next = (p)->prev = NULL; \ +} while (0) + +/* promote an element to the top of the list */ +#define DLIST_PROMOTE(list, p) \ +do { \ + DLIST_REMOVE(list, p); \ + DLIST_ADD(list, p); \ +} while (0) + +/* hook into the end of the list - needs a tmp pointer */ +#define DLIST_ADD_END(list, p, type) \ +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) + +/* 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; \ + }\ +} while (0) + +/* demote an element to the end of the list, needs a tmp pointer */ +#define DLIST_DEMOTE(list, p, tmp) \ +do { \ + DLIST_REMOVE(list, p); \ + DLIST_ADD_END(list, p, tmp); \ +} while (0) + +/* concatenate two lists - putting all elements of the 2nd list at the + end of the first list */ +#define DLIST_CONCATENATE(list1, list2, type) \ +do { \ + if (!(list1)) { \ + (list1) = (list2); \ + } else { \ + type tmp; \ + for (tmp = (list1); tmp->next; tmp = tmp->next) ; \ + tmp->next = (list2); \ + if (list2) { \ + (list2)->prev = tmp; \ + } \ + } \ +} 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); diff --git a/events/events_wrap.c b/events/events_wrap.c new file mode 100644 index 000000000..ccaeab7ad --- /dev/null +++ b/events/events_wrap.c @@ -0,0 +1,3343 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.35 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +#define SWIGPYTHON +#define SWIG_PYTHON_NO_BUILD_NONE +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# elif defined(__HP_aCC) +/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ +/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + + + +/* Python.h has to appear first */ +#include + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The swig conversion methods, as ConvertPtr, return and integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old swig versions, you usually write code as: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit as: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + that seems to be the same, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + requires also to SWIG_ConvertPtr to return new result values, as + + int SWIG_ConvertPtr(obj, ptr,...) { + if () { + if () { + *ptr = ; + return SWIG_NEWOBJ; + } else { + *ptr = ; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + swig errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() + + + */ +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class" == "Class", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like ||... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like ||... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCompare(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + + +/* think of this as a c++ template<> or a scheme macro */ +#define SWIG_TypeCheck_Template(comparison, ty) \ + if (ty) { \ + swig_cast_info *iter = ty->cast; \ + while (iter) { \ + if (comparison) { \ + if (iter == ty->cast) return iter; \ + /* Move iter to the top of the linked list */ \ + iter->prev->next = iter->next; \ + if (iter->next) \ + iter->next->prev = iter->prev; \ + iter->next = ty->cast; \ + iter->prev = 0; \ + if (ty->cast) ty->cast->prev = iter; \ + ty->cast = iter; \ + return iter; \ + } \ + iter = iter->next; \ + } \ + } \ + return 0 + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty); +} + +/* Same as previous function, except strcmp is replaced with a pointer comparison */ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) { + SWIG_TypeCheck_Template(iter->type == from, into); +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + + +/* Add PyOS_snprintf for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# define PyOS_snprintf _snprintf +# else +# define PyOS_snprintf snprintf +# endif +#endif + +/* A crude PyString_FromFormat implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 + +#ifndef SWIG_PYBUFFER_SIZE +# define SWIG_PYBUFFER_SIZE 1024 +#endif + +static PyObject * +PyString_FromFormat(const char *fmt, ...) { + va_list ap; + char buf[SWIG_PYBUFFER_SIZE * 2]; + int res; + va_start(ap, fmt); + res = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); +} +#endif + +/* Add PyObject_Del for old Pythons */ +#if PY_VERSION_HEX < 0x01060000 +# define PyObject_Del(op) PyMem_DEL((op)) +#endif +#ifndef PyObject_DEL +# define PyObject_DEL PyObject_Del +#endif + +/* A crude PyExc_StopIteration exception for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# ifndef PyExc_StopIteration +# define PyExc_StopIteration PyExc_RuntimeError +# endif +# ifndef PyObject_GenericGetAttr +# define PyObject_GenericGetAttr 0 +# endif +#endif +/* Py_NotImplemented is defined in 2.1 and up. */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef Py_NotImplemented +# define Py_NotImplemented PyExc_RuntimeError +# endif +#endif + + +/* A crude PyString_AsStringAndSize implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef PyString_AsStringAndSize +# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} +# endif +#endif + +/* PySequence_Size for old Pythons */ +#if PY_VERSION_HEX < 0x02000000 +# ifndef PySequence_Size +# define PySequence_Size PySequence_Length +# endif +#endif + + +/* PyBool_FromLong for old Pythons */ +#if PY_VERSION_HEX < 0x02030000 +static +PyObject *PyBool_FromLong(long ok) +{ + PyObject *result = ok ? Py_True : Py_False; + Py_INCREF(result); + return result; +} +#endif + +/* Py_ssize_t for old Pythons */ +/* This code is as recommended by: */ +/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +#endif + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIME PyObject* +SWIG_Python_ErrorType(int code) { + PyObject* type = 0; + switch(code) { + case SWIG_MemoryError: + type = PyExc_MemoryError; + break; + case SWIG_IOError: + type = PyExc_IOError; + break; + case SWIG_RuntimeError: + type = PyExc_RuntimeError; + break; + case SWIG_IndexError: + type = PyExc_IndexError; + break; + case SWIG_TypeError: + type = PyExc_TypeError; + break; + case SWIG_DivisionByZero: + type = PyExc_ZeroDivisionError; + break; + case SWIG_OverflowError: + type = PyExc_OverflowError; + break; + case SWIG_SyntaxError: + type = PyExc_SyntaxError; + break; + case SWIG_ValueError: + type = PyExc_ValueError; + break; + case SWIG_SystemError: + type = PyExc_SystemError; + break; + case SWIG_AttributeError: + type = PyExc_AttributeError; + break; + default: + type = PyExc_RuntimeError; + } + return type; +} + + +SWIGRUNTIME void +SWIG_Python_AddErrorMsg(const char* mesg) +{ + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + + if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + PyErr_Clear(); + Py_XINCREF(type); + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + Py_DECREF(old_str); + Py_DECREF(value); + } else { + PyErr_SetString(PyExc_RuntimeError, mesg); + } +} + + + +#if defined(SWIG_PYTHON_NO_THREADS) +# if defined(SWIG_PYTHON_THREADS) +# undef SWIG_PYTHON_THREADS +# endif +#endif +#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ +# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) +# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ +# define SWIG_PYTHON_USE_GIL +# endif +# endif +# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ +# ifndef SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() +# endif +# ifdef __cplusplus /* C++ code */ + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + public: + void end() { if (status) { PyEval_RestoreThread(save); status = false; }} + SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} + ~SWIG_Python_Thread_Allow() { end(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow +# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() +# else /* C code */ +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() +# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() +# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) +# define SWIG_PYTHON_INITIALIZE_THREADS +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif + +/* ----------------------------------------------------------------------------- + * Python API portion that goes into the runtime + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_PY_POINTER 4 +#define SWIG_PY_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * pyrun.swg + * + * This file contains the runtime support for Python modules + * and includes code for managing global variables and pointer + * type checking. + * + * ----------------------------------------------------------------------------- */ + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) +#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) +#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(ptr, type, flags) +#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) +#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) +#define swig_owntype int + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Python_GetModule() +#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) +#define SWIG_NewClientData(obj) PySwigClientData_New(obj) + +#define SWIG_SetErrorObj SWIG_Python_SetErrorObj +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Runtime API implementation */ + +/* Error manipulation */ + +SWIGINTERN void +SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetObject(errtype, obj); + Py_DECREF(obj); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +SWIGINTERN void +SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(errtype, (char *) msg); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) + +/* Set a constant value */ + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { + PyDict_SetItemString(d, (char*) name, obj); + Py_DECREF(obj); +} + +/* Append a value to the result obj */ + +SWIGINTERN PyObject* +SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { +#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyList_Check(result)) { + PyObject *o2 = result; + result = PyList_New(1); + PyList_SetItem(result, 0, o2); + } + PyList_Append(result,obj); + Py_DECREF(obj); + } + return result; +#else + PyObject* o2; + PyObject* o3; + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyTuple_Check(result)) { + o2 = result; + result = PyTuple_New(1); + PyTuple_SET_ITEM(result, 0, o2); + } + o3 = PyTuple_New(1); + PyTuple_SET_ITEM(o3, 0, obj); + o2 = result; + result = PySequence_Concat(o2, o3); + Py_DECREF(o2); + Py_DECREF(o3); + } + return result; +#endif +} + +/* Unpack the argument tuple */ + +SWIGINTERN int +SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) +{ + if (!args) { + if (!min && !max) { + return 1; + } else { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", + name, (min == max ? "" : "at least "), (int)min); + return 0; + } + } + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); + return 0; + } else { + register Py_ssize_t l = PyTuple_GET_SIZE(args); + if (l < min) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at least "), (int)min, (int)l); + return 0; + } else if (l > max) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at most "), (int)max, (int)l); + return 0; + } else { + register int i; + for (i = 0; i < l; ++i) { + objs[i] = PyTuple_GET_ITEM(args, i); + } + for (; l < max; ++l) { + objs[l] = 0; + } + return i + 1; + } + } +} + +/* A functor is a function object with one single object argument */ +#if PY_VERSION_HEX >= 0x02020000 +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); +#else +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); +#endif + +/* + Helper for static pointer initialization for both C and C++ code, for example + static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); +*/ +#ifdef __cplusplus +#define SWIG_STATIC_POINTER(var) var +#else +#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var +#endif + +/* ----------------------------------------------------------------------------- + * Pointer declarations + * ----------------------------------------------------------------------------- */ + +/* Flags for new pointer objects */ +#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) +#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) + +#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* How to access Py_None */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# ifndef SWIG_PYTHON_NO_BUILD_NONE +# ifndef SWIG_PYTHON_BUILD_NONE +# define SWIG_PYTHON_BUILD_NONE +# endif +# endif +#endif + +#ifdef SWIG_PYTHON_BUILD_NONE +# ifdef Py_None +# undef Py_None +# define Py_None SWIG_Py_None() +# endif +SWIGRUNTIMEINLINE PyObject * +_SWIG_Py_None(void) +{ + PyObject *none = Py_BuildValue((char*)""); + Py_DECREF(none); + return none; +} +SWIGRUNTIME PyObject * +SWIG_Py_None(void) +{ + static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); + return none; +} +#endif + +/* The python void return value */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Py_Void(void) +{ + PyObject *none = Py_None; + Py_INCREF(none); + return none; +} + +/* PySwigClientData */ + +typedef struct { + PyObject *klass; + PyObject *newraw; + PyObject *newargs; + PyObject *destroy; + int delargs; + int implicitconv; +} PySwigClientData; + +SWIGRUNTIMEINLINE int +SWIG_Python_CheckImplicit(swig_type_info *ty) +{ + PySwigClientData *data = (PySwigClientData *)ty->clientdata; + return data ? data->implicitconv : 0; +} + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_ExceptionType(swig_type_info *desc) { + PySwigClientData *data = desc ? (PySwigClientData *) desc->clientdata : 0; + PyObject *klass = data ? data->klass : 0; + return (klass ? klass : PyExc_RuntimeError); +} + + +SWIGRUNTIME PySwigClientData * +PySwigClientData_New(PyObject* obj) +{ + if (!obj) { + return 0; + } else { + PySwigClientData *data = (PySwigClientData *)malloc(sizeof(PySwigClientData)); + /* the klass element */ + data->klass = obj; + Py_INCREF(data->klass); + /* the newraw method and newargs arguments used to create a new raw instance */ + if (PyClass_Check(obj)) { + data->newraw = 0; + data->newargs = obj; + Py_INCREF(obj); + } else { +#if (PY_VERSION_HEX < 0x02020000) + data->newraw = 0; +#else + data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); +#endif + if (data->newraw) { + Py_INCREF(data->newraw); + data->newargs = PyTuple_New(1); + PyTuple_SetItem(data->newargs, 0, obj); + } else { + data->newargs = obj; + } + Py_INCREF(data->newargs); + } + /* the destroy method, aka as the C++ delete method */ + data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); + if (PyErr_Occurred()) { + PyErr_Clear(); + data->destroy = 0; + } + if (data->destroy) { + int flags; + Py_INCREF(data->destroy); + flags = PyCFunction_GET_FLAGS(data->destroy); +#ifdef METH_O + data->delargs = !(flags & (METH_O)); +#else + data->delargs = 0; +#endif + } else { + data->delargs = 0; + } + data->implicitconv = 0; + return data; + } +} + +SWIGRUNTIME void +PySwigClientData_Del(PySwigClientData* data) +{ + Py_XDECREF(data->newraw); + Py_XDECREF(data->newargs); + Py_XDECREF(data->destroy); +} + +/* =============== PySwigObject =====================*/ + +typedef struct { + PyObject_HEAD + void *ptr; + swig_type_info *ty; + int own; + PyObject *next; +} PySwigObject; + +SWIGRUNTIME PyObject * +PySwigObject_long(PySwigObject *v) +{ + return PyLong_FromVoidPtr(v->ptr); +} + +SWIGRUNTIME PyObject * +PySwigObject_format(const char* fmt, PySwigObject *v) +{ + PyObject *res = NULL; + PyObject *args = PyTuple_New(1); + if (args) { + if (PyTuple_SetItem(args, 0, PySwigObject_long(v)) == 0) { + PyObject *ofmt = PyString_FromString(fmt); + if (ofmt) { + res = PyString_Format(ofmt,args); + Py_DECREF(ofmt); + } + Py_DECREF(args); + } + } + return res; +} + +SWIGRUNTIME PyObject * +PySwigObject_oct(PySwigObject *v) +{ + return PySwigObject_format("%o",v); +} + +SWIGRUNTIME PyObject * +PySwigObject_hex(PySwigObject *v) +{ + return PySwigObject_format("%x",v); +} + +SWIGRUNTIME PyObject * +#ifdef METH_NOARGS +PySwigObject_repr(PySwigObject *v) +#else +PySwigObject_repr(PySwigObject *v, PyObject *args) +#endif +{ + const char *name = SWIG_TypePrettyName(v->ty); + PyObject *hex = PySwigObject_hex(v); + PyObject *repr = PyString_FromFormat("", name, PyString_AsString(hex)); + Py_DECREF(hex); + if (v->next) { +#ifdef METH_NOARGS + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next); +#else + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next, args); +#endif + PyString_ConcatAndDel(&repr,nrep); + } + return repr; +} + +SWIGRUNTIME int +PySwigObject_print(PySwigObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ +#ifdef METH_NOARGS + PyObject *repr = PySwigObject_repr(v); +#else + PyObject *repr = PySwigObject_repr(v, NULL); +#endif + if (repr) { + fputs(PyString_AsString(repr), fp); + Py_DECREF(repr); + return 0; + } else { + return 1; + } +} + +SWIGRUNTIME PyObject * +PySwigObject_str(PySwigObject *v) +{ + char result[SWIG_BUFFER_SIZE]; + return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ? + PyString_FromString(result) : 0; +} + +SWIGRUNTIME int +PySwigObject_compare(PySwigObject *v, PySwigObject *w) +{ + void *i = v->ptr; + void *j = w->ptr; + return (i < j) ? -1 : ((i > j) ? 1 : 0); +} + +SWIGRUNTIME PyTypeObject* _PySwigObject_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigObject_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigObject_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigObject_Check(PyObject *op) { + return ((op)->ob_type == PySwigObject_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigObject") == 0); +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own); + +SWIGRUNTIME void +PySwigObject_dealloc(PyObject *v) +{ + PySwigObject *sobj = (PySwigObject *) v; + PyObject *next = sobj->next; + if (sobj->own == SWIG_POINTER_OWN) { + swig_type_info *ty = sobj->ty; + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + PyObject *destroy = data ? data->destroy : 0; + if (destroy) { + /* destroy is always a VARARGS method */ + PyObject *res; + if (data->delargs) { + /* we need to create a temporal object to carry the destroy operation */ + PyObject *tmp = PySwigObject_New(sobj->ptr, ty, 0); + res = SWIG_Python_CallFunctor(destroy, tmp); + Py_DECREF(tmp); + } else { + PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); + PyObject *mself = PyCFunction_GET_SELF(destroy); + res = ((*meth)(mself, v)); + } + Py_XDECREF(res); + } +#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) + else { + const char *name = SWIG_TypePrettyName(ty); + printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); + } +#endif + } + Py_XDECREF(next); + PyObject_DEL(v); +} + +SWIGRUNTIME PyObject* +PySwigObject_append(PyObject* v, PyObject* next) +{ + PySwigObject *sobj = (PySwigObject *) v; +#ifndef METH_O + PyObject *tmp = 0; + if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; + next = tmp; +#endif + if (!PySwigObject_Check(next)) { + return NULL; + } + sobj->next = next; + Py_INCREF(next); + return SWIG_Py_Void(); +} + +SWIGRUNTIME PyObject* +#ifdef METH_NOARGS +PySwigObject_next(PyObject* v) +#else +PySwigObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *) v; + if (sobj->next) { + Py_INCREF(sobj->next); + return sobj->next; + } else { + return SWIG_Py_Void(); + } +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_disown(PyObject *v) +#else +PySwigObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = 0; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_acquire(PyObject *v) +#else +PySwigObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = SWIG_POINTER_OWN; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +PySwigObject_own(PyObject *v, PyObject *args) +{ + PyObject *val = 0; +#if (PY_VERSION_HEX < 0x02020000) + if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) +#else + if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) +#endif + { + return NULL; + } + else + { + PySwigObject *sobj = (PySwigObject *)v; + PyObject *obj = PyBool_FromLong(sobj->own); + if (val) { +#ifdef METH_NOARGS + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v); + } else { + PySwigObject_disown(v); + } +#else + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v,args); + } else { + PySwigObject_disown(v,args); + } +#endif + } + return obj; + } +} + +#ifdef METH_O +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_NOARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_O, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_NOARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#else +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_VARARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_VARARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#endif + +#if PY_VERSION_HEX < 0x02020000 +SWIGINTERN PyObject * +PySwigObject_getattr(PySwigObject *sobj,char *name) +{ + return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); +} +#endif + +SWIGRUNTIME PyTypeObject* +_PySwigObject_type(void) { + static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; + + static PyNumberMethods PySwigObject_as_number = { + (binaryfunc)0, /*nb_add*/ + (binaryfunc)0, /*nb_subtract*/ + (binaryfunc)0, /*nb_multiply*/ + (binaryfunc)0, /*nb_divide*/ + (binaryfunc)0, /*nb_remainder*/ + (binaryfunc)0, /*nb_divmod*/ + (ternaryfunc)0,/*nb_power*/ + (unaryfunc)0, /*nb_negative*/ + (unaryfunc)0, /*nb_positive*/ + (unaryfunc)0, /*nb_absolute*/ + (inquiry)0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + (coercion)0, /*nb_coerce*/ + (unaryfunc)PySwigObject_long, /*nb_int*/ + (unaryfunc)PySwigObject_long, /*nb_long*/ + (unaryfunc)0, /*nb_float*/ + (unaryfunc)PySwigObject_oct, /*nb_oct*/ + (unaryfunc)PySwigObject_hex, /*nb_hex*/ +#if PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ +#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ +#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ + 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ +#endif + }; + + static PyTypeObject pyswigobject_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigObject", /* tp_name */ + sizeof(PySwigObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigObject_dealloc, /* tp_dealloc */ + (printfunc)PySwigObject_print, /* tp_print */ +#if PY_VERSION_HEX < 0x02020000 + (getattrfunc)PySwigObject_getattr, /* tp_getattr */ +#else + (getattrfunc)0, /* tp_getattr */ +#endif + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigObject_compare, /* tp_compare */ + (reprfunc)PySwigObject_repr, /* tp_repr */ + &PySwigObject_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigObject_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigobject_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + swigobject_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigobject_type = tmp; + pyswigobject_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigobject_type; +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own) +{ + PySwigObject *sobj = PyObject_NEW(PySwigObject, PySwigObject_type()); + if (sobj) { + sobj->ptr = ptr; + sobj->ty = ty; + sobj->own = own; + sobj->next = 0; + } + return (PyObject *)sobj; +} + +/* ----------------------------------------------------------------------------- + * Implements a simple Swig Packed type, and use it instead of string + * ----------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + void *pack; + swig_type_info *ty; + size_t size; +} PySwigPacked; + +SWIGRUNTIME int +PySwigPacked_print(PySwigPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char result[SWIG_BUFFER_SIZE]; + fputs("pack, v->size, 0, sizeof(result))) { + fputs("at ", fp); + fputs(result, fp); + } + fputs(v->ty->name,fp); + fputs(">", fp); + return 0; +} + +SWIGRUNTIME PyObject * +PySwigPacked_repr(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + return PyString_FromFormat("", result, v->ty->name); + } else { + return PyString_FromFormat("", v->ty->name); + } +} + +SWIGRUNTIME PyObject * +PySwigPacked_str(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ + return PyString_FromFormat("%s%s", result, v->ty->name); + } else { + return PyString_FromString(v->ty->name); + } +} + +SWIGRUNTIME int +PySwigPacked_compare(PySwigPacked *v, PySwigPacked *w) +{ + size_t i = v->size; + size_t j = w->size; + int s = (i < j) ? -1 : ((i > j) ? 1 : 0); + return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); +} + +SWIGRUNTIME PyTypeObject* _PySwigPacked_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigPacked_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigPacked_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigPacked_Check(PyObject *op) { + return ((op)->ob_type == _PySwigPacked_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigPacked") == 0); +} + +SWIGRUNTIME void +PySwigPacked_dealloc(PyObject *v) +{ + if (PySwigPacked_Check(v)) { + PySwigPacked *sobj = (PySwigPacked *) v; + free(sobj->pack); + } + PyObject_DEL(v); +} + +SWIGRUNTIME PyTypeObject* +_PySwigPacked_type(void) { + static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; + static PyTypeObject pyswigpacked_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigPacked", /* tp_name */ + sizeof(PySwigPacked), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigPacked_dealloc, /* tp_dealloc */ + (printfunc)PySwigPacked_print, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigPacked_compare, /* tp_compare */ + (reprfunc)PySwigPacked_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigPacked_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigpacked_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigpacked_type = tmp; + pyswigpacked_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigpacked_type; +} + +SWIGRUNTIME PyObject * +PySwigPacked_New(void *ptr, size_t size, swig_type_info *ty) +{ + PySwigPacked *sobj = PyObject_NEW(PySwigPacked, PySwigPacked_type()); + if (sobj) { + void *pack = malloc(size); + if (pack) { + memcpy(pack, ptr, size); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = size; + } else { + PyObject_DEL((PyObject *) sobj); + sobj = 0; + } + } + return (PyObject *) sobj; +} + +SWIGRUNTIME swig_type_info * +PySwigPacked_UnpackData(PyObject *obj, void *ptr, size_t size) +{ + if (PySwigPacked_Check(obj)) { + PySwigPacked *sobj = (PySwigPacked *)obj; + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIMEINLINE PyObject * +_SWIG_This(void) +{ + return PyString_FromString("this"); +} + +SWIGRUNTIME PyObject * +SWIG_This(void) +{ + static PyObject *SWIG_STATIC_POINTER(swig_this) = _SWIG_This(); + return swig_this; +} + +/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ + +SWIGRUNTIME PySwigObject * +SWIG_Python_GetSwigThis(PyObject *pyobj) +{ + if (PySwigObject_Check(pyobj)) { + return (PySwigObject *) pyobj; + } else { + PyObject *obj = 0; +#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) + if (PyInstance_Check(pyobj)) { + obj = _PyInstance_Lookup(pyobj, SWIG_This()); + } else { + PyObject **dictptr = _PyObject_GetDictPtr(pyobj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; + } else { +#ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); + return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; + } +#endif + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } + } + } +#else + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } +#endif + if (obj && !PySwigObject_Check(obj)) { + /* a PyObject is called 'this', try to get the 'real this' + PySwigObject from it */ + return SWIG_Python_GetSwigThis(obj); + } + return (PySwigObject *)obj; + } +} + +/* Acquire a pointer value */ + +SWIGRUNTIME int +SWIG_Python_AcquirePtr(PyObject *obj, int own) { + if (own == SWIG_POINTER_OWN) { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (sobj) { + int oldown = sobj->own; + sobj->own = own; + return oldown; + } + } + return 0; +} + +/* Convert a pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { + if (!obj) return SWIG_ERROR; + if (obj == Py_None) { + if (ptr) *ptr = 0; + return SWIG_OK; + } else { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (own) + *own = 0; + while (sobj) { + void *vptr = sobj->ptr; + if (ty) { + swig_type_info *to = sobj->ty; + if (to == ty) { + /* no type cast needed */ + if (ptr) *ptr = vptr; + break; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) { + sobj = (PySwigObject *)sobj->next; + } else { + if (ptr) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + } + break; + } + } + } else { + if (ptr) *ptr = vptr; + break; + } + } + if (sobj) { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + return SWIG_OK; + } else { + int res = SWIG_ERROR; + if (flags & SWIG_POINTER_IMPLICIT_CONV) { + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + if (data && !data->implicitconv) { + PyObject *klass = data->klass; + if (klass) { + PyObject *impconv; + data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ + impconv = SWIG_Python_CallFunctor(klass, obj); + data->implicitconv = 0; + if (PyErr_Occurred()) { + PyErr_Clear(); + impconv = 0; + } + if (impconv) { + PySwigObject *iobj = SWIG_Python_GetSwigThis(impconv); + if (iobj) { + void *vptr; + res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); + if (SWIG_IsOK(res)) { + if (ptr) { + *ptr = vptr; + /* transfer the ownership to 'ptr' */ + iobj->own = 0; + res = SWIG_AddCast(res); + res = SWIG_AddNewMask(res); + } else { + res = SWIG_AddCast(res); + } + } + } + Py_DECREF(impconv); + } + } + } + } + return res; + } + } +} + +/* Convert a function ptr value */ + +SWIGRUNTIME int +SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { + if (!PyCFunction_Check(obj)) { + return SWIG_ConvertPtr(obj, ptr, ty, 0); + } else { + void *vptr = 0; + + /* here we get the method pointer for callbacks */ + const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); + const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; + if (desc) { + desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; + if (!desc) return SWIG_ERROR; + } + if (ty) { + swig_cast_info *tc = SWIG_TypeCheck(desc,ty); + if (tc) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } else { + return SWIG_ERROR; + } + } else { + *ptr = vptr; + } + return SWIG_OK; + } +} + +/* Convert a packed value value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = PySwigPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Create a new pointer object + * ----------------------------------------------------------------------------- */ + +/* + Create a new instance object, whitout calling __init__, and set the + 'this' attribute. +*/ + +SWIGRUNTIME PyObject* +SWIG_Python_NewShadowInstance(PySwigClientData *data, PyObject *swig_this) +{ +#if (PY_VERSION_HEX >= 0x02020000) + PyObject *inst = 0; + PyObject *newraw = data->newraw; + if (newraw) { + inst = PyObject_Call(newraw, data->newargs, NULL); + if (inst) { +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + PyDict_SetItem(dict, SWIG_This(), swig_this); + } + } +#else + PyObject *key = SWIG_This(); + PyObject_SetAttr(inst, key, swig_this); +#endif + } + } else { + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + } + return inst; +#else +#if (PY_VERSION_HEX >= 0x02010000) + PyObject *inst; + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + return (PyObject *) inst; +#else + PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); + if (inst == NULL) { + return NULL; + } + inst->in_class = (PyClassObject *)data->newargs; + Py_INCREF(inst->in_class); + inst->in_dict = PyDict_New(); + if (inst->in_dict == NULL) { + Py_DECREF(inst); + return NULL; + } +#ifdef Py_TPFLAGS_HAVE_WEAKREFS + inst->in_weakreflist = NULL; +#endif +#ifdef Py_TPFLAGS_GC + PyObject_GC_Init(inst); +#endif + PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); + return (PyObject *) inst; +#endif +#endif +} + +SWIGRUNTIME void +SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) +{ + PyObject *dict; +#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + } + PyDict_SetItem(dict, SWIG_This(), swig_this); + return; + } +#endif + dict = PyObject_GetAttrString(inst, (char*)"__dict__"); + PyDict_SetItem(dict, SWIG_This(), swig_this); + Py_DECREF(dict); +} + + +SWIGINTERN PyObject * +SWIG_Python_InitShadowInstance(PyObject *args) { + PyObject *obj[2]; + if (!SWIG_Python_UnpackTuple(args,(char*)"swiginit", 2, 2, obj)) { + return NULL; + } else { + PySwigObject *sthis = SWIG_Python_GetSwigThis(obj[0]); + if (sthis) { + PySwigObject_append((PyObject*) sthis, obj[1]); + } else { + SWIG_Python_SetSwigThis(obj[0], obj[1]); + } + return SWIG_Py_Void(); + } +} + +/* Create a new pointer object */ + +SWIGRUNTIME PyObject * +SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int flags) { + if (!ptr) { + return SWIG_Py_Void(); + } else { + int own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; + PyObject *robj = PySwigObject_New(ptr, type, own); + PySwigClientData *clientdata = type ? (PySwigClientData *)(type->clientdata) : 0; + if (clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { + PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); + if (inst) { + Py_DECREF(robj); + robj = inst; + } + } + return robj; + } +} + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? PySwigPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_LINK_RUNTIME +void *SWIG_ReturnGlobalTypeList(void *); +#endif + +SWIGRUNTIME swig_module_info * +SWIG_Python_GetModule(void) { + static void *type_pointer = (void *)0; + /* first check if module already created */ + if (!type_pointer) { +#ifdef SWIG_LINK_RUNTIME + type_pointer = SWIG_ReturnGlobalTypeList((void *)0); +#else + type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); + if (PyErr_Occurred()) { + PyErr_Clear(); + type_pointer = (void *)0; + } +#endif + } + return (swig_module_info *) type_pointer; +} + +#if PY_MAJOR_VERSION < 2 +/* PyModule_AddObject function was introduced in Python 2.0. The following function + is copied out of Python/modsupport.c in python version 2.3.4 */ +SWIGINTERN int +PyModule_AddObject(PyObject *m, char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs module as first arg"); + return SWIG_ERROR; + } + if (!o) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs non-NULL value"); + return SWIG_ERROR; + } + + dict = PyModule_GetDict(m); + if (dict == NULL) { + /* Internal error -- modules must have a dict! */ + PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", + PyModule_GetName(m)); + return SWIG_ERROR; + } + if (PyDict_SetItemString(dict, name, o)) + return SWIG_ERROR; + Py_DECREF(o); + return SWIG_OK; +} +#endif + +SWIGRUNTIME void +SWIG_Python_DestroyModule(void *vptr) +{ + swig_module_info *swig_module = (swig_module_info *) vptr; + swig_type_info **types = swig_module->types; + size_t i; + for (i =0; i < swig_module->size; ++i) { + swig_type_info *ty = types[i]; + if (ty->owndata) { + PySwigClientData *data = (PySwigClientData *) ty->clientdata; + if (data) PySwigClientData_Del(data); + } + } + Py_DECREF(SWIG_This()); +} + +SWIGRUNTIME void +SWIG_Python_SetModule(swig_module_info *swig_module) { + static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} };/* Sentinel */ + + PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + swig_empty_runtime_method_table); + PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +} + +/* The python cached type query */ +SWIGRUNTIME PyObject * +SWIG_Python_TypeCache(void) { + static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); + return cache; +} + +SWIGRUNTIME swig_type_info * +SWIG_Python_TypeQuery(const char *type) +{ + PyObject *cache = SWIG_Python_TypeCache(); + PyObject *key = PyString_FromString(type); + PyObject *obj = PyDict_GetItem(cache, key); + swig_type_info *descriptor; + if (obj) { + descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); + } else { + swig_module_info *swig_module = SWIG_Python_GetModule(); + descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); + if (descriptor) { + obj = PyCObject_FromVoidPtr(descriptor, NULL); + PyDict_SetItem(cache, key, obj); + Py_DECREF(obj); + } + } + Py_DECREF(key); + return descriptor; +} + +/* + For backward compatibility only +*/ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) +#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) + +SWIGRUNTIME int +SWIG_Python_AddErrMesg(const char* mesg, int infront) +{ + if (PyErr_Occurred()) { + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + Py_XINCREF(type); + PyErr_Clear(); + if (infront) { + PyErr_Format(type, "%s %s", mesg, PyString_AsString(old_str)); + } else { + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + } + Py_DECREF(old_str); + } + return 1; + } else { + return 0; + } +} + +SWIGRUNTIME int +SWIG_Python_ArgFail(int argnum) +{ + if (PyErr_Occurred()) { + /* add information about failing argument */ + char mesg[256]; + PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); + return SWIG_Python_AddErrMesg(mesg, 1); + } else { + return 0; + } +} + +SWIGRUNTIMEINLINE const char * +PySwigObject_GetDesc(PyObject *self) +{ + PySwigObject *v = (PySwigObject *)self; + swig_type_info *ty = v ? v->ty : 0; + return ty ? ty->str : (char*)""; +} + +SWIGRUNTIME void +SWIG_Python_TypeError(const char *type, PyObject *obj) +{ + if (type) { +#if defined(SWIG_COBJECT_TYPES) + if (obj && PySwigObject_Check(obj)) { + const char *otype = (const char *) PySwigObject_GetDesc(obj); + if (otype) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'PySwigObject(%s)' is received", + type, otype); + return; + } + } else +#endif + { + const char *otype = (obj ? obj->ob_type->tp_name : 0); + if (otype) { + PyObject *str = PyObject_Str(obj); + const char *cstr = str ? PyString_AsString(str) : 0; + if (cstr) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", + type, otype, cstr); + } else { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", + type, otype); + } + Py_XDECREF(str); + return; + } + } + PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); + } else { + PyErr_Format(PyExc_TypeError, "unexpected type is received"); + } +} + + +/* Convert a pointer value, signal an exception on a type mismatch */ +SWIGRUNTIME void * +SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) { + void *result; + if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { + PyErr_Clear(); + if (flags & SWIG_POINTER_EXCEPTION) { + SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); + SWIG_Python_ArgFail(argnum); + } + } + return result; +} + + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_TALLOC_CTX swig_types[0] +#define SWIGTYPE_p_char swig_types[1] +#define SWIGTYPE_p_event_context swig_types[2] +#define SWIGTYPE_p_p_char swig_types[3] +static swig_type_info *swig_types[5]; +static swig_module_info swig_module = {swig_types, 4, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#if (PY_VERSION_HEX <= 0x02000000) +# if !defined(SWIG_PYTHON_CLASSIC) +# error "This python version requires swig to be run with the '-classic' option" +# endif +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodern' option" +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodernargs' option" +#endif +#ifndef METH_O +# error "This python version requires swig to be run with the '-nofastunpack' option" +#endif +#ifdef SWIG_TypeQuery +# undef SWIG_TypeQuery +#endif +#define SWIG_TypeQuery SWIG_Python_TypeQuery + +/*----------------------------------------------- + @(target):= _events.so + ------------------------------------------------*/ +#define SWIG_init init_events + +#define SWIG_name "_events" + +#define SWIGVERSION 0x010335 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "events.h" +typedef struct event_context event; + +SWIGINTERN event *new_event(TALLOC_CTX *mem_ctx){ return event_context_init(mem_ctx); } + + #define SWIG_From_long PyInt_FromLong + + +SWIGINTERNINLINE PyObject * +SWIG_From_int (int value) +{ + return SWIG_From_long (value); +} + +SWIGINTERN void delete_event(event *self){ talloc_free(self); } + +SWIGINTERN swig_type_info* +SWIG_pchar_descriptor(void) +{ + static int init = 0; + static swig_type_info* info = 0; + if (!init) { + info = SWIG_TypeQuery("_p_char"); + init = 1; + } + return info; +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) +{ + if (PyString_Check(obj)) { + char *cstr; Py_ssize_t len; + PyString_AsStringAndSize(obj, &cstr, &len); + if (cptr) { + if (alloc) { + /* + In python the user should not be able to modify the inner + string representation. To warranty that, if you define + SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string + buffer is always returned. + + The default behavior is just to return the pointer value, + so, be careful. + */ +#if defined(SWIG_PYTHON_SAFE_CSTRINGS) + if (*alloc != SWIG_OLDOBJ) +#else + if (*alloc == SWIG_NEWOBJ) +#endif + { + *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + *cptr = PyString_AsString(obj); + } + } + if (psize) *psize = len + 1; + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + void* vptr = 0; + if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = (char *) vptr; + if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + +#ifdef __cplusplus +extern "C" { +#endif +SWIGINTERN PyObject *_wrap_new_event(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + event *result = 0 ; + + arg1 = NULL; + if (!SWIG_Python_UnpackTuple(args,"new_event",0,0,0)) SWIG_fail; + result = (event *)new_event(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_event_context, SWIG_POINTER_NEW | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_event_loop_once(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + event *arg1 = (event *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_event_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "event_loop_once" "', argument " "1"" of type '" "event *""'"); + } + arg1 = (event *)(argp1); + result = (int)event_loop_once(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_event_loop_wait(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + event *arg1 = (event *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_event_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "event_loop_wait" "', argument " "1"" of type '" "event *""'"); + } + arg1 = (event *)(argp1); + result = (int)event_loop_wait(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_delete_event(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + event *arg1 = (event *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_event_context, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_event" "', argument " "1"" of type '" "event *""'"); + } + arg1 = (event *)(argp1); + delete_event(arg1); + + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *event_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_event_context, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject *event_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + return SWIG_Python_InitShadowInstance(args); +} + +SWIGINTERN PyObject *_wrap_event_context_init_byname(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + char *arg2 = (char *) 0 ; + struct event_context *result = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "name", NULL + }; + + arg1 = NULL; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:event_context_init_byname",kwnames,&obj0)) SWIG_fail; + res2 = SWIG_AsCharPtrAndSize(obj0, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "event_context_init_byname" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = (struct event_context *)event_context_init_byname(arg1,(char const *)arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_event_context, 0 | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_event_backend_list(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + char **result = 0 ; + + arg1 = NULL; + if (!SWIG_Python_UnpackTuple(args,"event_backend_list",0,0,0)) SWIG_fail; + result = (char **)event_backend_list(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_p_char, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_set_default_backend(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "backend", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:set_default_backend",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "set_default_backend" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + event_set_default_backend((char const *)arg1); + resultobj = SWIG_Py_Void(); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +static PyMethodDef SwigMethods[] = { + { (char *)"new_event", (PyCFunction)_wrap_new_event, METH_NOARGS, (char *)"S.__init__()"}, + { (char *)"event_loop_once", (PyCFunction)_wrap_event_loop_once, METH_O, (char *)"S.loop_once() -> int"}, + { (char *)"event_loop_wait", (PyCFunction)_wrap_event_loop_wait, METH_O, (char *)"S.loop_wait() -> int"}, + { (char *)"delete_event", (PyCFunction)_wrap_delete_event, METH_O, NULL}, + { (char *)"event_swigregister", event_swigregister, METH_VARARGS, NULL}, + { (char *)"event_swiginit", event_swiginit, METH_VARARGS, NULL}, + { (char *)"event_context_init_byname", (PyCFunction) _wrap_event_context_init_byname, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"event_backend_list", (PyCFunction)_wrap_event_backend_list, METH_NOARGS, (char *)"event_backend_list() -> list"}, + { (char *)"set_default_backend", (PyCFunction) _wrap_set_default_backend, METH_VARARGS | METH_KEYWORDS, (char *)"event_set_default_backend(name) -> None"}, + { NULL, NULL, 0, NULL } +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_TALLOC_CTX = {"_p_TALLOC_CTX", "TALLOC_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_event_context = {"_p_event_context", "struct event_context *|event *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_TALLOC_CTX, + &_swigt__p_char, + &_swigt__p_event_context, + &_swigt__p_p_char, +}; + +static swig_cast_info _swigc__p_TALLOC_CTX[] = { {&_swigt__p_TALLOC_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_event_context[] = { {&_swigt__p_event_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_char[] = { {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_TALLOC_CTX, + _swigc__p_char, + _swigc__p_event_context, + _swigc__p_p_char, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_const_info swig_const_table[] = { +{0, 0, 0, 0.0, 0, 0}}; + +#ifdef __cplusplus +} +#endif +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found, init; + + clientdata = clientdata; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + init = 1; + } else { + init = 0; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* When multiple interpeters are used, a module could have already been initialized in + a different interpreter, but not yet have a pointer in this interpreter. + In this case, we do not want to continue adding types... everything should be + set up already */ + if (init == 0) return; + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + /* Python-specific SWIG API */ +#define SWIG_newvarlink() SWIG_Python_newvarlink() +#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) +#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) + + /* ----------------------------------------------------------------------------- + * global variable support code. + * ----------------------------------------------------------------------------- */ + + typedef struct swig_globalvar { + char *name; /* Name of global variable */ + PyObject *(*get_attr)(void); /* Return the current value */ + int (*set_attr)(PyObject *); /* Set the value */ + struct swig_globalvar *next; + } swig_globalvar; + + typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar *vars; + } swig_varlinkobject; + + SWIGINTERN PyObject * + swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { + return PyString_FromString(""); + } + + SWIGINTERN PyObject * + swig_varlink_str(swig_varlinkobject *v) { + PyObject *str = PyString_FromString("("); + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + PyString_ConcatAndDel(&str,PyString_FromString(var->name)); + if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); + } + PyString_ConcatAndDel(&str,PyString_FromString(")")); + return str; + } + + SWIGINTERN int + swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + PyObject *str = swig_varlink_str(v); + fprintf(fp,"Swig global variables "); + fprintf(fp,"%s\n", PyString_AsString(str)); + Py_DECREF(str); + return 0; + } + + SWIGINTERN void + swig_varlink_dealloc(swig_varlinkobject *v) { + swig_globalvar *var = v->vars; + while (var) { + swig_globalvar *n = var->next; + free(var->name); + free(var); + var = n; + } + } + + SWIGINTERN PyObject * + swig_varlink_getattr(swig_varlinkobject *v, char *n) { + PyObject *res = NULL; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->get_attr)(); + break; + } + var = var->next; + } + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN int + swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { + int res = 1; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->set_attr)(p); + break; + } + var = var->next; + } + if (res == 1 && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN PyTypeObject* + swig_varlink_type(void) { + static char varlink__doc__[] = "Swig var link object"; + static PyTypeObject varlink_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* Number of items in variable part (ob_size) */ + (char *)"swigvarlink", /* Type name (tp_name) */ + sizeof(swig_varlinkobject), /* Basic size (tp_basicsize) */ + 0, /* Itemsize (tp_itemsize) */ + (destructor) swig_varlink_dealloc, /* Deallocator (tp_dealloc) */ + (printfunc) swig_varlink_print, /* Print (tp_print) */ + (getattrfunc) swig_varlink_getattr, /* get attr (tp_getattr) */ + (setattrfunc) swig_varlink_setattr, /* Set attr (tp_setattr) */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)swig_varlink_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + varlink__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + varlink_type = tmp; + varlink_type.ob_type = &PyType_Type; + type_init = 1; + } + return &varlink_type; + } + + /* Create a variable linking object for use later */ + SWIGINTERN PyObject * + SWIG_Python_newvarlink(void) { + swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); + if (result) { + result->vars = 0; + } + return ((PyObject*) result); + } + + SWIGINTERN void + SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { + swig_varlinkobject *v = (swig_varlinkobject *) p; + swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + if (gv) { + size_t size = strlen(name)+1; + gv->name = (char *)malloc(size); + if (gv->name) { + strncpy(gv->name,name,size); + gv->get_attr = get_attr; + gv->set_attr = set_attr; + gv->next = v->vars; + } + } + v->vars = gv; + } + + SWIGINTERN PyObject * + SWIG_globals(void) { + static PyObject *_SWIG_globals = 0; + if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); + return _SWIG_globals; + } + + /* ----------------------------------------------------------------------------- + * constants/methods manipulation + * ----------------------------------------------------------------------------- */ + + /* Install Constants */ + SWIGINTERN void + SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { + PyObject *obj = 0; + size_t i; + for (i = 0; constants[i].type; ++i) { + switch(constants[i].type) { + case SWIG_PY_POINTER: + obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); + break; + case SWIG_PY_BINARY: + obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); + break; + default: + obj = 0; + break; + } + if (obj) { + PyDict_SetItemString(d, constants[i].name, obj); + Py_DECREF(obj); + } + } + } + + /* -----------------------------------------------------------------------------*/ + /* Fix SwigMethods to carry the callback ptrs when needed */ + /* -----------------------------------------------------------------------------*/ + + SWIGINTERN void + SWIG_Python_FixMethods(PyMethodDef *methods, + swig_const_info *const_table, + swig_type_info **types, + swig_type_info **types_initial) { + size_t i; + for (i = 0; methods[i].ml_name; ++i) { + const char *c = methods[i].ml_doc; + if (c && (c = strstr(c, "swig_ptr: "))) { + int j; + swig_const_info *ci = 0; + const char *name = c + 10; + for (j = 0; const_table[j].type; ++j) { + if (strncmp(const_table[j].name, name, + strlen(const_table[j].name)) == 0) { + ci = &(const_table[j]); + break; + } + } + if (ci) { + size_t shift = (ci->ptype) - types; + swig_type_info *ty = types_initial[shift]; + size_t ldoc = (c - methods[i].ml_doc); + size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; + char *ndoc = (char*)malloc(ldoc + lptr + 10); + if (ndoc) { + char *buff = ndoc; + void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; + if (ptr) { + strncpy(buff, methods[i].ml_doc, ldoc); + buff += ldoc; + strncpy(buff, "swig_ptr: ", 10); + buff += 10; + SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); + methods[i].ml_doc = ndoc; + } + } + } + } + } + } + +#ifdef __cplusplus +} +#endif + +/* -----------------------------------------------------------------------------* + * Partial Init method + * -----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" +#endif +SWIGEXPORT void SWIG_init(void) { + PyObject *m, *d; + + /* Fix SwigMethods to carry the callback ptrs when needed */ + SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); + + m = Py_InitModule((char *) SWIG_name, SwigMethods); + d = PyModule_GetDict(m); + + SWIG_InitializeModule(0); + SWIG_InstallConstants(d,swig_const_table); + + +} + diff --git a/events/install-sh b/events/install-sh new file mode 100755 index 000000000..58719246f --- /dev/null +++ b/events/install-sh @@ -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 diff --git a/events/libevents.m4 b/events/libevents.m4 new file mode 100644 index 000000000..d17da64b3 --- /dev/null +++ b/events/libevents.m4 @@ -0,0 +1,49 @@ +dnl find the events sources. This is meant to work both for +dnl standalone builds, and builds of packages using libevents +if test x"$eventsdir" = "x"; then + eventsdir="" + eventspaths="$srcdir $srcdir/../samba4/source/lib/events $srcdir/lib/events $srcdir/events $srcdir/../events" + for d in $eventspaths; do + if test -f "$d/events.c"; then + eventsdir="$d" + AC_SUBST(eventsdir) + break; + fi + done + if test x"$eventsdir" = "x"; then + AC_MSG_ERROR([cannot find libevents source in $eventspaths]) + fi +fi + +EVENTS_OBJ="events.o events_select.o events_signal.o events_timed.o events_standard.o events_debug.o events_util.o" +AC_LIBREPLACE_NETWORK_CHECKS + +SMB_ENABLE(EVENTS_EPOLL, NO) +SMB_ENABLE(EVENTS_AIO, NO) +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 + EVENTS_OBJ="$EVENTS_OBJ events_epoll.o" + SMB_ENABLE(EVENTS_EPOLL,YES) + AC_DEFINE(HAVE_EVENTS_EPOLL, 1, [Whether epoll available]) + + # check for native Linux AIO interface + AC_CHECK_HEADERS(libaio.h) + AC_CHECK_LIB_EXT(aio, AIO_LIBS, io_getevents) + if test x"$ac_cv_header_libaio_h" = x"yes" -a x"$ac_cv_lib_ext_aio_io_getevents" = x"yes";then + EVENTS_OBJ="$EVENTS_OBJ events_aio.o" + SMB_ENABLE(EVENTS_AIO,YES) + AC_DEFINE(HAVE_LINUX_AIO, 1, [Whether Linux AIO is available]) + fi +fi + +AC_SUBST(EVENTS_OBJ) +SMB_EXT_LIB(LIBAIO_LINUX, $AIO_LIBS) + +EVENTS_CFLAGS="-I$eventsdir" +AC_SUBST(EVENTS_CFLAGS) + +EVENTS_LIBS="" +AC_SUBST(EVENTS_LIBS) + + diff --git a/events/libtalloc.m4 b/events/libtalloc.m4 new file mode 100644 index 000000000..a4c5b8a9d --- /dev/null +++ b/events/libtalloc.m4 @@ -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)]) diff --git a/events/pkg.m4 b/events/pkg.m4 new file mode 100644 index 000000000..a8b3d06c8 --- /dev/null +++ b/events/pkg.m4 @@ -0,0 +1,156 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant . +# +# 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 . +# +# 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 .])], + [$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 diff --git a/events/rules.mk b/events/rules.mk new file mode 100644 index 000000000..cfe548039 --- /dev/null +++ b/events/rules.mk @@ -0,0 +1,21 @@ +.SUFFIXES: .i _wrap.c + +.i_wrap.c: + $(SWIG) -O -Wall -python -keyword $< + +showflags:: + @echo 'libevents 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) -c $< -o $@ + +distclean:: + rm -f *~ */*~ diff --git a/events/tests.py b/events/tests.py new file mode 100644 index 000000000..006426207 --- /dev/null +++ b/events/tests.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 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 . +# + +from samba import events +import unittest + +# Just test the bindings are there and that calling them doesn't crash +# anything. + +class EventTestCase(unittest.TestCase): + def test_create(self): + self.assertTrue(events.event() is not None) + + def test_loop_wait(self): + self.assertEquals(0, events.event().loop_wait()) diff --git a/events/testsuite.c b/events/testsuite.c new file mode 100644 index 000000000..7f2729cef --- /dev/null +++ b/events/testsuite.c @@ -0,0 +1,145 @@ +/* + Unix SMB/CIFS implementation. + + testing of the events subsystem + + Copyright (C) Stefan Metzmacher + + 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 . +*/ + +#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 event_context *ev_ctx, struct fd_event *f, + uint16_t flags, void *private) +{ + int *fd = (int *)private; + 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 event_context *ev_ctx, struct timed_event *te, + struct timeval tval, void *private) +{ + int *finished = (int *)private; + (*finished) = 1; +} + +static void count_handler(struct event_context *ev_ctx, struct signal_event *te, + int signum, int count, void *info, void *private) +{ + int *countp = (int *)private; + (*countp) += count; +} + +static bool test_event_context(struct torture_context *test, + const void *test_data) +{ + struct event_context *ev_ctx; + int fd[2] = { -1, -1 }; + const char *backend = (const char *)test_data; + int alarm_count=0, info_count=0; + struct fd_event *fde; + struct signal_event *se1, *se2, *se3; + 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|EVENT_FD_AUTOCLOSE, + fde_handler, fd); + + event_add_timed(ev_ctx, ev_ctx, timeval_current_ofs(2,0), + finished_handler, &finished); + + se1 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count); + 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)); + + talloc_free(se1); + + 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; +} diff --git a/ldb/Doxyfile b/ldb/Doxyfile new file mode 100644 index 000000000..07b12b516 --- /dev/null +++ b/ldb/Doxyfile @@ -0,0 +1,26 @@ +PROJECT_NAME = LDB +OUTPUT_DIRECTORY = apidocs +REPEAT_BRIEF = YES +OPTIMIZE_OUTPUT_FOR_C = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +GENERATE_TODOLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +SHOW_USED_FILES = NO +SHOW_DIRECTORIES = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +INPUT = include . +FILE_PATTERNS = *.h *.dox +EXCLUDE = include/config.h include/dlinklist.h \ + include/includes.h +EXAMPLE_PATH = examples +GENERATE_HTML = YES +HTML_OUTPUT = html +GENERATE_MAN = YES +ALWAYS_DETAILED_SEC = YES +JAVADOC_AUTOBRIEF = YES diff --git a/ldb/Makefile.in b/ldb/Makefile.in new file mode 100644 index 000000000..c94c820a4 --- /dev/null +++ b/ldb/Makefile.in @@ -0,0 +1,183 @@ +#!gmake +# +CC = @CC@ +GCOV = @GCOV@ +XSLTPROC = @XSLTPROC@ +DOXYGEN = @DOXYGEN@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +includedir = @includedir@ +libdir = @libdir@ +bindir = @bindir@ +mandir = @mandir@ +VPATH = @srcdir@:@libreplacedir@ +srcdir = @srcdir@ +builddir = @builddir@ +buildinstdir = @buildinstdir@ +INSTALLCMD = @INSTALL@ +SLAPD = @SLAPD@ +SWIG = swig +EXTRA_OBJ=@EXTRA_OBJ@ +TESTS=test-tdb.sh @TESTS@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PYTHON = @PYTHON@ +PYTHON_CONFIG = @PYTHON_CONFIG@ +ldbdir = $(srcdir) + +TALLOC_LIBS = @TALLOC_LIBS@ +TALLOC_CFLAGS = @TALLOC_CFLAGS@ +TALLOC_OBJ = @TALLOC_OBJ@ + +TDB_LIBS = @TDB_LIBS@ +TDB_CFLAGS = @TDB_CFLAGS@ +TDB_OBJ = @TDB_OBJ@ + +EVENTS_LIBS = @EVENTS_LIBS@ +EVENTS_CFLAGS = @EVENTS_CFLAGS@ +EVENTS_OBJ = @EVENTS_OBJ@ + +POPT_LIBS = @POPT_LIBS@ +POPT_CFLAGS = @POPT_CFLAGS@ +POPT_OBJ = @POPT_OBJ@ + +LDAP_LIBS = @LDAP_LIBS@ + +LIBDL = @LIBDL@ + +SHLIBEXT = @SHLIBEXT@ + +LD_EXPORT_DYNAMIC = @LD_EXPORT_DYNAMIC@ +SHLD = @SHLD@ +SHLD_FLAGS = @SHLD_FLAGS@ + +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +PICFLAG = @PICFLAG@ +CFLAGS=-g -I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \ + $(POPT_CFLAGS) $(TALLOC_CFLAGS) $(TDB_CFLAGS) $(EVENTS_CFLAGS) \ + -DLIBDIR=\"$(libdir)\" -DSHLIBEXT=\"$(SHLIBEXT)\" -DUSE_MMAP=1 @CFLAGS@ + +MDLD = @MDLD@ +MDLD_FLAGS = @MDLD_FLAGS@ + +OBJS = $(MODULES_OBJ) $(COMMON_OBJ) $(LDB_TDB_OBJ) $(TDB_OBJ) $(EVENTS_OBJ) $(TALLOC_OBJ) $(POPT_OBJ) $(LDB_MAP_OBJ) @LIBREPLACEOBJ@ $(EXTRA_OBJ) + +headers = $(srcdir)/include/ldb.h $(srcdir)/include/ldb_errors.h $(srcdir)/include/ldb_handlers.h + +BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify bin/ldbedit bin/ldbrename bin/ldbtest + +EXAMPLES = examples/ldbreader examples/ldifreader + +DIRS = lib bin common ldb_tdb ldb_ldap ldb_sqlite3 modules tools examples + +default: all + +include $(ldbdir)/rules.mk + +nss: nssdir all $(NSS_LIB) + +nssdir: + @mkdir -p $(NSSDIR) + +SONAME = libldb.$(SHLIBEXT).0 +SOLIB = libldb.$(SHLIBEXT).$(PACKAGE_VERSION) +LIBSOLIB = lib/$(SOLIB) +STATICLIB = lib/libldb.a + +lib/$(SONAME): $(LIBSOLIB) + ln -fs libldb.$(SHLIBEXT).$(PACKAGE_VERSION) $@ + +lib/libldb.$(SHLIBEXT): $(LIBSOLIB) + ln -fs libldb.$(SHLIBEXT).$(PACKAGE_VERSION) $@ + +lib/libnss_ldb.$(SHLIBEXT).2: $(NSS_OBJ) $(LIBSOLIB) + $(SHLD) $(SHLD_FLAGS) -o $@ $(NSS_OBJ) $(LDFLAGS) $(LIBSOLIB) @SONAMEFLAG@libnss_ldb.$(SHLIBEXT).2 + +$(LIBSOLIB): $(OBJS) + $(SHLD) $(SHLD_FLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS) $(TALLOC_LIBS) $(TDB_LIBS) $(EVENTS_LIBS) $(LIBDL) $(LDAP_LIBS) @SONAMEFLAG@$(SONAME) + ln -sf libldb.$(SHLIBEXT).$(PACKAGE_VERSION) lib/libldb.$(SHLIBEXT) + +all: showflags dirs $(OBJS) $(STATICLIB) $(LIBSOLIB) $(BINS) $(EXAMPLES) manpages \ + @PYTHON_BUILD_TARGET@ + +build-install: all + ${INSTALLCMD} -d $(buildinstdir)/lib + ${INSTALLCMD} -m 755 $(STATICLIB) $(buildinstdir)/lib + ${INSTALLCMD} -m 755 $(LIBSOLIB) $(buildinstdir)/lib + ln -sf $(SOLIB) $(buildinstdir)/lib/$(SONAME) + ln -sf $(SOLIB) $(buildinstdir)/lib/libldb.so + ${INSTALLCMD} -d $(buildinstdir)/include + ${INSTALLCMD} -m 644 $(srcdir)/include/ldb.h $(buildinstdir)/include + ${INSTALLCMD} -m 644 $(srcdir)/include/ldb_errors.h $(buildinstdir)/include + ${INSTALLCMD} -m 644 $(srcdir)/include/ldb_handlers.h $(buildinstdir)/include + +dirs: + @mkdir -p $(DIRS) + +manpages:: + @$(srcdir)/docs/builddocs.sh "$(XSLTPROC)" "$(srcdir)" + +doxygen:: + test -z "$(DOXYGEN)" || (cd $(srcdir) && "$(DOXYGEN)") + +clean:: + rm -f *.o */*.o *.gcov */*.gc?? tdbtest.ldb* + rm -f $(BINS) $(TDB_OBJ) $(TALLOC_OBJ) $(STATICLIB) $(NSS_LIB) $(LIBSOLIB) + rm -f $(POPT_OBJ) + rm -f man/*.1 man/*.3 man/*.html + rm -f $(EXAMPLES) + rm -rf apidocs/ + rm -rf tests/schema/ + +distclean:: clean + rm -rf bin lib + rm -f config.log config.status config.cache include/config.h + rm -f ldb.pc + rm -f Makefile + +realdistclean:: distclean + rm -f configure include/config.h.in + +check:: test @PYTHON_CHECK_TARGET@ + +check-soloading: sample.$(SHLIBEXT) + LDB_MODULES_PATH=$(builddir) $(srcdir)/tests/test-soloading.sh + +test:: all check-soloading + for t in $(TESTS); do echo STARTING $${t}; $(srcdir)/tests/$${t} || exit 1; done + +valgrindtest:: all + for t in $(TESTS); do echo STARTING $${t}; VALGRIND="valgrind -q --db-attach=yes --num-callers=30" $(srcdir)/tests/$${t} || exit 1; done + +installcheck:: install test + +install:: all installdirs installheaders installlibs installbin installdocs \ + @PYTHON_INSTALL_TARGET@ + +installdirs:: + mkdir -p $(DESTDIR)$(includedir) $(DESTDIR)$(libdir) $(DESTDIR)$(bindir) $(DESTDIR)$(libdir)/pkgconfig + +installheaders:: installdirs + cp $(headers) $(DESTDIR)$(includedir) + +installlibs:: installdirs + cp $(STATICLIB) $(LIBSOLIB) $(DESTDIR)$(libdir) + cp ldb.pc $(DESTDIR)$(libdir)/pkgconfig + +installbin:: installdirs + cp $(BINS) $(DESTDIR)$(bindir) + +installdocs:: installdirs + $(srcdir)/docs/installdocs.sh $(DESTDIR)$(mandir) + +gcov:: + $(GCOV) -po ldb_sqlite3 $(srcdir)/ldb_sqlite3/*.c 2| tee ldb_sqlite3.report.gcov + $(GCOV) -po ldb_ldap $(srcdir)/ldb_ldap/*.c 2| tee ldb_ldap.report.gcov + $(GCOV) -po ldb_tdb $(srcdir)/ldb_tdb/*.c 2| tee ldb_tdb.report.gcov + $(GCOV) -po common $(srcdir)/common/*.c 2| tee common.report.gcov + $(GCOV) -po modules $(srcdir)/modules/*.c 2| tee modules.report.gcov + $(GCOV) -po tools $(srcdir)/tools/*.c 2| tee tools.report.gcov + +include $(ldbdir)/ldb.mk diff --git a/ldb/README_gcov.txt b/ldb/README_gcov.txt new file mode 100644 index 000000000..2abd9378f --- /dev/null +++ b/ldb/README_gcov.txt @@ -0,0 +1,29 @@ +Here is how to use gcov to test code coverage in ldb. + +Step 1: build ldb with gcov enabled + + make clean all WITH_GCOV=1 + +Step 3: run the test suite + make test-tdb + +Step 4: produce the gcov report + make gcov + +Step 5: read the summary reports + less *.report.gcov + +Step 6: examine the per-file reports + less ldb_tdb\#ldb_tdb.c.gcov + +You can also combine steps 2 to 4 like this: + + make clean all test-tdb gcov WITH_GCOV=1 + +Note that you should not expect 100% coverage, as some error paths +(such as memory allocation failures) are very hard to trigger. There +are ways of working around this, but they are quite tricky (they +involve allocation wrappers that "fork and fail on malloc"). + +The lines to look for in the per-file reports are the ones starting +with "#####". Those are lines that are never executed. diff --git a/ldb/aclocal.m4 b/ldb/aclocal.m4 new file mode 100644 index 000000000..5605e476b --- /dev/null +++ b/ldb/aclocal.m4 @@ -0,0 +1 @@ +m4_include(libreplace.m4) diff --git a/ldb/autogen.sh b/ldb/autogen.sh new file mode 100755 index 000000000..1681b5042 --- /dev/null +++ b/ldb/autogen.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f configure config.h.in + +IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace" +IPATHS="$IPATHS -I ./external" + +autoheader $IPATHS || exit 1 +autoconf $IPATHS || exit 1 + +rm -rf autom4te.cache + +swig -O -Wall -python -keyword ldb.i # Ignore errors, for now + +echo "Now run ./configure and then make." +exit 0 + diff --git a/ldb/build_macros.m4 b/ldb/build_macros.m4 new file mode 100644 index 000000000..bb05a5822 --- /dev/null +++ b/ldb/build_macros.m4 @@ -0,0 +1,14 @@ +AC_DEFUN(BUILD_WITH_BUILD_INST_DIR, + [ AC_ARG_WITH([build-install-dir], + [AC_HELP_STRING([--with-build-install-dir=DIR], + [temporary build directory where libraries are installed [$srcdir/buildinst]])]) + + buildinstdir="$srcdir/buildinst" + if test x"$with_build_install_dir" != x; then + buildinstdir=$with_build_install_dir + CFLAGS="$CFLAGS -I$with_build_install_dir/include" + CPPFLAGS="$CPPFLAGS -I$with_build_install_dir/include" + LIBS="$LIBS -L$with_build_install_dir/lib" + fi + AC_SUBST(buildinstdir) + ]) diff --git a/ldb/common/attrib_handlers.c b/ldb/common/attrib_handlers.c new file mode 100644 index 000000000..fb57e2dad --- /dev/null +++ b/ldb/common/attrib_handlers.c @@ -0,0 +1,378 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ +/* + attribute handlers for well known attribute types, selected by syntax OID + see rfc2252 +*/ + +#include "ldb_includes.h" +#include "system/locale.h" +#include "ldb_handlers.h" + +/* + default handler that just copies a ldb_val. +*/ +int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + *out = ldb_val_dup(mem_ctx, in); + if (in->length > 0 && out->data == NULL) { + ldb_oom(ldb); + return -1; + } + return 0; +} + +/* + a case folding copy handler, removing leading and trailing spaces and + multiple internal spaces + + We exploit the fact that utf8 never uses the space octet except for + the space itself +*/ +int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + char *s, *t; + int l; + + if (!in || !out || !(in->data)) { + return -1; + } + + out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data), in->length); + if (out->data == NULL) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data); + return -1; + } + + s = (char *)(out->data); + + /* remove trailing spaces if any */ + l = strlen(s); + while (l > 0 && s[l - 1] == ' ') l--; + s[l] = '\0'; + + /* remove leading spaces if any */ + if (*s == ' ') { + for (t = s; *s == ' '; s++) ; + + /* remove leading spaces by moving down the string */ + memmove(t, s, l); + + s = t; + } + + /* check middle spaces */ + while ((t = strchr(s, ' ')) != NULL) { + for (s = t; *s == ' '; s++) ; + + if ((s - t) > 1) { + l = strlen(s); + + /* remove all spaces but one by moving down the string */ + memmove(t + 1, s, l); + } + } + + out->length = strlen((char *)out->data); + return 0; +} + + + +/* + canonicalise a ldap Integer + rfc2252 specifies it should be in decimal form +*/ +int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + char *end; + long long i = strtoll((char *)in->data, &end, 0); + if (*end != 0) { + return -1; + } + out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i); + if (out->data == NULL) { + return -1; + } + out->length = strlen((char *)out->data); + return 0; +} + +/* + compare two Integers +*/ +int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2) +{ + return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0); +} + +/* + compare two binary blobs +*/ +int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2) +{ + if (v1->length != v2->length) { + return v1->length - v2->length; + } + return memcmp(v1->data, v2->data, v1->length); +} + +/* + compare two case insensitive strings, ignoring multiple whitespaces + and leading and trailing whitespaces + see rfc2252 section 8.1 + + try to optimize for the ascii case, + but if we find out an utf8 codepoint revert to slower but correct function +*/ +int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2) +{ + const char *s1=(const char *)v1->data, *s2=(const char *)v2->data; + size_t n1 = v1->length, n2 = v2->length; + const char *u1, *u2; + char *b1, *b2; + int ret; + while (*s1 == ' ' && n1) { s1++; n1--; }; + while (*s2 == ' ' && n2) { s2++; n2--; }; + /* TODO: make utf8 safe, possibly with helper function from application */ + while (*s1 && *s2 && n1 && n2) { + /* the first 127 (0x7F) chars are ascii and utf8 guarantes they + * never appear in multibyte sequences */ + if (((unsigned char)s1[0]) & 0x80) goto utf8str; + if (((unsigned char)s2[0]) & 0x80) goto utf8str; + if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2)) + break; + if (*s1 == ' ') { + while (s1[0] == s1[1] && n1) { s1++; n1--; } + while (s2[0] == s2[1] && n2) { s2++; n2--; } + } + s1++; s2++; + n1--; n2--; + } + if (! (*s1 && *s2)) { + /* check for trailing spaces only if one of the pointers + * has reached the end of the strings otherwise we + * can mistakenly match. + * ex. "domain users" <-> "domainUpdates" + */ + while (*s1 == ' ') { s1++; n1--; } + while (*s2 == ' ') { s2++; n2--; } + } + if (n1 != n2) { + return n1 - n2; + } + return (int)(toupper(*s1)) - (int)(toupper(*s2)); + +utf8str: + /* no need to recheck from the start, just from the first utf8 char found */ + b1 = ldb_casefold(ldb, mem_ctx, s1, n1); + b2 = ldb_casefold(ldb, mem_ctx, s2, n2); + + if (b1 && b2) { + /* Both strings converted correctly */ + + u1 = b1; + u2 = b2; + } else { + /* One of the strings was not UTF8, so we have no options but to do a binary compare */ + + u1 = s1; + u2 = s2; + } + + while (*u1 & *u2) { + if (*u1 != *u2) + break; + if (*u1 == ' ') { + while (u1[0] == u1[1]) u1++; + while (u2[0] == u2[1]) u2++; + } + u1++; u2++; + } + if (! (*u1 && *u2)) { + while (*u1 == ' ') u1++; + while (*u2 == ' ') u2++; + } + ret = (int)(*u1 - *u2); + + talloc_free(b1); + talloc_free(b2); + + return ret; +} + + +/* + canonicalise a attribute in DN format +*/ +int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + struct ldb_dn *dn; + int ret = -1; + + out->length = 0; + out->data = NULL; + + dn = ldb_dn_new(ldb, mem_ctx, (char *)in->data); + if ( ! ldb_dn_validate(dn)) { + return LDB_ERR_INVALID_DN_SYNTAX; + } + + out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn); + if (out->data == NULL) { + goto done; + } + out->length = strlen((char *)out->data); + + ret = 0; + +done: + talloc_free(dn); + + return ret; +} + +/* + compare two dns +*/ +int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2) +{ + struct ldb_dn *dn1 = NULL, *dn2 = NULL; + int ret; + + dn1 = ldb_dn_new(ldb, mem_ctx, (char *)v1->data); + if ( ! ldb_dn_validate(dn1)) return -1; + + dn2 = ldb_dn_new(ldb, mem_ctx, (char *)v2->data); + if ( ! ldb_dn_validate(dn2)) { + talloc_free(dn1); + return -1; + } + + ret = ldb_dn_compare(dn1, dn2); + + talloc_free(dn1); + talloc_free(dn2); + return ret; +} + +/* + compare two utc time values. 1 second resolution +*/ +int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2) +{ + time_t t1, t2; + t1 = ldb_string_to_time((char *)v1->data); + t2 = ldb_string_to_time((char *)v2->data); + return (int)t2 - (int)t1; +} + +/* + canonicalise a utc time +*/ +int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + time_t t = ldb_string_to_time((char *)in->data); + out->data = (uint8_t *)ldb_timestring(mem_ctx, t); + if (out->data == NULL) { + return -1; + } + out->length = strlen((char *)out->data); + return 0; +} + +/* + table of standard attribute handlers +*/ +static const struct ldb_schema_syntax ldb_standard_syntaxes[] = { + { + .name = LDB_SYNTAX_INTEGER, + .ldif_read_fn = ldb_handler_copy, + .ldif_write_fn = ldb_handler_copy, + .canonicalise_fn = ldb_canonicalise_Integer, + .comparison_fn = ldb_comparison_Integer + }, + { + .name = LDB_SYNTAX_OCTET_STRING, + .ldif_read_fn = ldb_handler_copy, + .ldif_write_fn = ldb_handler_copy, + .canonicalise_fn = ldb_handler_copy, + .comparison_fn = ldb_comparison_binary + }, + { + .name = LDB_SYNTAX_DIRECTORY_STRING, + .ldif_read_fn = ldb_handler_copy, + .ldif_write_fn = ldb_handler_copy, + .canonicalise_fn = ldb_handler_fold, + .comparison_fn = ldb_comparison_fold + }, + { + .name = LDB_SYNTAX_DN, + .ldif_read_fn = ldb_handler_copy, + .ldif_write_fn = ldb_handler_copy, + .canonicalise_fn = ldb_canonicalise_dn, + .comparison_fn = ldb_comparison_dn + }, + { + .name = LDB_SYNTAX_OBJECTCLASS, + .ldif_read_fn = ldb_handler_copy, + .ldif_write_fn = ldb_handler_copy, + .canonicalise_fn = ldb_handler_fold, + .comparison_fn = ldb_comparison_fold + }, + { + .name = LDB_SYNTAX_UTC_TIME, + .ldif_read_fn = ldb_handler_copy, + .ldif_write_fn = ldb_handler_copy, + .canonicalise_fn = ldb_canonicalise_utctime, + .comparison_fn = ldb_comparison_utctime + } +}; + + +/* + return the attribute handlers for a given syntax name +*/ +const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb, + const char *syntax) +{ + int i; + unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]); + /* TODO: should be replaced with a binary search */ + for (i=0;i. +*/ + +/* + * Name: ldb + * + * Component: ldb core API + * + * Description: core API routines interfacing to ldb backends + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" + +/* + initialise a ldb context + The mem_ctx is required + The event_ctx is required +*/ +struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct event_context *ev_ctx) +{ + struct ldb_context *ldb; + int ret; + + ldb = talloc_zero(mem_ctx, struct ldb_context); + /* FIXME: Hack a new event context so that CMD line utilities work + * until we have them all converted */ + if (ev_ctx == NULL) { + ev_ctx = event_context_init(talloc_autofree_context()); + } + + ret = ldb_setup_wellknown_attributes(ldb); + if (ret != 0) { + talloc_free(ldb); + return NULL; + } + + ldb_set_utf8_default(ldb); + ldb_set_create_perms(ldb, 0666); + ldb_set_modules_dir(ldb, LDB_MODULESDIR); + ldb_set_event_context(ldb, ev_ctx); + + /* TODO: get timeout from options if available there */ + ldb->default_timeout = 300; /* set default to 5 minutes */ + + return ldb; +} + +/* + try to autodetect a basedn if none specified. This fixes one of my + pet hates about ldapsearch, which is that you have to get a long, + complex basedn right to make any use of it. +*/ +void ldb_set_default_dns(struct ldb_context *ldb) +{ + TALLOC_CTX *tmp_ctx; + int ret; + struct ldb_result *res; + struct ldb_dn *tmp_dn=NULL; + static const char *attrs[] = { + "rootDomainNamingContext", + "configurationNamingContext", + "schemaNamingContext", + "defaultNamingContext", + NULL + }; + + tmp_ctx = talloc_new(ldb); + ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, NULL), LDB_SCOPE_BASE, + "(objectClass=*)", attrs, &res); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return; + } + + if (res->count != 1) { + talloc_free(res); + return; + } + + if (!ldb_get_opaque(ldb, "rootDomainNamingContext")) { + tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], + "rootDomainNamingContext"); + ldb_set_opaque(ldb, "rootDomainNamingContext", tmp_dn); + } + + if (!ldb_get_opaque(ldb, "configurationNamingContext")) { + tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], + "configurationNamingContext"); + ldb_set_opaque(ldb, "configurationNamingContext", tmp_dn); + } + + if (!ldb_get_opaque(ldb, "schemaNamingContext")) { + tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], + "schemaNamingContext"); + ldb_set_opaque(ldb, "schemaNamingContext", tmp_dn); + } + + if (!ldb_get_opaque(ldb, "defaultNamingContext")) { + tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], + "defaultNamingContext"); + ldb_set_opaque(ldb, "defaultNamingContext", tmp_dn); + } + + talloc_free(res); + talloc_free(tmp_ctx); +} + +struct ldb_dn *ldb_get_root_basedn(struct ldb_context *ldb) +{ + void *opaque = ldb_get_opaque(ldb, "rootDomainNamingContext"); + return talloc_get_type(opaque, struct ldb_dn); +} + +struct ldb_dn *ldb_get_config_basedn(struct ldb_context *ldb) +{ + void *opaque = ldb_get_opaque(ldb, "configurationNamingContext"); + return talloc_get_type(opaque, struct ldb_dn); +} + +struct ldb_dn *ldb_get_schema_basedn(struct ldb_context *ldb) +{ + void *opaque = ldb_get_opaque(ldb, "schemaNamingContext"); + return talloc_get_type(opaque, struct ldb_dn); +} + +struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb) +{ + void *opaque = ldb_get_opaque(ldb, "defaultNamingContext"); + return talloc_get_type(opaque, struct ldb_dn); +} + +/* + connect to a database. The URL can either be one of the following forms + ldb://path + ldapi://path + + flags is made up of LDB_FLG_* + + the options are passed uninterpreted to the backend, and are + backend specific +*/ +int ldb_connect(struct ldb_context *ldb, const char *url, + unsigned int flags, const char *options[]) +{ + int ret; + const char *url2; + /* We seem to need to do this here, or else some utilities don't + * get ldb backends */ + + ldb->flags = flags; + + url2 = talloc_strdup(ldb, url); + if (!url2) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = ldb_set_opaque(ldb, "ldb_url", talloc_strdup(ldb, url2)); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_connect_backend(ldb, url, options, &ldb->modules); + if (ret != LDB_SUCCESS) { + return ret; + } + + if (ldb_load_modules(ldb, options) != LDB_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_FATAL, + "Unable to load modules for %s: %s\n", + url, ldb_errstring(ldb)); + return LDB_ERR_OTHER; + } + + /* TODO: get timeout from options if available there */ + ldb->default_timeout = 300; /* set default to 5 minutes */ + + /* set the default base dn */ + ldb_set_default_dns(ldb); + + return LDB_SUCCESS; +} + +void ldb_set_errstring(struct ldb_context *ldb, const char *err_string) +{ + if (ldb->err_string) { + talloc_free(ldb->err_string); + } + ldb->err_string = talloc_strdup(ldb, err_string); +} + +void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) +{ + va_list ap; + char *old_string = NULL; + + if (ldb->err_string) { + old_string = ldb->err_string; + } + + va_start(ap, format); + ldb->err_string = talloc_vasprintf(ldb, format, ap); + va_end(ap); + talloc_free(old_string); +} + +void ldb_reset_err_string(struct ldb_context *ldb) +{ + if (ldb->err_string) { + talloc_free(ldb->err_string); + ldb->err_string = NULL; + } +} + +#define FIRST_OP(ldb, op) do { \ + module = ldb->modules; \ + while (module && module->ops->op == NULL) module = module->next; \ + if (module == NULL) { \ + ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \ + return LDB_ERR_OPERATIONS_ERROR; \ + } \ +} while (0) + +/* + start a transaction +*/ +static int ldb_transaction_start_internal(struct ldb_context *ldb) +{ + struct ldb_module *module; + int status; + FIRST_OP(ldb, start_transaction); + + ldb_reset_err_string(ldb); + + status = module->ops->start_transaction(module); + if (status != LDB_SUCCESS) { + if (ldb->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, + "ldb transaction start: %s (%d)", + ldb_strerror(status), + status); + } + } + return status; +} + +/* + commit a transaction +*/ +static int ldb_transaction_commit_internal(struct ldb_context *ldb) +{ + struct ldb_module *module; + int status; + FIRST_OP(ldb, end_transaction); + + ldb_reset_err_string(ldb); + + status = module->ops->end_transaction(module); + if (status != LDB_SUCCESS) { + if (ldb->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, + "ldb transaction commit: %s (%d)", + ldb_strerror(status), + status); + } + } + return status; +} + +/* + cancel a transaction +*/ +static int ldb_transaction_cancel_internal(struct ldb_context *ldb) +{ + struct ldb_module *module; + int status; + FIRST_OP(ldb, del_transaction); + + status = module->ops->del_transaction(module); + if (status != LDB_SUCCESS) { + if (ldb->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, + "ldb transaction cancel: %s (%d)", + ldb_strerror(status), + status); + } + } + return status; +} + +int ldb_transaction_start(struct ldb_context *ldb) +{ + /* disable autotransactions */ + ldb->transaction_active++; + + return ldb_transaction_start_internal(ldb); +} + +int ldb_transaction_commit(struct ldb_context *ldb) +{ + /* renable autotransactions (when we reach 0) */ + if (ldb->transaction_active > 0) + ldb->transaction_active--; + + return ldb_transaction_commit_internal(ldb); +} + +int ldb_transaction_cancel(struct ldb_context *ldb) +{ + /* renable autotransactions (when we reach 0) */ + if (ldb->transaction_active > 0) + ldb->transaction_active--; + + return ldb_transaction_cancel_internal(ldb); +} + +static int ldb_autotransaction_start(struct ldb_context *ldb) +{ + /* explicit transaction active, ignore autotransaction request */ + if (ldb->transaction_active) + return LDB_SUCCESS; + + return ldb_transaction_start_internal(ldb); +} + +static int ldb_autotransaction_commit(struct ldb_context *ldb) +{ + /* explicit transaction active, ignore autotransaction request */ + if (ldb->transaction_active) + return LDB_SUCCESS; + + return ldb_transaction_commit_internal(ldb); +} + +static int ldb_autotransaction_cancel(struct ldb_context *ldb) +{ + /* explicit transaction active, ignore autotransaction request */ + if (ldb->transaction_active) + return LDB_SUCCESS; + + return ldb_transaction_cancel_internal(ldb); +} + +/* autostarts a transacion if none active */ +static int ldb_autotransaction_request(struct ldb_context *ldb, + struct ldb_request *req) +{ + int ret; + + ret = ldb_autotransaction_start(ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_request(ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + return ldb_autotransaction_commit(ldb); + } + ldb_autotransaction_cancel(ldb); + + if (ldb->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret); + } + + return ret; +} + +int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + int ret; + if (!handle) { + return LDB_SUCCESS; + } + + ret = handle->module->ops->wait(handle, type); + if (!ldb_errstring(handle->module->ldb)) { + /* Set a default error string, to place the blame somewhere */ + ldb_asprintf_errstring(handle->module->ldb, + "error waiting on module %s: %s (%d)", + handle->module->ops->name, + ldb_strerror(ret), ret); + } + return ret; +} + +/* set the specified timeout or, if timeout is 0 set the default timeout */ +/* timeout == -1 means no timeout */ +int ldb_set_timeout(struct ldb_context *ldb, + struct ldb_request *req, + int timeout) +{ + if (req == NULL) return LDB_ERR_OPERATIONS_ERROR; + + if (timeout != 0) { + req->timeout = timeout; + } else { + req->timeout = ldb->default_timeout; + } + req->starttime = time(NULL); + + return LDB_SUCCESS; +} + +/* calculates the new timeout based on the previous starttime and timeout */ +int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, + struct ldb_request *oldreq, + struct ldb_request *newreq) +{ + time_t now; + + if (newreq == NULL) return LDB_ERR_OPERATIONS_ERROR; + + now = time(NULL); + + if (oldreq == NULL) + return ldb_set_timeout(ldb, newreq, 0); + + if ((now - oldreq->starttime) > oldreq->timeout) { + return LDB_ERR_TIME_LIMIT_EXCEEDED; + } + newreq->starttime = oldreq->starttime; + newreq->timeout = oldreq->timeout - (now - oldreq->starttime); + + return LDB_SUCCESS; +} + + +/* + set the permissions for new files to be passed to open() in + backends that use local files + */ +void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms) +{ + ldb->create_perms = perms; +} + +void ldb_set_event_context(struct ldb_context *ldb, struct event_context *ev) +{ + ldb->ev_ctx = ev; +} + +struct event_context * ldb_get_event_context(struct ldb_context *ldb) +{ + return ldb->ev_ctx; +} + +/* + start an ldb request + NOTE: the request must be a talloc context. + returns LDB_ERR_* on errors. +*/ +int ldb_request(struct ldb_context *ldb, struct ldb_request *req) +{ + struct ldb_module *module; + int ret; + + ldb_reset_err_string(ldb); + + /* call the first module in the chain */ + switch (req->operation) { + case LDB_SEARCH: + FIRST_OP(ldb, search); + ret = module->ops->search(module, req); + break; + case LDB_ADD: + FIRST_OP(ldb, add); + ret = module->ops->add(module, req); + break; + case LDB_MODIFY: + FIRST_OP(ldb, modify); + ret = module->ops->modify(module, req); + break; + case LDB_DELETE: + FIRST_OP(ldb, del); + ret = module->ops->del(module, req); + break; + case LDB_RENAME: + FIRST_OP(ldb, rename); + ret = module->ops->rename(module, req); + break; + case LDB_EXTENDED: + FIRST_OP(ldb, extended); + ret = module->ops->extended(module, req); + break; + case LDB_SEQUENCE_NUMBER: + FIRST_OP(ldb, sequence_number); + ret = module->ops->sequence_number(module, req); + break; + default: + FIRST_OP(ldb, request); + ret = module->ops->request(module, req); + break; + } + + return ret; +} + +/* + search the database given a LDAP-like search expression + + returns an LDB error code + + Use talloc_free to free the ldb_message returned in 'res', if successful + +*/ +int ldb_search_default_callback(struct ldb_context *ldb, + void *context, + struct ldb_reply *ares) +{ + struct ldb_result *res; + int n; + + if (!context) { + ldb_set_errstring(ldb, "NULL Context in callback"); + return LDB_ERR_OPERATIONS_ERROR; + } + + res = talloc_get_type(context, struct ldb_result); + + if (!res || !ares) { + ldb_set_errstring(ldb, "NULL res or ares in callback"); + goto error; + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (! res->msgs) { + goto error; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_move(res->msgs, &ares->message); + res->count++; + break; + case LDB_REPLY_REFERRAL: + if (res->refs) { + for (n = 0; res->refs[n]; n++) /*noop*/ ; + } else { + n = 0; + } + + res->refs = talloc_realloc(res, res->refs, char *, n + 2); + if (! res->refs) { + goto error; + } + + res->refs[n] = talloc_move(res->refs, &ares->referral); + res->refs[n + 1] = NULL; + break; + case LDB_REPLY_EXTENDED: + case LDB_REPLY_DONE: + /* TODO: we should really support controls on entries + * and referrals too! */ + res->controls = talloc_move(res, &ares->controls); + break; + } + talloc_free(ares); + return LDB_SUCCESS; + +error: + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; +} + +int ldb_build_search_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + struct ldb_dn *base, + enum ldb_scope scope, + const char *expression, + const char * const *attrs, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_SEARCH; + if (base == NULL) { + req->op.search.base = ldb_dn_new(req, ldb, NULL); + } else { + req->op.search.base = base; + } + req->op.search.scope = scope; + + req->op.search.tree = ldb_parse_tree(req, expression); + if (req->op.search.tree == NULL) { + ldb_set_errstring(ldb, "Unable to parse search expression"); + talloc_free(req); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->op.search.attrs = attrs; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + return LDB_SUCCESS; +} + +int ldb_build_add_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_ADD; + req->op.add.message = message; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +int ldb_build_mod_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_MODIFY; + req->op.mod.message = message; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +int ldb_build_del_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + struct ldb_dn *dn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_DELETE; + req->op.del.dn = dn; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +int ldb_build_rename_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + struct ldb_dn *olddn, + struct ldb_dn *newdn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_RENAME; + req->op.rename.olddn = olddn; + req->op.rename.newdn = newdn; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +int ldb_extended_default_callback(struct ldb_context *ldb, + void *context, + struct ldb_reply *ares) +{ + struct ldb_result *res; + + if (!context) { + ldb_set_errstring(ldb, "NULL Context in callback"); + return LDB_ERR_OPERATIONS_ERROR; + } + + res = talloc_get_type(context, struct ldb_result); + if (!res || !ares) { + ldb_set_errstring(ldb, "NULL res or ares in callback"); + goto error; + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + case LDB_REPLY_REFERRAL: + case LDB_REPLY_DONE: + ldb_set_errstring(ldb, "invalid ares type in callback"); + goto error; + case LDB_REPLY_EXTENDED: + /* TODO: we should really support controls on entries and + * referrals too! */ + res->extended = talloc_move(res, &ares->response); + res->controls = talloc_move(res, &ares->controls); + break; + } + talloc_free(ares); + return LDB_SUCCESS; + +error: + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; +} + +int ldb_build_extended_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const char *oid, + void *data, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_EXTENDED; + req->op.extended.oid = oid; + req->op.extended.data = data; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +int ldb_extended(struct ldb_context *ldb, + const char *oid, + void *data, + struct ldb_result **_res) +{ + struct ldb_request *req; + int ret; + struct ldb_result *res; + + *_res = NULL; + + res = talloc_zero(ldb, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_extended_req(&req, ldb, ldb, + oid, data, NULL, + res, ldb_extended_default_callback); + if (ret != LDB_SUCCESS) goto done; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + ret = ldb_request(ldb, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + +done: + if (ret != LDB_SUCCESS) { + talloc_free(res); + } + + *_res = res; + return ret; +} + +/* + note that ldb_search() will automatically replace a NULL 'base' value + with the defaultNamingContext from the rootDSE if available. +*/ +int ldb_search(struct ldb_context *ldb, + struct ldb_dn *base, + enum ldb_scope scope, + const char *expression, + const char * const *attrs, + struct ldb_result **_res) +{ + struct ldb_request *req; + int ret; + struct ldb_result *res; + + *_res = NULL; + + res = talloc_zero(ldb, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&req, ldb, ldb, + base?base:ldb_get_default_basedn(ldb), + scope, + expression, + attrs, + NULL, + res, + ldb_search_default_callback); + + if (ret != LDB_SUCCESS) goto done; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + ret = ldb_request(ldb, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + +done: + if (ret != LDB_SUCCESS) { + talloc_free(res); + } + + *_res = res; + return ret; +} + +/* + a useful search function where you can easily define the expression and that + takes a memory context where results are allocated +*/ + +int ldb_search_exp_fmt(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, + struct ldb_result **result, struct ldb_dn *base, + enum ldb_scope scope, const char * const *attrs, + const char *exp_fmt, ...) +{ + struct ldb_result *res; + char *expression; + va_list ap; + int ret; + + res = NULL; + *result = NULL; + + va_start(ap, exp_fmt); + expression = talloc_vasprintf(mem_ctx, exp_fmt, ap); + va_end(ap); + + if ( ! expression) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_search(ldb, base, scope, expression, attrs, &res); + + if (ret == LDB_SUCCESS) { + talloc_steal(mem_ctx, res); + *result = res; + } + + talloc_free(expression); + + return ret; +} + +/* + add a record to the database. Will fail if a record with the + given class and key already exists +*/ +int ldb_add(struct ldb_context *ldb, + const struct ldb_message *message) +{ + struct ldb_request *req; + int ret; + + ret = ldb_msg_sanity_check(ldb, message); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_add_req(&req, ldb, ldb, + message, + NULL, + NULL, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + /* do request and autostart a transaction */ + ret = ldb_autotransaction_request(ldb, req); + + talloc_free(req); + return ret; +} + +/* + modify the specified attributes of a record +*/ +int ldb_modify(struct ldb_context *ldb, + const struct ldb_message *message) +{ + struct ldb_request *req; + int ret; + + ret = ldb_msg_sanity_check(ldb, message); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_mod_req(&req, ldb, ldb, + message, + NULL, + NULL, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + /* do request and autostart a transaction */ + ret = ldb_autotransaction_request(ldb, req); + + talloc_free(req); + return ret; +} + + +/* + delete a record from the database +*/ +int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn) +{ + struct ldb_request *req; + int ret; + + ret = ldb_build_del_req(&req, ldb, ldb, + dn, + NULL, + NULL, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + /* do request and autostart a transaction */ + ret = ldb_autotransaction_request(ldb, req); + + talloc_free(req); + return ret; +} + +/* + rename a record in the database +*/ +int ldb_rename(struct ldb_context *ldb, + struct ldb_dn *olddn, struct ldb_dn *newdn) +{ + struct ldb_request *req; + int ret; + + ret = ldb_build_rename_req(&req, ldb, ldb, + olddn, + newdn, + NULL, + NULL, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + /* do request and autostart a transaction */ + ret = ldb_autotransaction_request(ldb, req); + + talloc_free(req); + return ret; +} + + +/* + return the global sequence number +*/ +int ldb_sequence_number(struct ldb_context *ldb, + enum ldb_sequence_type type, + uint64_t *seq_num) +{ + struct ldb_request *req; + int ret; + + req = talloc(ldb, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_SEQUENCE_NUMBER; + req->controls = NULL; + req->context = NULL; + req->callback = NULL; + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + req->op.seq_num.type = type; + /* do request and autostart a transaction */ + ret = ldb_request(ldb, req); + + if (ret == LDB_SUCCESS) { + *seq_num = req->op.seq_num.seq_num; + } + + talloc_free(req); + return ret; +} + + + +/* + return extended error information +*/ +const char *ldb_errstring(struct ldb_context *ldb) +{ + if (ldb->err_string) { + return ldb->err_string; + } + + return NULL; +} + +/* + return a string explaining what a ldb error constant meancs +*/ +const char *ldb_strerror(int ldb_err) +{ + switch (ldb_err) { + case LDB_SUCCESS: + return "Success"; + case LDB_ERR_OPERATIONS_ERROR: + return "Operations error"; + case LDB_ERR_PROTOCOL_ERROR: + return "Protocol error"; + case LDB_ERR_TIME_LIMIT_EXCEEDED: + return "Time limit exceeded"; + case LDB_ERR_SIZE_LIMIT_EXCEEDED: + return "Size limit exceeded"; + case LDB_ERR_COMPARE_FALSE: + return "Compare false"; + case LDB_ERR_COMPARE_TRUE: + return "Compare true"; + case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED: + return "Auth method not supported"; + case LDB_ERR_STRONG_AUTH_REQUIRED: + return "Strong auth required"; +/* 9 RESERVED */ + case LDB_ERR_REFERRAL: + return "Referral error"; + case LDB_ERR_ADMIN_LIMIT_EXCEEDED: + return "Admin limit exceeded"; + case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION: + return "Unsupported critical extension"; + case LDB_ERR_CONFIDENTIALITY_REQUIRED: + return "Confidentiality required"; + case LDB_ERR_SASL_BIND_IN_PROGRESS: + return "SASL bind in progress"; + case LDB_ERR_NO_SUCH_ATTRIBUTE: + return "No such attribute"; + case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE: + return "Undefined attribute type"; + case LDB_ERR_INAPPROPRIATE_MATCHING: + return "Inappropriate matching"; + case LDB_ERR_CONSTRAINT_VIOLATION: + return "Constraint violation"; + case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS: + return "Attribute or value exists"; + case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX: + return "Invalid attribute syntax"; +/* 22-31 unused */ + case LDB_ERR_NO_SUCH_OBJECT: + return "No such object"; + case LDB_ERR_ALIAS_PROBLEM: + return "Alias problem"; + case LDB_ERR_INVALID_DN_SYNTAX: + return "Invalid DN syntax"; +/* 35 RESERVED */ + case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM: + return "Alias dereferencing problem"; +/* 37-47 unused */ + case LDB_ERR_INAPPROPRIATE_AUTHENTICATION: + return "Inappropriate authentication"; + case LDB_ERR_INVALID_CREDENTIALS: + return "Invalid credentials"; + case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: + return "insufficient access rights"; + case LDB_ERR_BUSY: + return "Busy"; + case LDB_ERR_UNAVAILABLE: + return "Unavailable"; + case LDB_ERR_UNWILLING_TO_PERFORM: + return "Unwilling to perform"; + case LDB_ERR_LOOP_DETECT: + return "Loop detect"; +/* 55-63 unused */ + case LDB_ERR_NAMING_VIOLATION: + return "Naming violation"; + case LDB_ERR_OBJECT_CLASS_VIOLATION: + return "Object class violation"; + case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF: + return "Not allowed on non-leaf"; + case LDB_ERR_NOT_ALLOWED_ON_RDN: + return "Not allowed on RDN"; + case LDB_ERR_ENTRY_ALREADY_EXISTS: + return "Entry already exists"; + case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED: + return "Object class mods prohibited"; +/* 70 RESERVED FOR CLDAP */ + case LDB_ERR_AFFECTS_MULTIPLE_DSAS: + return "Affects multiple DSAs"; +/* 72-79 unused */ + case LDB_ERR_OTHER: + return "Other"; + } + + return "Unknown error"; +} + +/* + set backend specific opaque parameters +*/ +int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value) +{ + struct ldb_opaque *o; + + /* allow updating an existing value */ + for (o=ldb->opaque;o;o=o->next) { + if (strcmp(o->name, name) == 0) { + o->value = value; + return LDB_SUCCESS; + } + } + + o = talloc(ldb, struct ldb_opaque); + if (o == NULL) { + ldb_oom(ldb); + return LDB_ERR_OTHER; + } + o->next = ldb->opaque; + o->name = name; + o->value = value; + ldb->opaque = o; + return LDB_SUCCESS; +} + +/* + get a previously set opaque value +*/ +void *ldb_get_opaque(struct ldb_context *ldb, const char *name) +{ + struct ldb_opaque *o; + for (o=ldb->opaque;o;o=o->next) { + if (strcmp(o->name, name) == 0) { + return o->value; + } + } + return NULL; +} diff --git a/ldb/common/ldb_attributes.c b/ldb/common/ldb_attributes.c new file mode 100644 index 000000000..747f24178 --- /dev/null +++ b/ldb/common/ldb_attributes.c @@ -0,0 +1,227 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ +/* + register handlers for specific attributes and objectclass relationships + + this allows a backend to store its schema information in any format + it likes (or to not have any schema information at all) while keeping the + message matching logic generic +*/ + +#include "ldb_includes.h" + +/* + add a attribute to the ldb_schema + + if flags contains LDB_ATTR_FLAG_ALLOCATED + the attribute name string will be copied using + talloc_strdup(), otherwise it needs to be a static const + string at least with a lifetime longer than the ldb struct! + + the ldb_schema_syntax structure should be a pointer + to a static const struct or at least it needs to be + a struct with a longer lifetime than the ldb context! + +*/ +int ldb_schema_attribute_add_with_syntax(struct ldb_context *ldb, + const char *attribute, + unsigned flags, + const struct ldb_schema_syntax *syntax) +{ + int i, n; + struct ldb_schema_attribute *a; + + if (!syntax) { + return LDB_ERR_OPERATIONS_ERROR; + } + + n = ldb->schema.num_attributes + 1; + + a = talloc_realloc(ldb, ldb->schema.attributes, + struct ldb_schema_attribute, n); + if (a == NULL) { + ldb_oom(ldb); + return -1; + } + ldb->schema.attributes = a; + + for (i = 0; i < ldb->schema.num_attributes; i++) { + int cmp = ldb_attr_cmp(attribute, a[i].name); + if (cmp == 0) { + /* silently ignore attempts to overwrite fixed attributes */ + if (a[i].flags & LDB_ATTR_FLAG_FIXED) { + return 0; + } + if (a[i].flags & LDB_ATTR_FLAG_ALLOCATED) { + talloc_free(discard_const_p(char, a[i].name)); + } + /* To cancel out increment below */ + ldb->schema.num_attributes--; + break; + } else if (cmp < 0) { + memmove(a+i+1, a+i, sizeof(*a) * (ldb->schema.num_attributes-i)); + break; + } + } + ldb->schema.num_attributes++; + + a[i].name = attribute; + a[i].flags = flags; + a[i].syntax = syntax; + + if (a[i].flags & LDB_ATTR_FLAG_ALLOCATED) { + a[i].name = talloc_strdup(a, a[i].name); + if (a[i].name == NULL) { + ldb_oom(ldb); + return -1; + } + } + + return 0; +} + +static const struct ldb_schema_syntax ldb_syntax_default = { + .name = LDB_SYNTAX_OCTET_STRING, + .ldif_read_fn = ldb_handler_copy, + .ldif_write_fn = ldb_handler_copy, + .canonicalise_fn = ldb_handler_copy, + .comparison_fn = ldb_comparison_binary +}; + +static const struct ldb_schema_attribute ldb_attribute_default = { + .name = NULL, + .flags = 0, + .syntax = &ldb_syntax_default +}; + +/* + return the attribute handlers for a given attribute +*/ +const struct ldb_schema_attribute *ldb_schema_attribute_by_name(struct ldb_context *ldb, + const char *name) +{ + int i, e, b = 0, r; + const struct ldb_schema_attribute *def = &ldb_attribute_default; + + /* as handlers are sorted, '*' must be the first if present */ + if (strcmp(ldb->schema.attributes[0].name, "*") == 0) { + def = &ldb->schema.attributes[0]; + b = 1; + } + + /* do a binary search on the array */ + e = ldb->schema.num_attributes - 1; + + while (b <= e) { + + i = (b + e) / 2; + + r = ldb_attr_cmp(name, ldb->schema.attributes[i].name); + if (r == 0) { + return &ldb->schema.attributes[i]; + } + if (r < 0) { + e = i - 1; + } else { + b = i + 1; + } + + } + + return def; +} + + +/* + add to the list of ldif handlers for this ldb context +*/ +void ldb_schema_attribute_remove(struct ldb_context *ldb, const char *name) +{ + const struct ldb_schema_attribute *a; + int i; + + a = ldb_schema_attribute_by_name(ldb, name); + if (a == NULL || a->name == NULL) { + return; + } + + /* FIXED attributes are never removed */ + if (a->flags & LDB_ATTR_FLAG_FIXED) { + return; + } + + if (a->flags & LDB_ATTR_FLAG_ALLOCATED) { + talloc_free(discard_const_p(char, a->name)); + } + + i = a - ldb->schema.attributes; + if (i < ldb->schema.num_attributes - 1) { + memmove(&ldb->schema.attributes[i], + a+1, sizeof(*a) * (ldb->schema.num_attributes-(i+1))); + } + + ldb->schema.num_attributes--; +} + +/* + setup a attribute handler using a standard syntax +*/ +int ldb_schema_attribute_add(struct ldb_context *ldb, + const char *attribute, + unsigned flags, + const char *syntax) +{ + const struct ldb_schema_syntax *s = ldb_standard_syntax_by_name(ldb, syntax); + return ldb_schema_attribute_add_with_syntax(ldb, attribute, flags, s); +} + +/* + setup the attribute handles for well known attributes +*/ +int ldb_setup_wellknown_attributes(struct ldb_context *ldb) +{ + const struct { + const char *attr; + const char *syntax; + } wellknown[] = { + { "dn", LDB_SYNTAX_DN }, + { "distinguishedName", LDB_SYNTAX_DN }, + { "cn", LDB_SYNTAX_DIRECTORY_STRING }, + { "dc", LDB_SYNTAX_DIRECTORY_STRING }, + { "ou", LDB_SYNTAX_DIRECTORY_STRING }, + { "objectClass", LDB_SYNTAX_OBJECTCLASS } + }; + int i; + int ret; + + for (i=0;i. +*/ + +/* + * Name: ldb_controls.c + * + * Component: ldb controls utility functions + * + * Description: helper functions for control modules + * + * Author: Simo Sorce + */ + +#include "ldb_includes.h" + +/* check if a control with the specified "oid" exist and return it */ +/* returns NULL if not found */ +struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char *oid) +{ + int i; + + /* check if there's a paged request control */ + if (req->controls != NULL) { + for (i = 0; req->controls[i]; i++) { + if (strcmp(oid, req->controls[i]->oid) == 0) { + break; + } + } + + return req->controls[i]; + } + + return NULL; +} + +/* saves the current controls list into the "saver" and replace the one in req with a new one excluding +the "exclude" control */ +/* returns False on error */ +int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver) +{ + struct ldb_control **lcs; + int i, j; + + *saver = req->controls; + for (i = 0; req->controls[i]; i++); + if (i == 1) { + req->controls = NULL; + return 1; + } + + lcs = talloc_array(req, struct ldb_control *, i); + if (!lcs) { + return 0; + } + + for (i = 0, j = 0; (*saver)[i]; i++) { + if (exclude == (*saver)[i]) continue; + lcs[j] = (*saver)[i]; + j++; + } + lcs[j] = NULL; + + req->controls = lcs; + return 1; +} + +/* check if there's any control marked as critical in the list */ +/* return True if any, False if none */ +int check_critical_controls(struct ldb_control **controls) +{ + int i; + + if (controls == NULL) { + return 0; + } + + for (i = 0; controls[i]; i++) { + if (controls[i]->critical) { + return 1; + } + } + + return 0; +} + +int ldb_request_add_control(struct ldb_request *req, const char *oid, bool critical, void *data) +{ + unsigned n; + struct ldb_control **ctrls; + struct ldb_control *ctrl; + + for (n=0; req->controls && req->controls[n];) { n++; } + + ctrls = talloc_realloc(req, req->controls, + struct ldb_control *, + n + 2); + if (!ctrls) return LDB_ERR_OPERATIONS_ERROR; + req->controls = ctrls; + ctrls[n] = NULL; + ctrls[n+1] = NULL; + + ctrl = talloc(ctrls, struct ldb_control); + if (!ctrl) return LDB_ERR_OPERATIONS_ERROR; + + ctrl->oid = talloc_strdup(ctrl, oid); + if (!ctrl->oid) return LDB_ERR_OPERATIONS_ERROR; + ctrl->critical = critical; + ctrl->data = data; + + ctrls[n] = ctrl; + return LDB_SUCCESS; +} + +/* Parse controls from the format used on the command line and in ejs */ + +struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, void *mem_ctx, const char **control_strings) +{ + int i; + struct ldb_control **ctrl; + + char *error_string = NULL; + + if (control_strings == NULL || control_strings[0] == NULL) + return NULL; + + for (i = 0; control_strings[i]; i++); + + ctrl = talloc_array(mem_ctx, struct ldb_control *, i + 1); + + for (i = 0; control_strings[i]; i++) { + if (strncmp(control_strings[i], "vlv:", 4) == 0) { + struct ldb_vlv_req_control *control; + const char *p; + char attr[1024]; + char ctxid[1024]; + int crit, bc, ac, os, cc, ret; + + attr[0] = '\0'; + ctxid[0] = '\0'; + p = &(control_strings[i][4]); + ret = sscanf(p, "%d:%d:%d:%d:%d:%1023[^$]", &crit, &bc, &ac, &os, &cc, ctxid); + if (ret < 5) { + ret = sscanf(p, "%d:%d:%d:%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid); + } + + if ((ret < 4) || (crit < 0) || (crit > 1)) { + error_string = talloc_asprintf(mem_ctx, "invalid server_sort control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b):bc(n):ac(n):[:ctxid(o)]\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number, s = string, o = b64 binary blob"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + if (!(ctrl[i] = talloc(ctrl, struct ldb_control))) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_VLV_REQ_OID; + ctrl[i]->critical = crit; + if (!(control = talloc(ctrl[i], + struct ldb_vlv_req_control))) { + ldb_oom(ldb); + return NULL; + } + control->beforeCount = bc; + control->afterCount = ac; + if (attr[0]) { + control->type = 1; + control->match.gtOrEq.value = talloc_strdup(control, attr); + control->match.gtOrEq.value_len = strlen(attr); + } else { + control->type = 0; + control->match.byOffset.offset = os; + control->match.byOffset.contentCount = cc; + } + if (ctxid[0]) { + control->ctxid_len = ldb_base64_decode(ctxid); + control->contextId = (char *)talloc_memdup(control, ctxid, control->ctxid_len); + } else { + control->ctxid_len = 0; + control->contextId = NULL; + } + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "dirsync:", 8) == 0) { + struct ldb_dirsync_control *control; + const char *p; + char cookie[1024]; + int crit, flags, max_attrs, ret; + + cookie[0] = '\0'; + p = &(control_strings[i][8]); + ret = sscanf(p, "%d:%d:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie); + + if ((ret < 3) || (crit < 0) || (crit > 1) || (flags < 0) || (max_attrs < 0)) { + error_string = talloc_asprintf(mem_ctx, "invalid dirsync control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number, o = b64 binary blob"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + /* w2k3 seems to ignore the parameter, + * but w2k sends a wrong cookie when this value is to small + * this would cause looping forever, while getting + * the same data and same cookie forever + */ + if (max_attrs == 0) max_attrs = 0x0FFFFFFF; + + ctrl[i] = talloc(ctrl, struct ldb_control); + ctrl[i]->oid = LDB_CONTROL_DIRSYNC_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_dirsync_control); + control->flags = flags; + control->max_attributes = max_attrs; + if (*cookie) { + control->cookie_len = ldb_base64_decode(cookie); + control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len); + } else { + control->cookie = NULL; + control->cookie_len = 0; + } + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "asq:", 4) == 0) { + struct ldb_asq_control *control; + const char *p; + char attr[256]; + int crit, ret; + + attr[0] = '\0'; + p = &(control_strings[i][4]); + ret = sscanf(p, "%d:%255[^$]", &crit, attr); + if ((ret != 2) || (crit < 0) || (crit > 1) || (attr[0] == '\0')) { + error_string = talloc_asprintf(mem_ctx, "invalid asq control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b):attr(s)\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean, s = string"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_ASQ_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_asq_control); + control->request = 1; + control->source_attribute = talloc_strdup(control, attr); + control->src_attr_len = strlen(attr); + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "extended_dn:", 12) == 0) { + struct ldb_extended_dn_control *control; + const char *p; + int crit, type, ret; + + p = &(control_strings[i][12]); + ret = sscanf(p, "%d:%d", &crit, &type); + if ((ret != 2) || (crit < 0) || (crit > 1) || (type < 0) || (type > 1)) { + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + error_string = talloc_asprintf(mem_ctx, "invalid extended_dn control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b)[:type(i)]\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean\n"); + error_string = talloc_asprintf_append(error_string, " i = integer\n"); + error_string = talloc_asprintf_append(error_string, " valid values are: 0 - hexadecimal representation\n"); + error_string = talloc_asprintf_append(error_string, " 1 - normal string representation"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + control = NULL; + } else { + control = talloc(ctrl, struct ldb_extended_dn_control); + control->type = type; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_EXTENDED_DN_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = talloc_steal(ctrl[i], control); + + continue; + } + + if (strncmp(control_strings[i], "sd_flags:", 9) == 0) { + struct ldb_sd_flags_control *control; + const char *p; + int crit, ret; + unsigned secinfo_flags; + + p = &(control_strings[i][9]); + ret = sscanf(p, "%d:%u", &crit, &secinfo_flags); + if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags < 0) || (secinfo_flags > 0xF)) { + error_string = talloc_asprintf(mem_ctx, "invalid sd_flags control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b):secinfo_flags(n)\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_SD_FLAGS_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_sd_flags_control); + control->secinfo_flags = secinfo_flags; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "search_options:", 15) == 0) { + struct ldb_search_options_control *control; + const char *p; + int crit, ret; + unsigned search_options; + + p = &(control_strings[i][15]); + ret = sscanf(p, "%d:%u", &crit, &search_options); + if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options < 0) || (search_options > 0xF)) { + error_string = talloc_asprintf(mem_ctx, "invalid search_options control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b):search_options(n)\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_SEARCH_OPTIONS_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_search_options_control); + control->search_options = search_options; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "domain_scope:", 13) == 0) { + const char *p; + int crit, ret; + + p = &(control_strings[i][13]); + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + error_string = talloc_asprintf(mem_ctx, "invalid domain_scope control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_DOMAIN_SCOPE_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = NULL; + + continue; + } + + if (strncmp(control_strings[i], "paged_results:", 14) == 0) { + struct ldb_paged_control *control; + const char *p; + int crit, size, ret; + + p = &(control_strings[i][14]); + ret = sscanf(p, "%d:%d", &crit, &size); + + if ((ret != 2) || (crit < 0) || (crit > 1) || (size < 0)) { + error_string = talloc_asprintf(mem_ctx, "invalid paged_results control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b):size(n)\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_PAGED_RESULTS_OID; + ctrl[i]->critical = crit; + control = talloc(ctrl[i], struct ldb_paged_control); + control->size = size; + control->cookie = NULL; + control->cookie_len = 0; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "server_sort:", 12) == 0) { + struct ldb_server_sort_control **control; + const char *p; + char attr[256]; + char rule[128]; + int crit, rev, ret; + + attr[0] = '\0'; + rule[0] = '\0'; + p = &(control_strings[i][12]); + ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule); + if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') { + error_string = talloc_asprintf(mem_ctx, "invalid server_sort control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b):rev(b):attr(s)[:rule(s)]\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean, s = string"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_SERVER_SORT_OID; + ctrl[i]->critical = crit; + control = talloc_array(ctrl[i], struct ldb_server_sort_control *, 2); + control[0] = talloc(control, struct ldb_server_sort_control); + control[0]->attributeName = talloc_strdup(control, attr); + if (rule[0]) + control[0]->orderingRule = talloc_strdup(control, rule); + else + control[0]->orderingRule = NULL; + control[0]->reverse = rev; + control[1] = NULL; + ctrl[i]->data = control; + + continue; + } + + if (strncmp(control_strings[i], "notification:", 13) == 0) { + const char *p; + int crit, ret; + + p = &(control_strings[i][13]); + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + error_string = talloc_asprintf(mem_ctx, "invalid notification control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_NOTIFICATION_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = NULL; + + continue; + } + + if (strncmp(control_strings[i], "show_deleted:", 13) == 0) { + const char *p; + int crit, ret; + + p = &(control_strings[i][13]); + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + error_string = talloc_asprintf(mem_ctx, "invalid show_deleted control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_SHOW_DELETED_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = NULL; + + continue; + } + + if (strncmp(control_strings[i], "permissive_modify:", 18) == 0) { + const char *p; + int crit, ret; + + p = &(control_strings[i][18]); + ret = sscanf(p, "%d", &crit); + if ((ret != 1) || (crit < 0) || (crit > 1)) { + error_string = talloc_asprintf(mem_ctx, "invalid permissive_modify control syntax\n"); + error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n"); + error_string = talloc_asprintf_append(error_string, " note: b = boolean"); + ldb_set_errstring(ldb, error_string); + talloc_free(error_string); + return NULL; + } + + ctrl[i] = talloc(ctrl, struct ldb_control); + if (!ctrl[i]) { + ldb_oom(ldb); + return NULL; + } + ctrl[i]->oid = LDB_CONTROL_PERMISSIVE_MODIFY_OID; + ctrl[i]->critical = crit; + ctrl[i]->data = NULL; + + continue; + } + + /* no controls matched, throw an error */ + ldb_asprintf_errstring(ldb, "Invalid control name: '%s'", control_strings[i]); + return NULL; + } + + ctrl[i] = NULL; + + return ctrl; +} + + diff --git a/ldb/common/ldb_debug.c b/ldb/common/ldb_debug.c new file mode 100644 index 000000000..0f78e37c1 --- /dev/null +++ b/ldb/common/ldb_debug.c @@ -0,0 +1,103 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb debug + * + * Description: functions for printing debug messages + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" + +/* + this allows the user to choose their own debug function +*/ +int ldb_set_debug(struct ldb_context *ldb, + void (*debug)(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap), + void *context) +{ + ldb->debug_ops.debug = debug; + ldb->debug_ops.context = context; + return 0; +} + +/* + debug function for ldb_set_debug_stderr +*/ +static void ldb_debug_stderr(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); +static void ldb_debug_stderr(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap) +{ + if (level <= LDB_DEBUG_WARNING) { + vfprintf(stderr, fmt, ap); + } +} + +/* + convenience function to setup debug messages on stderr + messages of level LDB_DEBUG_WARNING and higher are printed +*/ +int ldb_set_debug_stderr(struct ldb_context *ldb) +{ + return ldb_set_debug(ldb, ldb_debug_stderr, ldb); +} + +/* + log a message +*/ +void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...) +{ + va_list ap; + if (ldb->debug_ops.debug == NULL) { + ldb_set_debug_stderr(ldb); + } + va_start(ap, fmt); + ldb->debug_ops.debug(ldb->debug_ops.context, level, fmt, ap); + va_end(ap); +} + + +/* + log a message, and set the ldb error string to the same message +*/ +void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level, + const char *fmt, ...) +{ + va_list ap; + char *msg; + va_start(ap, fmt); + msg = talloc_vasprintf(ldb, fmt, ap); + va_end(ap); + if (msg != NULL) { + ldb_set_errstring(ldb, msg); + ldb_debug(ldb, level, "%s", msg); + } + talloc_free(msg); +} + diff --git a/ldb/common/ldb_dn.c b/ldb/common/ldb_dn.c new file mode 100644 index 000000000..c0d36cfbf --- /dev/null +++ b/ldb/common/ldb_dn.c @@ -0,0 +1,1463 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb dn creation and manipulation utility functions + * + * Description: - explode a dn into it's own basic elements + * and put them in a structure (only if necessary) + * - manipulate ldb_dn structures + * + * Author: Simo Sorce + */ + +#include "ldb_includes.h" +#include + +#define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed + +#define LDB_FREE(x) do { talloc_free(x); x = NULL; } while(0) + +/** + internal ldb exploded dn structures +*/ +struct ldb_dn_component { + + char *name; + struct ldb_val value; + + char *cf_name; + struct ldb_val cf_value; +}; + +struct ldb_dn { + + struct ldb_context *ldb; + + /* Special DNs are always linearized */ + bool special; + bool invalid; + + bool valid_case; + + char *linearized; + char *casefold; + + unsigned int comp_num; + struct ldb_dn_component *components; + +}; + +/* strdn may be NULL */ +struct ldb_dn *ldb_dn_from_ldb_val(void *mem_ctx, struct ldb_context *ldb, const struct ldb_val *strdn) +{ + struct ldb_dn *dn; + + if (! ldb) return NULL; + + dn = talloc_zero(mem_ctx, struct ldb_dn); + LDB_DN_NULL_FAILED(dn); + + dn->ldb = ldb; + + if (strdn->data && strdn->length) { + if (strdn->data[0] == '@') { + dn->special = true; + } + if (strdn->length >= 6 && strncasecmp((const char *)strdn->data, "special = true; + /* FIXME: add a GUID string to ldb_dn structure */ + } else if (strdn->length >= 8 && strncasecmp((const char *)strdn->data, "special = true; + /* FIXME: add a SID string to ldb_dn structure */ + } else if (strdn->length >= 8 && strncasecmp((const char *)strdn->data, "special = true; + /* FIXME: add a WKGUID string to ldb_dn structure */ + } + dn->linearized = talloc_strndup(dn, (const char *)strdn->data, strdn->length); + } else { + dn->linearized = talloc_strdup(dn, ""); + } + LDB_DN_NULL_FAILED(dn->linearized); + + return dn; + +failed: + talloc_free(dn); + return NULL; +} + +/* strdn may be NULL */ +struct ldb_dn *ldb_dn_new(void *mem_ctx, struct ldb_context *ldb, const char *strdn) +{ + struct ldb_val blob; + blob.data = strdn; + blob.length = strdn ? strlen(strdn) : 0; + return ldb_dn_from_ldb_val(mem_ctx, ldb, &blob); +} + +struct ldb_dn *ldb_dn_new_fmt(void *mem_ctx, struct ldb_context *ldb, const char *new_fmt, ...) +{ + struct ldb_dn *dn; + char *strdn; + va_list ap; + + if ( (! mem_ctx) || (! ldb)) return NULL; + + dn = talloc_zero(mem_ctx, struct ldb_dn); + LDB_DN_NULL_FAILED(dn); + + dn->ldb = ldb; + + va_start(ap, new_fmt); + strdn = talloc_vasprintf(dn, new_fmt, ap); + va_end(ap); + LDB_DN_NULL_FAILED(strdn); + + if (strdn[0] == '@') { + dn->special = true; + } + if (strncasecmp(strdn, "special = true; + /* FIXME: add a GUID string to ldb_dn structure */ + } else if (strncasecmp(strdn, "special = true; + /* FIXME: add a SID string to ldb_dn structure */ + } else if (strncasecmp(strdn, "special = true; + /* FIXME: add a WKGUID string to ldb_dn structure */ + } + dn->linearized = strdn; + + return dn; + +failed: + talloc_free(dn); + return NULL; +} + +static int ldb_dn_escape_internal(char *dst, const char *src, int len) +{ + const char *p, *s; + char *d; + int l; + + p = s = src; + d = dst; + + while (p - src < len) { + + p += strcspn(p, ",=\n+<>#;\\\""); + + if (p - src == len) /* found no escapable chars */ + break; + + memcpy(d, s, p - s); /* copy the part of the string before the stop */ + d += (p - s); /* move to current position */ + + if (*p) { /* it is a normal escapable character */ + *d++ = '\\'; + *d++ = *p++; + } else { /* we have a zero byte in the string */ + strncpy(d, "\00", 3); /* escape the zero */ + d += 3; + p++; /* skip the zero */ + } + s = p; /* move forward */ + } + + /* copy the last part (with zero) and return */ + l = len - (s - src); + memcpy(d, s, l + 1); + + /* return the length of the resulting string */ + return (l + (d - dst)); +} + +char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value) +{ + char *dst; + + if (!value.length) + return NULL; + + /* allocate destination string, it will be at most 3 times the source */ + dst = talloc_array(mem_ctx, char, value.length * 3 + 1); + if ( ! dst) { + talloc_free(dst); + return NULL; + } + + ldb_dn_escape_internal(dst, (const char *)value.data, value.length); + + dst = talloc_realloc(mem_ctx, dst, char, strlen(dst) + 1); + + return dst; +} + +/* + explode a DN string into a ldb_dn structure + based on RFC4514 except that we don't support multiple valued RDNs +*/ +static bool ldb_dn_explode(struct ldb_dn *dn) +{ + char *p, *data, *d, *dt, *t; + bool trim = false; + bool in_attr = false; + bool in_value = false; + bool in_quote = false; + bool is_oid = false; + bool escape = false; + unsigned x; + int l; + + if ( ! dn || dn->invalid) return false; + + if (dn->components) { + return true; + } + + if ( ! dn->linearized) { + return false; + } + + /* Empty DNs */ + if (dn->linearized[0] == '\0') { + return true; + } + + /* Special DNs case */ + if (dn->special) { + return true; + } + + /* make sure we free this if alloced previously before replacing */ + talloc_free(dn->components); + + /* in the common case we have 3 or more components */ + /* make sure all components are zeroed, other functions depend on this */ + dn->components = talloc_zero_array(dn, struct ldb_dn_component, 3); + if ( ! dn->components) { + return false; + } + dn->comp_num = 0; + + /* Components data space is allocated here once */ + data = talloc_array(dn->components, char, strlen(dn->linearized) + 1); + if (!data) { + return false; + } + + p = dn->linearized; + in_attr = true; + trim = true; + t = NULL; + d = dt = data; + + while (*p) { + + if (in_attr) { + if (trim) { + if (*p == ' ') { + p++; + continue; + } + + /* first char */ + trim = false; + + if (!isascii(*p)) { + /* attr names must be ascii only */ + dn->invalid = true; + goto failed; + } + + if (isdigit(*p)) { + is_oid = true; + } else + if ( ! isalpha(*p)) { + /* not a digit nor an alpha, invalid attribute name */ + dn->invalid = true; + goto failed; + } + + *d++ = *p++; + continue; + } + + if (*p == ' ') { + p++; + /* valid only if we are at the end */ + trim = true; + continue; + } + + if (trim && (*p != '=')) { + /* spaces/tabs are not allowed in attribute names */ + dn->invalid = true; + goto failed; + } + + if (*p == '=') { + /* attribute terminated */ + in_attr = false; + in_value = true; + trim = true; + l = 0; + + *d++ = '\0'; + dn->components[dn->comp_num].name = talloc_strdup(dn->components, dt); + if ( ! dn->components[dn->comp_num].name) { + /* ouch */ + goto failed; + } + + dt = d; + + p++; + continue; + } + + if (!isascii(*p)) { + /* attr names must be ascii only */ + dn->invalid = true; + goto failed; + } + + if (is_oid && ( ! (isdigit(*p) || (*p == '.')))) { + /* not a digit nor a dot, invalid attribute oid */ + dn->invalid = true; + goto failed; + } else + if ( ! (isalpha(*p) || isdigit(*p) || (*p == '-'))) { + /* not ALPHA, DIGIT or HYPHEN */ + dn->invalid = true; + goto failed; + } + + *d++ = *p++; + continue; + } + + if (in_value) { + if (in_quote) { + if (*p == '\"') { + if (p[-1] != '\\') { + p++; + in_quote = false; + continue; + } + } + *d++ = *p++; + l++; + continue; + } + + if (trim) { + if (*p == ' ') { + p++; + continue; + } + + /* first char */ + trim = false; + + if (*p == '\"') { + in_quote = true; + p++; + continue; + } + } + + switch (*p) { + + /* TODO: support ber encoded values + case '#': + */ + + case ',': + if (escape) { + *d++ = *p++; + l++; + escape = false; + continue; + } + /* ok found value terminator */ + + if ( t ) { + /* trim back */ + d -= (p - t); + l -= (p - t); + } + + in_attr = true; + in_value = false; + trim = true; + + p++; + *d++ = '\0'; + dn->components[dn->comp_num].value.data = (uint8_t *)talloc_strdup(dn->components, dt); + dn->components[dn->comp_num].value.length = l; + if ( ! dn->components[dn->comp_num].value.data) { + /* ouch ! */ + goto failed; + } + + dt = d; + + dn->comp_num++; + if (dn->comp_num > 2) { + dn->components = talloc_realloc(dn, + dn->components, + struct ldb_dn_component, + dn->comp_num + 1); + if ( ! dn->components) { + /* ouch ! */ + goto failed; + } + /* make sure all components are zeroed, other functions depend on this */ + memset(&dn->components[dn->comp_num], '\0', sizeof(struct ldb_dn_component)); + } + + continue; + + case '=': + case '\n': + case '+': + case '<': + case '>': + case '#': + case ';': + case '\"': + /* a string with not escaped specials is invalid (tested) */ + if ( ! escape) { + dn->invalid = true; + goto failed; + } + escape = false; + + *d++ = *p++; + l++; + + if ( t ) t = NULL; + break; + + case '\\': + if ( ! escape) { + escape = true; + p++; + continue; + } + escape = false; + + *d++ = *p++; + l++; + + if ( t ) t = NULL; + break; + + default: + if (escape) { + if (sscanf(p, "%02x", &x) != 1) { + /* invalid escaping sequence */ + dn->invalid = true; + goto failed; + } + escape = false; + + p += 2; + *d++ = (unsigned char)x; + l++; + + if ( t ) t = NULL; + break; + } + + if (*p == ' ') { + if ( ! t) t = p; + } else { + if ( t ) t = NULL; + } + + *d++ = *p++; + l++; + + break; + } + + } + } + + if (in_attr || in_quote) { + /* invalid dn */ + dn->invalid = true; + goto failed; + } + + /* save last element */ + if ( t ) { + /* trim back */ + d -= (p - t); + l -= (p - t); + } + + *d++ = '\0'; + dn->components[dn->comp_num].value.data = (uint8_t *)talloc_strdup(dn->components, dt); + dn->components[dn->comp_num].value.length = l; + + if ( ! dn->components[dn->comp_num].value.data) { + /* ouch */ + goto failed; + } + + dn->comp_num++; + + talloc_free(data); + return true; + +failed: + dn->comp_num = 0; + talloc_free(dn->components); + return false; +} + +bool ldb_dn_validate(struct ldb_dn *dn) +{ + return ldb_dn_explode(dn); +} + +const char *ldb_dn_get_linearized(struct ldb_dn *dn) +{ + int i, len; + char *d, *n; + + if ( ! dn || ( dn->invalid)) return NULL; + + if (dn->linearized) return dn->linearized; + + if ( ! dn->components) { + dn->invalid = true; + return NULL; + } + + if (dn->comp_num == 0) { + dn->linearized = talloc_strdup(dn, ""); + if ( ! dn->linearized) return NULL; + return dn->linearized; + } + + /* calculate maximum possible length of DN */ + for (len = 0, i = 0; i < dn->comp_num; i++) { + len += strlen(dn->components[i].name); /* name len */ + len += (dn->components[i].value.length * 3); /* max escaped data len */ + len += 2; /* '=' and ',' */ + } + dn->linearized = talloc_array(dn, char, len); + if ( ! dn->linearized) return NULL; + + d = dn->linearized; + + for (i = 0; i < dn->comp_num; i++) { + + /* copy the name */ + n = dn->components[i].name; + while (*n) *d++ = *n++; + + *d++ = '='; + + /* and the value */ + d += ldb_dn_escape_internal( d, + (char *)dn->components[i].value.data, + dn->components[i].value.length); + *d++ = ','; + } + + *(--d) = '\0'; + + /* don't waste more memory than necessary */ + dn->linearized = talloc_realloc(dn, dn->linearized, char, (d - dn->linearized + 1)); + + return dn->linearized; +} + +char *ldb_dn_alloc_linearized(void *mem_ctx, struct ldb_dn *dn) +{ + return talloc_strdup(mem_ctx, ldb_dn_get_linearized(dn)); +} + +/* + casefold a dn. We need to casefold the attribute names, and canonicalize + attribute values of case insensitive attributes. +*/ + +static bool ldb_dn_casefold_internal(struct ldb_dn *dn) +{ + int i, ret; + + if ( ! dn || dn->invalid) return false; + + if (dn->valid_case) return true; + + if (( ! dn->components) && ( ! ldb_dn_explode(dn))) { + return false; + } + + for (i = 0; i < dn->comp_num; i++) { + const struct ldb_schema_attribute *a; + + dn->components[i].cf_name = ldb_attr_casefold(dn->components, dn->components[i].name); + if (!dn->components[i].cf_name) { + goto failed; + } + + a = ldb_schema_attribute_by_name(dn->ldb, dn->components[i].cf_name); + ret = a->syntax->canonicalise_fn(dn->ldb, dn->components, + &(dn->components[i].value), + &(dn->components[i].cf_value)); + if (ret != 0) { + goto failed; + } + } + + dn->valid_case = true; + + return true; + +failed: + for (i = 0; i < dn->comp_num; i++) { + LDB_FREE(dn->components[i].cf_name); + LDB_FREE(dn->components[i].cf_value.data); + } + return false; +} + +const char *ldb_dn_get_casefold(struct ldb_dn *dn) +{ + int i, len; + char *d, *n; + + if (dn->casefold) return dn->casefold; + + if (dn->special) { + dn->casefold = talloc_strdup(dn, dn->linearized); + if (!dn->casefold) return NULL; + dn->valid_case = true; + return dn->casefold; + } + + if ( ! ldb_dn_casefold_internal(dn)) { + return NULL; + } + + if (dn->comp_num == 0) { + if (dn->linearized && dn->linearized[0] == '\0') { + /* hmm a NULL dn, should we faild casefolding ? */ + dn->casefold = talloc_strdup(dn, ""); + return dn->casefold; + } + /* A DN must be NULL, special, or have components */ + dn->invalid = true; + return NULL; + } + + /* calculate maximum possible length of DN */ + for (len = 0, i = 0; i < dn->comp_num; i++) { + len += strlen(dn->components[i].cf_name); /* name len */ + len += (dn->components[i].cf_value.length * 3); /* max escaped data len */ + len += 2; /* '=' and ',' */ + } + dn->casefold = talloc_array(dn, char, len); + if ( ! dn->casefold) return NULL; + + d = dn->casefold; + + for (i = 0; i < dn->comp_num; i++) { + + /* copy the name */ + n = dn->components[i].cf_name; + while (*n) *d++ = *n++; + + *d++ = '='; + + /* and the value */ + d += ldb_dn_escape_internal( d, + (char *)dn->components[i].cf_value.data, + dn->components[i].cf_value.length); + *d++ = ','; + } + *(--d) = '\0'; + + /* don't waste more memory than necessary */ + dn->casefold = talloc_realloc(dn, dn->casefold, char, strlen(dn->casefold) + 1); + + return dn->casefold; +} + +char *ldb_dn_alloc_casefold(void *mem_ctx, struct ldb_dn *dn) +{ + return talloc_strdup(mem_ctx, ldb_dn_get_casefold(dn)); +} + +/* Determine if dn is below base, in the ldap tree. Used for + * evaluating a subtree search. + * 0 if they match, otherwise non-zero + */ + +int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn) +{ + int ret; + int n_base, n_dn; + + if ( ! base || base->invalid) return 1; + if ( ! dn || dn->invalid) return -1; + + if (( ! base->valid_case) || ( ! dn->valid_case)) { + if (base->linearized && dn->linearized) { + /* try with a normal compare first, if we are lucky + * we will avoid exploding and casfolding */ + int dif; + dif = strlen(dn->linearized) - strlen(base->linearized); + if (dif < 0) return dif; + if (strcmp(base->linearized, &dn->linearized[dif]) == 0) return 0; + } + + if ( ! ldb_dn_casefold_internal(base)) { + return 1; + } + + if ( ! ldb_dn_casefold_internal(dn)) { + return -1; + } + + } + + /* if base has more components, + * they don't have the same base */ + if (base->comp_num > dn->comp_num) { + return (dn->comp_num - base->comp_num); + } + + if (dn->comp_num == 0) { + if (dn->special && base->special) { + return strcmp(base->linearized, dn->linearized); + } else if (dn->special) { + return -1; + } else if (base->special) { + return 1; + } else { + return 0; + } + } + + n_base = base->comp_num - 1; + n_dn = dn->comp_num - 1; + + while (n_base >= 0) { + /* compare attr names */ + ret = strcmp(base->components[n_base].cf_name, dn->components[n_dn].cf_name); + if (ret != 0) return ret; + + /* compare attr.cf_value. */ + if (base->components[n_base].cf_value.length != dn->components[n_dn].cf_value.length) { + return base->components[n_base].cf_value.length - dn->components[n_dn].cf_value.length; + } + ret = strcmp((char *)base->components[n_base].cf_value.data, (char *)dn->components[n_dn].cf_value.data); + if (ret != 0) return ret; + + n_base--; + n_dn--; + } + + return 0; +} + +/* compare DNs using casefolding compare functions. + + If they match, then return 0 + */ + +int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1) +{ + int i, ret; + + if (( ! dn0) || dn0->invalid || ! dn1 || dn1->invalid) return -1; + + if (( ! dn0->valid_case) || ( ! dn1->valid_case)) { + if (dn0->linearized && dn1->linearized) { + /* try with a normal compare first, if we are lucky + * we will avoid exploding and casfolding */ + if (strcmp(dn0->linearized, dn1->linearized) == 0) return 0; + } + + if ( ! ldb_dn_casefold_internal(dn0)) { + return 1; + } + + if ( ! ldb_dn_casefold_internal(dn1)) { + return -1; + } + + } + + if (dn0->comp_num != dn1->comp_num) { + return (dn1->comp_num - dn0->comp_num); + } + + if (dn0->comp_num == 0) { + if (dn0->special && dn1->special) { + return strcmp(dn0->linearized, dn1->linearized); + } else if (dn0->special) { + return 1; + } else if (dn1->special) { + return -1; + } else { + return 0; + } + } + + for (i = 0; i < dn0->comp_num; i++) { + /* compare attr names */ + ret = strcmp(dn0->components[i].cf_name, dn1->components[i].cf_name); + if (ret != 0) return ret; + + /* compare attr.cf_value. */ + if (dn0->components[i].cf_value.length != dn1->components[i].cf_value.length) { + return dn0->components[i].cf_value.length - dn1->components[i].cf_value.length; + } + ret = strcmp((char *)dn0->components[i].cf_value.data, (char *)dn1->components[i].cf_value.data); + if (ret != 0) return ret; + } + + return 0; +} + +static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_dn_component *src) +{ + struct ldb_dn_component dst; + + memset(&dst, 0, sizeof(dst)); + + if (src == NULL) { + return dst; + } + + dst.value = ldb_val_dup(mem_ctx, &(src->value)); + if (dst.value.data == NULL) { + return dst; + } + + dst.name = talloc_strdup(mem_ctx, src->name); + if (dst.name == NULL) { + LDB_FREE(dst.value.data); + return dst; + } + + if (src->cf_value.data) { + dst.cf_value = ldb_val_dup(mem_ctx, &(src->cf_value)); + if (dst.cf_value.data == NULL) { + LDB_FREE(dst.value.data); + LDB_FREE(dst.name); + return dst; + } + + dst.cf_name = talloc_strdup(mem_ctx, src->cf_name); + if (dst.cf_name == NULL) { + LDB_FREE(dst.cf_name); + LDB_FREE(dst.value.data); + LDB_FREE(dst.name); + return dst; + } + } else { + dst.cf_value.data = NULL; + dst.cf_name = NULL; + } + + return dst; +} + +struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn) +{ + struct ldb_dn *new_dn; + + if (!dn || dn->invalid) { + return NULL; + } + + new_dn = talloc_zero(mem_ctx, struct ldb_dn); + if ( !new_dn) { + return NULL; + } + + *new_dn = *dn; + + if (dn->components) { + int i; + + new_dn->components = talloc_zero_array(new_dn, struct ldb_dn_component, dn->comp_num); + if ( ! new_dn->components) { + talloc_free(new_dn); + return NULL; + } + + for (i = 0; i < dn->comp_num; i++) { + new_dn->components[i] = ldb_dn_copy_component(new_dn->components, &dn->components[i]); + if ( ! new_dn->components[i].value.data) { + talloc_free(new_dn); + return NULL; + } + } + } + + if (dn->casefold) { + new_dn->casefold = talloc_strdup(new_dn, dn->casefold); + if ( ! new_dn->casefold) { + talloc_free(new_dn); + return NULL; + } + } + + if (dn->linearized) { + new_dn->linearized = talloc_strdup(new_dn, dn->linearized); + if ( ! new_dn->linearized) { + talloc_free(new_dn); + return NULL; + } + } + + return new_dn; +} + +/* modify the given dn by adding a base. + * + * return true if successful and false if not + * if false is returned the dn may be marked invalid + */ +bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base) +{ + const char *s; + char *t; + + if ( !base || base->invalid || !dn || dn->invalid) { + return false; + } + + if (dn->components) { + int i; + + if ( ! ldb_dn_validate(base)) { + return false; + } + + s = NULL; + if (dn->valid_case) { + if ( ! (s = ldb_dn_get_casefold(base))) { + return false; + } + } + + dn->components = talloc_realloc(dn, + dn->components, + struct ldb_dn_component, + dn->comp_num + base->comp_num); + if ( ! dn->components) { + dn->invalid = true; + return false; + } + + for (i = 0; i < base->comp_num; dn->comp_num++, i++) { + dn->components[dn->comp_num] = ldb_dn_copy_component(dn->components, &base->components[i]); + if (dn->components[dn->comp_num].value.data == NULL) { + dn->invalid = true; + return false; + } + } + + if (dn->casefold && s) { + if (*dn->casefold) { + t = talloc_asprintf(dn, "%s,%s", dn->casefold, s); + } else { + t = talloc_strdup(dn, s); + } + LDB_FREE(dn->casefold); + dn->casefold = t; + } + } + + if (dn->linearized) { + + s = ldb_dn_get_linearized(base); + if ( ! s) { + return false; + } + + if (*dn->linearized) { + t = talloc_asprintf(dn, "%s,%s", dn->linearized, s); + } else { + t = talloc_strdup(dn, s); + } + if ( ! t) { + dn->invalid = true; + return false; + } + LDB_FREE(dn->linearized); + dn->linearized = t; + } + + return true; +} + +/* modify the given dn by adding a base. + * + * return true if successful and false if not + * if false is returned the dn may be marked invalid + */ +bool ldb_dn_add_base_fmt(struct ldb_dn *dn, const char *base_fmt, ...) +{ + struct ldb_dn *base; + char *base_str; + va_list ap; + bool ret; + + if ( !dn || dn->invalid) { + return false; + } + + va_start(ap, base_fmt); + base_str = talloc_vasprintf(dn, base_fmt, ap); + va_end(ap); + + if (base_str == NULL) { + return false; + } + + base = ldb_dn_new(base_str, dn->ldb, base_str); + + ret = ldb_dn_add_base(dn, base); + + talloc_free(base_str); + + return ret; +} + +/* modify the given dn by adding children elements. + * + * return true if successful and false if not + * if false is returned the dn may be marked invalid + */ +bool ldb_dn_add_child(struct ldb_dn *dn, struct ldb_dn *child) +{ + const char *s; + char *t; + + if ( !child || child->invalid || !dn || dn->invalid) { + return false; + } + + if (dn->components) { + int n, i, j; + + if ( ! ldb_dn_validate(child)) { + return false; + } + + s = NULL; + if (dn->valid_case) { + if ( ! (s = ldb_dn_get_casefold(child))) { + return false; + } + } + + n = dn->comp_num + child->comp_num; + + dn->components = talloc_realloc(dn, + dn->components, + struct ldb_dn_component, + n); + if ( ! dn->components) { + dn->invalid = true; + return false; + } + + for (i = dn->comp_num - 1, j = n - 1; i >= 0; i--, j--) { + dn->components[j] = dn->components[i]; + } + + for (i = 0; i < child->comp_num; i++) { + dn->components[i] = ldb_dn_copy_component(dn->components, &child->components[i]); + if (dn->components[i].value.data == NULL) { + dn->invalid = true; + return false; + } + } + + dn->comp_num = n; + + if (dn->casefold && s) { + t = talloc_asprintf(dn, "%s,%s", s, dn->casefold); + LDB_FREE(dn->casefold); + dn->casefold = t; + } + } + + if (dn->linearized) { + + s = ldb_dn_get_linearized(child); + if ( ! s) { + return false; + } + + t = talloc_asprintf(dn, "%s,%s", s, dn->linearized); + if ( ! t) { + dn->invalid = true; + return false; + } + LDB_FREE(dn->linearized); + dn->linearized = t; + } + + return true; +} + +/* modify the given dn by adding children elements. + * + * return true if successful and false if not + * if false is returned the dn may be marked invalid + */ +bool ldb_dn_add_child_fmt(struct ldb_dn *dn, const char *child_fmt, ...) +{ + struct ldb_dn *child; + char *child_str; + va_list ap; + bool ret; + + if ( !dn || dn->invalid) { + return false; + } + + va_start(ap, child_fmt); + child_str = talloc_vasprintf(dn, child_fmt, ap); + va_end(ap); + + if (child_str == NULL) { + return false; + } + + child = ldb_dn_new(child_str, dn->ldb, child_str); + + ret = ldb_dn_add_child(dn, child); + + talloc_free(child_str); + + return ret; +} + +bool ldb_dn_remove_base_components(struct ldb_dn *dn, unsigned int num) +{ + int i; + + if ( ! ldb_dn_validate(dn)) { + return false; + } + + if (dn->comp_num < num) { + return false; + } + + /* free components */ + for (i = num; i > 0; i--) { + LDB_FREE(dn->components[dn->comp_num - i].name); + LDB_FREE(dn->components[dn->comp_num - i].value.data); + LDB_FREE(dn->components[dn->comp_num - i].cf_name); + LDB_FREE(dn->components[dn->comp_num - i].cf_value.data); + } + + dn->comp_num -= num; + + if (dn->valid_case) { + for (i = 0; i < dn->comp_num; i++) { + LDB_FREE(dn->components[i].cf_name); + LDB_FREE(dn->components[i].cf_value.data); + } + dn->valid_case = false; + } + + LDB_FREE(dn->casefold); + LDB_FREE(dn->linearized); + + return true; +} + +bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num) +{ + int i, j; + + if ( ! ldb_dn_validate(dn)) { + return false; + } + + if (dn->comp_num < num) { + return false; + } + + for (i = 0, j = num; j < dn->comp_num; i++, j++) { + if (i < num) { + LDB_FREE(dn->components[i].name); + LDB_FREE(dn->components[i].value.data); + LDB_FREE(dn->components[i].cf_name); + LDB_FREE(dn->components[i].cf_value.data); + } + dn->components[i] = dn->components[j]; + } + + dn->comp_num -= num; + + if (dn->valid_case) { + for (i = 0; i < dn->comp_num; i++) { + LDB_FREE(dn->components[i].cf_name); + LDB_FREE(dn->components[i].cf_value.data); + } + dn->valid_case = false; + } + + LDB_FREE(dn->casefold); + LDB_FREE(dn->linearized); + + return true; +} + +struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, struct ldb_dn *dn) +{ + struct ldb_dn *new_dn; + + new_dn = ldb_dn_copy(mem_ctx, dn); + if ( !new_dn ) { + return NULL; + } + + if ( ! ldb_dn_remove_child_components(new_dn, 1)) { + talloc_free(new_dn); + return NULL; + } + + return new_dn; +} + +/* Create a 'canonical name' string from a DN: + + ie dc=samba,dc=org -> samba.org/ + uid=administrator,ou=users,dc=samba,dc=org = samba.org/users/administrator + + There are two formats, the EX format has the last / replaced with a newline (\n). + +*/ +static char *ldb_dn_canonical(void *mem_ctx, struct ldb_dn *dn, int ex_format) { + int i; + TALLOC_CTX *tmpctx; + char *cracked = NULL; + const char *format = (ex_format ? "\n" : "/" ); + + if ( ! ldb_dn_validate(dn)) { + return NULL; + } + + tmpctx = talloc_new(mem_ctx); + + /* Walk backwards down the DN, grabbing 'dc' components at first */ + for (i = dn->comp_num - 1 ; i >= 0; i--) { + if (ldb_attr_cmp(dn->components[i].name, "dc") != 0) { + break; + } + if (cracked) { + cracked = talloc_asprintf(tmpctx, "%s.%s", + ldb_dn_escape_value(tmpctx, dn->components[i].value), + cracked); + } else { + cracked = ldb_dn_escape_value(tmpctx, dn->components[i].value); + } + if (!cracked) { + goto done; + } + } + + /* Only domain components? Finish here */ + if (i < 0) { + cracked = talloc_strdup_append_buffer(cracked, format); + talloc_steal(mem_ctx, cracked); + goto done; + } + + /* Now walk backwards appending remaining components */ + for (; i > 0; i--) { + cracked = talloc_asprintf_append_buffer(cracked, "/%s", + ldb_dn_escape_value(tmpctx, dn->components[i].value)); + if (!cracked) { + goto done; + } + } + + /* Last one, possibly a newline for the 'ex' format */ + cracked = talloc_asprintf_append_buffer(cracked, "%s%s", format, + ldb_dn_escape_value(tmpctx, dn->components[i].value)); + + talloc_steal(mem_ctx, cracked); +done: + talloc_free(tmpctx); + return cracked; +} + +/* Wrapper functions for the above, for the two different string formats */ +char *ldb_dn_canonical_string(void *mem_ctx, struct ldb_dn *dn) { + return ldb_dn_canonical(mem_ctx, dn, 0); + +} + +char *ldb_dn_canonical_ex_string(void *mem_ctx, struct ldb_dn *dn) { + return ldb_dn_canonical(mem_ctx, dn, 1); +} + +int ldb_dn_get_comp_num(struct ldb_dn *dn) +{ + if ( ! ldb_dn_validate(dn)) { + return -1; + } + return dn->comp_num; +} + +const char *ldb_dn_get_component_name(struct ldb_dn *dn, unsigned int num) +{ + if ( ! ldb_dn_validate(dn)) { + return NULL; + } + if (num >= dn->comp_num) return NULL; + return dn->components[num].name; +} + +const struct ldb_val *ldb_dn_get_component_val(struct ldb_dn *dn, unsigned int num) +{ + if ( ! ldb_dn_validate(dn)) { + return NULL; + } + if (num >= dn->comp_num) return NULL; + return &dn->components[num].value; +} + +const char *ldb_dn_get_rdn_name(struct ldb_dn *dn) +{ + if ( ! ldb_dn_validate(dn)) { + return NULL; + } + if (dn->comp_num == 0) return NULL; + return dn->components[0].name; +} + +const struct ldb_val *ldb_dn_get_rdn_val(struct ldb_dn *dn) +{ + if ( ! ldb_dn_validate(dn)) { + return NULL; + } + if (dn->comp_num == 0) return NULL; + return &dn->components[0].value; +} + +int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val) +{ + char *n; + struct ldb_val v; + + if ( ! ldb_dn_validate(dn)) { + return LDB_ERR_OTHER; + } + + if (num >= dn->comp_num) { + return LDB_ERR_OTHER; + } + + n = talloc_strdup(dn, name); + if ( ! n) { + return LDB_ERR_OTHER; + } + + v.length = val.length; + v.data = (uint8_t *)talloc_memdup(dn, val.data, v.length+1); + if ( ! v.data) { + talloc_free(n); + return LDB_ERR_OTHER; + } + + talloc_free(dn->components[num].name); + talloc_free(dn->components[num].value.data); + dn->components[num].name = n; + dn->components[num].value = v; + + if (dn->valid_case) { + int i; + for (i = 0; i < dn->comp_num; i++) { + LDB_FREE(dn->components[i].cf_name); + LDB_FREE(dn->components[i].cf_value.data); + } + dn->valid_case = false; + } + LDB_FREE(dn->casefold); + LDB_FREE(dn->linearized); + + return LDB_SUCCESS; +} + +bool ldb_dn_is_valid(struct ldb_dn *dn) +{ + if ( ! dn) return false; + return ! dn->invalid; +} + +bool ldb_dn_is_special(struct ldb_dn *dn) +{ + if ( ! dn || dn->invalid) return false; + return dn->special; +} + +bool ldb_dn_check_special(struct ldb_dn *dn, const char *check) +{ + if ( ! dn || dn->invalid) return false; + return ! strcmp(dn->linearized, check); +} + +bool ldb_dn_is_null(struct ldb_dn *dn) +{ + if ( ! dn || dn->invalid) return false; + if (dn->linearized && (dn->linearized[0] == '\0')) return true; + return false; +} diff --git a/ldb/common/ldb_ldif.c b/ldb/common/ldb_ldif.c new file mode 100644 index 000000000..fb93e17c6 --- /dev/null +++ b/ldb/common/ldb_ldif.c @@ -0,0 +1,757 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldif routines + * + * Description: ldif pack/unpack routines + * + * Author: Andrew Tridgell + */ + +/* + see RFC2849 for the LDIF format definition +*/ + +#include "ldb_includes.h" +#include "system/locale.h" + +/* + +*/ +static int ldb_read_data_file(void *mem_ctx, struct ldb_val *value) +{ + struct stat statbuf; + char *buf; + int count, size, bytes; + int ret; + int f; + const char *fname = (const char *)value->data; + + if (strncmp(fname, "file://", 7) != 0) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + fname += 7; + + f = open(fname, O_RDONLY); + if (f == -1) { + return -1; + } + + if (fstat(f, &statbuf) != 0) { + ret = -1; + goto done; + } + + if (statbuf.st_size == 0) { + ret = -1; + goto done; + } + + value->data = (uint8_t *)talloc_size(mem_ctx, statbuf.st_size + 1); + if (value->data == NULL) { + ret = -1; + goto done; + } + value->data[statbuf.st_size] = 0; + + count = 0; + size = statbuf.st_size; + buf = (char *)value->data; + while (count < statbuf.st_size) { + bytes = read(f, buf, size); + if (bytes == -1) { + talloc_free(value->data); + ret = -1; + goto done; + } + count += bytes; + buf += bytes; + size -= bytes; + } + + value->length = statbuf.st_size; + ret = statbuf.st_size; + +done: + close(f); + return ret; +} + +/* + this base64 decoder was taken from jitterbug (written by tridge). + we might need to replace it with a new version +*/ +int ldb_base64_decode(char *s) +{ + const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int bit_offset=0, byte_offset, idx, i, n; + uint8_t *d = (uint8_t *)s; + char *p=NULL; + + n=i=0; + + while (*s && (p=strchr(b64,*s))) { + idx = (int)(p - b64); + byte_offset = (i*6)/8; + bit_offset = (i*6)%8; + d[byte_offset] &= ~((1<<(8-bit_offset))-1); + if (bit_offset < 3) { + d[byte_offset] |= (idx << (2-bit_offset)); + n = byte_offset+1; + } else { + d[byte_offset] |= (idx >> (bit_offset-2)); + d[byte_offset+1] = 0; + d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF; + n = byte_offset+2; + } + s++; i++; + } + if (bit_offset >= 3) { + n--; + } + + if (*s && !p) { + /* the only termination allowed */ + if (*s != '=') { + return -1; + } + } + + /* null terminate */ + d[n] = 0; + return n; +} + + +/* + encode as base64 + caller frees +*/ +char *ldb_base64_encode(void *mem_ctx, const char *buf, int len) +{ + const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int bit_offset, byte_offset, idx, i; + const uint8_t *d = (const uint8_t *)buf; + int bytes = (len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0; + char *out; + + out = talloc_array(mem_ctx, char, bytes+pad_bytes+1); + if (!out) return NULL; + + for (i=0;i> (2-bit_offset)) & 0x3F; + } else { + idx = (d[byte_offset] << (bit_offset-2)) & 0x3F; + if (byte_offset+1 < len) { + idx |= (d[byte_offset+1] >> (8-(bit_offset-2))); + } + } + out[i] = b64[idx]; + } + + for (;idata; + + if (val->length == 0) { + return 0; + } + + if (p[0] == ' ' || p[0] == ':') { + return 1; + } + + for (i=0; ilength; i++) { + if (!isprint(p[i]) || p[i] == '\n') { + return 1; + } + } + return 0; +} + +/* this macro is used to handle the return checking on fprintf_fn() */ +#define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0) + +/* + write a line folded string onto a file +*/ +static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private_data, + const char *buf, size_t length, int start_pos) +{ + unsigned int i; + int total=0, ret; + + for (i=0;imsg; + + ret = fprintf_fn(private_data, "dn: %s\n", ldb_dn_get_linearized(msg->dn)); + CHECK_RET; + + if (ldif->changetype != LDB_CHANGETYPE_NONE) { + for (i=0;ldb_changetypes[i].name;i++) { + if (ldb_changetypes[i].changetype == ldif->changetype) { + break; + } + } + if (!ldb_changetypes[i].name) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Invalid ldif changetype %d\n", + ldif->changetype); + talloc_free(mem_ctx); + return -1; + } + ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name); + CHECK_RET; + } + + for (i=0;inum_elements;i++) { + const struct ldb_schema_attribute *a; + + a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name); + + if (ldif->changetype == LDB_CHANGETYPE_MODIFY) { + switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) { + case LDB_FLAG_MOD_ADD: + fprintf_fn(private_data, "add: %s\n", + msg->elements[i].name); + break; + case LDB_FLAG_MOD_DELETE: + fprintf_fn(private_data, "delete: %s\n", + msg->elements[i].name); + break; + case LDB_FLAG_MOD_REPLACE: + fprintf_fn(private_data, "replace: %s\n", + msg->elements[i].name); + break; + } + } + + for (j=0;jelements[i].num_values;j++) { + struct ldb_val v; + ret = a->syntax->ldif_write_fn(ldb, mem_ctx, &msg->elements[i].values[j], &v); + CHECK_RET; + if (ldb_should_b64_encode(&v)) { + ret = fprintf_fn(private_data, "%s:: ", + msg->elements[i].name); + CHECK_RET; + ret = base64_encode_f(ldb, fprintf_fn, private_data, + (char *)v.data, v.length, + strlen(msg->elements[i].name)+3); + CHECK_RET; + ret = fprintf_fn(private_data, "\n"); + CHECK_RET; + } else { + ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name); + CHECK_RET; + ret = fold_string(fprintf_fn, private_data, + (char *)v.data, v.length, + strlen(msg->elements[i].name)+2); + CHECK_RET; + ret = fprintf_fn(private_data, "\n"); + CHECK_RET; + } + if (v.data != msg->elements[i].values[j].data) { + talloc_free(v.data); + } + } + if (ldif->changetype == LDB_CHANGETYPE_MODIFY) { + fprintf_fn(private_data, "-\n"); + } + } + ret = fprintf_fn(private_data,"\n"); + CHECK_RET; + + return total; +} + +#undef CHECK_RET + + +/* + pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF + this routine removes any RFC2849 continuations and comments + + caller frees +*/ +static char *next_chunk(struct ldb_context *ldb, + int (*fgetc_fn)(void *), void *private_data) +{ + size_t alloc_size=0, chunk_size = 0; + char *chunk = NULL; + int c; + int in_comment = 0; + + while ((c = fgetc_fn(private_data)) != EOF) { + if (chunk_size+1 >= alloc_size) { + char *c2; + alloc_size += 1024; + c2 = talloc_realloc(ldb, chunk, char, alloc_size); + if (!c2) { + talloc_free(chunk); + errno = ENOMEM; + return NULL; + } + chunk = c2; + } + + if (in_comment) { + if (c == '\n') { + in_comment = 0; + } + continue; + } + + /* handle continuation lines - see RFC2849 */ + if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') { + chunk_size--; + continue; + } + + /* chunks are terminated by a double line-feed */ + if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') { + chunk[chunk_size-1] = 0; + return chunk; + } + + if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) { + in_comment = 1; + continue; + } + + /* ignore leading blank lines */ + if (chunk_size == 0 && c == '\n') { + continue; + } + + chunk[chunk_size++] = c; + } + + if (chunk) { + chunk[chunk_size] = 0; + } + + return chunk; +} + + +/* simple ldif attribute parser */ +static int next_attr(void *mem_ctx, char **s, const char **attr, struct ldb_val *value) +{ + char *p; + int base64_encoded = 0; + int binary_file = 0; + + if (strncmp(*s, "-\n", 2) == 0) { + value->length = 0; + *attr = "-"; + *s += 2; + return 0; + } + + p = strchr(*s, ':'); + if (!p) { + return -1; + } + + *p++ = 0; + + if (*p == ':') { + base64_encoded = 1; + p++; + } + + if (*p == '<') { + binary_file = 1; + p++; + } + + *attr = *s; + + while (*p == ' ' || *p == '\t') { + p++; + } + + value->data = (uint8_t *)p; + + p = strchr(p, '\n'); + + if (!p) { + value->length = strlen((char *)value->data); + *s = ((char *)value->data) + value->length; + } else { + value->length = p - (char *)value->data; + *s = p+1; + *p = 0; + } + + if (base64_encoded) { + int len = ldb_base64_decode((char *)value->data); + if (len == -1) { + /* it wasn't valid base64 data */ + return -1; + } + value->length = len; + } + + if (binary_file) { + int len = ldb_read_data_file(mem_ctx, value); + if (len == -1) { + /* an error occured hile trying to retrieve the file */ + return -1; + } + } + + return 0; +} + + +/* + free a message from a ldif_read +*/ +void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif) +{ + talloc_free(ldif); +} + +/* + read from a LDIF source, creating a ldb_message +*/ +struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb, + int (*fgetc_fn)(void *), void *private_data) +{ + struct ldb_ldif *ldif; + struct ldb_message *msg; + const char *attr=NULL; + char *chunk=NULL, *s; + struct ldb_val value; + unsigned flags = 0; + + value.data = NULL; + + ldif = talloc(ldb, struct ldb_ldif); + if (!ldif) return NULL; + + ldif->msg = talloc(ldif, struct ldb_message); + if (ldif->msg == NULL) { + talloc_free(ldif); + return NULL; + } + + ldif->changetype = LDB_CHANGETYPE_NONE; + msg = ldif->msg; + + msg->dn = NULL; + msg->elements = NULL; + msg->num_elements = 0; + + chunk = next_chunk(ldb, fgetc_fn, private_data); + if (!chunk) { + goto failed; + } + talloc_steal(ldif, chunk); + + s = chunk; + + if (next_attr(ldif, &s, &attr, &value) != 0) { + goto failed; + } + + /* first line must be a dn */ + if (ldb_attr_cmp(attr, "dn") != 0) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: First line of ldif must be a dn not '%s'\n", + attr); + goto failed; + } + + msg->dn = ldb_dn_new(msg, ldb, (char *)value.data); + + if ( ! ldb_dn_validate(msg->dn)) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Unable to parse dn '%s'\n", + value.data); + goto failed; + } + + while (next_attr(ldif, &s, &attr, &value) == 0) { + const struct ldb_schema_attribute *a; + struct ldb_message_element *el; + int ret, empty = 0; + + if (ldb_attr_cmp(attr, "changetype") == 0) { + int i; + for (i=0;ldb_changetypes[i].name;i++) { + if (ldb_attr_cmp((char *)value.data, ldb_changetypes[i].name) == 0) { + ldif->changetype = ldb_changetypes[i].changetype; + break; + } + } + if (!ldb_changetypes[i].name) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "Error: Bad ldif changetype '%s'\n",(char *)value.data); + } + flags = 0; + continue; + } + + if (ldb_attr_cmp(attr, "add") == 0) { + flags = LDB_FLAG_MOD_ADD; + empty = 1; + } + if (ldb_attr_cmp(attr, "delete") == 0) { + flags = LDB_FLAG_MOD_DELETE; + empty = 1; + } + if (ldb_attr_cmp(attr, "replace") == 0) { + flags = LDB_FLAG_MOD_REPLACE; + empty = 1; + } + if (ldb_attr_cmp(attr, "-") == 0) { + flags = 0; + continue; + } + + if (empty) { + if (ldb_msg_add_empty(msg, (char *)value.data, flags, NULL) != 0) { + goto failed; + } + continue; + } + + el = &msg->elements[msg->num_elements-1]; + + a = ldb_schema_attribute_by_name(ldb, attr); + + if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 && + flags == el->flags) { + /* its a continuation */ + el->values = + talloc_realloc(msg->elements, el->values, + struct ldb_val, el->num_values+1); + if (!el->values) { + goto failed; + } + ret = a->syntax->ldif_read_fn(ldb, ldif, &value, &el->values[el->num_values]); + if (ret != 0) { + goto failed; + } + if (value.length == 0) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "Error: Attribute value cannot be empty for attribute '%s'\n", el->name); + goto failed; + } + if (value.data != el->values[el->num_values].data) { + talloc_steal(el->values, el->values[el->num_values].data); + } + el->num_values++; + } else { + /* its a new attribute */ + msg->elements = talloc_realloc(ldif, msg->elements, + struct ldb_message_element, + msg->num_elements+1); + if (!msg->elements) { + goto failed; + } + el = &msg->elements[msg->num_elements]; + el->flags = flags; + el->name = talloc_strdup(msg->elements, attr); + el->values = talloc(msg->elements, struct ldb_val); + if (!el->values || !el->name) { + goto failed; + } + el->num_values = 1; + ret = a->syntax->ldif_read_fn(ldb, ldif, &value, &el->values[0]); + if (ret != 0) { + goto failed; + } + if (value.data != el->values[0].data) { + talloc_steal(el->values, el->values[0].data); + } + msg->num_elements++; + } + } + + return ldif; + +failed: + talloc_free(ldif); + return NULL; +} + + + +/* + a wrapper around ldif_read() for reading from FILE* +*/ +struct ldif_read_file_state { + FILE *f; +}; + +static int fgetc_file(void *private_data) +{ + struct ldif_read_file_state *state = + (struct ldif_read_file_state *)private_data; + return fgetc(state->f); +} + +struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f) +{ + struct ldif_read_file_state state; + state.f = f; + return ldb_ldif_read(ldb, fgetc_file, &state); +} + + +/* + a wrapper around ldif_read() for reading from const char* +*/ +struct ldif_read_string_state { + const char *s; +}; + +static int fgetc_string(void *private_data) +{ + struct ldif_read_string_state *state = + (struct ldif_read_string_state *)private_data; + if (state->s[0] != 0) { + return *state->s++; + } + return EOF; +} + +struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s) +{ + struct ldif_read_string_state state; + struct ldb_ldif *ldif; + state.s = *s; + ldif = ldb_ldif_read(ldb, fgetc_string, &state); + *s = state.s; + return ldif; +} + + +/* + wrapper around ldif_write() for a file +*/ +struct ldif_write_file_state { + FILE *f; +}; + +static int fprintf_file(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3); + +static int fprintf_file(void *private_data, const char *fmt, ...) +{ + struct ldif_write_file_state *state = + (struct ldif_write_file_state *)private_data; + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vfprintf(state->f, fmt, ap); + va_end(ap); + return ret; +} + +int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *ldif) +{ + struct ldif_write_file_state state; + state.f = f; + return ldb_ldif_write(ldb, fprintf_file, &state, ldif); +} diff --git a/ldb/common/ldb_match.c b/ldb/common/ldb_match.c new file mode 100644 index 000000000..64d0e5476 --- /dev/null +++ b/ldb/common/ldb_match.c @@ -0,0 +1,428 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004-2005 + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb expression matching + * + * Description: ldb expression matching + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" + +/* + check if the scope matches in a search result +*/ +static int ldb_match_scope(struct ldb_context *ldb, + struct ldb_dn *base, + struct ldb_dn *dn, + enum ldb_scope scope) +{ + int ret = 0; + + if (base == NULL || dn == NULL) { + return 1; + } + + switch (scope) { + case LDB_SCOPE_BASE: + if (ldb_dn_compare(base, dn) == 0) { + ret = 1; + } + break; + + case LDB_SCOPE_ONELEVEL: + if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) { + if (ldb_dn_compare_base(base, dn) == 0) { + ret = 1; + } + } + break; + + case LDB_SCOPE_SUBTREE: + default: + if (ldb_dn_compare_base(base, dn) == 0) { + ret = 1; + } + break; + } + + return ret; +} + + +/* + match if node is present +*/ +static int ldb_match_present(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + enum ldb_scope scope) +{ + if (ldb_attr_dn(tree->u.present.attr) == 0) { + return 1; + } + + if (ldb_msg_find_element(msg, tree->u.present.attr)) { + return 1; + } + + return 0; +} + +static int ldb_match_comparison(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + enum ldb_scope scope, + enum ldb_parse_op comp_op) +{ + unsigned int i; + struct ldb_message_element *el; + const struct ldb_schema_attribute *a; + int ret; + + /* FIXME: APPROX comparison not handled yet */ + if (comp_op == LDB_OP_APPROX) return 0; + + el = ldb_msg_find_element(msg, tree->u.comparison.attr); + if (el == NULL) { + return 0; + } + + a = ldb_schema_attribute_by_name(ldb, el->name); + + for (i = 0; i < el->num_values; i++) { + ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value); + + if (ret == 0) { + return 1; + } + if (ret > 0 && comp_op == LDB_OP_GREATER) { + return 1; + } + if (ret < 0 && comp_op == LDB_OP_LESS) { + return 1; + } + } + + return 0; +} + +/* + match a simple leaf node +*/ +static int ldb_match_equality(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + enum ldb_scope scope) +{ + unsigned int i; + struct ldb_message_element *el; + const struct ldb_schema_attribute *a; + struct ldb_dn *valuedn; + int ret; + + if (ldb_attr_dn(tree->u.equality.attr) == 0) { + valuedn = ldb_dn_new(ldb, ldb, (char *)tree->u.equality.value.data); + if (valuedn == NULL) { + return 0; + } + + ret = ldb_dn_compare(msg->dn, valuedn); + + talloc_free(valuedn); + + if (ret == 0) return 1; + return 0; + } + + /* TODO: handle the "*" case derived from an extended search + operation without the attibute type defined */ + el = ldb_msg_find_element(msg, tree->u.equality.attr); + if (el == NULL) { + return 0; + } + + a = ldb_schema_attribute_by_name(ldb, el->name); + + for (i=0;inum_values;i++) { + if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value, + &el->values[i]) == 0) { + return 1; + } + } + + return 0; +} + +static int ldb_wildcard_compare(struct ldb_context *ldb, + const struct ldb_parse_tree *tree, + const struct ldb_val value) +{ + const struct ldb_schema_attribute *a; + struct ldb_val val; + struct ldb_val cnk; + struct ldb_val *chunk; + char *p, *g; + uint8_t *save_p = NULL; + int c = 0; + + a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr); + + if(a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) + return -1; + + save_p = val.data; + cnk.data = NULL; + + if ( ! tree->u.substring.start_with_wildcard ) { + + chunk = tree->u.substring.chunks[c]; + if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed; + + /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */ + if (cnk.length > val.length) { + goto failed; + } + if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed; + val.length -= cnk.length; + val.data += cnk.length; + c++; + talloc_free(cnk.data); + cnk.data = NULL; + } + + while (tree->u.substring.chunks[c]) { + + chunk = tree->u.substring.chunks[c]; + if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed; + + /* FIXME: case of embedded nulls */ + p = strstr((char *)val.data, (char *)cnk.data); + if (p == NULL) goto failed; + if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) { + do { /* greedy */ + g = strstr((char *)p + cnk.length, (char *)cnk.data); + if (g) p = g; + } while(g); + } + val.length = val.length - (p - (char *)(val.data)) - cnk.length; + val.data = (uint8_t *)(p + cnk.length); + c++; + talloc_free(cnk.data); + cnk.data = NULL; + } + + if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */ + talloc_free(save_p); + return 1; + +failed: + talloc_free(save_p); + talloc_free(cnk.data); + return 0; +} + +/* + match a simple leaf node +*/ +static int ldb_match_substring(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + enum ldb_scope scope) +{ + unsigned int i; + struct ldb_message_element *el; + + el = ldb_msg_find_element(msg, tree->u.substring.attr); + if (el == NULL) { + return 0; + } + + for (i = 0; i < el->num_values; i++) { + if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) { + return 1; + } + } + + return 0; +} + + +/* + bitwise-and comparator +*/ +static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2) +{ + uint64_t i1, i2; + i1 = strtoull((char *)v1->data, NULL, 0); + i2 = strtoull((char *)v2->data, NULL, 0); + return ((i1 & i2) == i2); +} + +/* + bitwise-or comparator +*/ +static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2) +{ + uint64_t i1, i2; + i1 = strtoull((char *)v1->data, NULL, 0); + i2 = strtoull((char *)v2->data, NULL, 0); + return ((i1 & i2) != 0); +} + + +/* + extended match, handles things like bitops +*/ +static int ldb_match_extended(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + enum ldb_scope scope) +{ + int i; + const struct { + const char *oid; + int (*comparator)(const struct ldb_val *, const struct ldb_val *); + } rules[] = { + { LDB_OID_COMPARATOR_AND, ldb_comparator_and}, + { LDB_OID_COMPARATOR_OR, ldb_comparator_or} + }; + int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL; + struct ldb_message_element *el; + + if (tree->u.extended.dnAttributes) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet"); + return -1; + } + if (tree->u.extended.rule_id == NULL) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet"); + return -1; + } + if (tree->u.extended.attr == NULL) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet"); + return -1; + } + + for (i=0;iu.extended.rule_id) == 0) { + comp = rules[i].comparator; + break; + } + } + if (comp == NULL) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n", + tree->u.extended.rule_id); + return -1; + } + + /* find the message element */ + el = ldb_msg_find_element(msg, tree->u.extended.attr); + if (el == NULL) { + return 0; + } + + for (i=0;inum_values;i++) { + int ret = comp(&el->values[i], &tree->u.extended.value); + if (ret == -1 || ret == 1) return ret; + } + + return 0; +} + +/* + return 0 if the given parse tree matches the given message. Assumes + the message is in sorted order + + return 1 if it matches, and 0 if it doesn't match + + this is a recursive function, and does short-circuit evaluation + */ +static int ldb_match_message(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + enum ldb_scope scope) +{ + unsigned int i; + int v; + + switch (tree->operation) { + case LDB_OP_AND: + for (i=0;iu.list.num_elements;i++) { + v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope); + if (!v) return 0; + } + return 1; + + case LDB_OP_OR: + for (i=0;iu.list.num_elements;i++) { + v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope); + if (v) return 1; + } + return 0; + + case LDB_OP_NOT: + return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope); + + case LDB_OP_EQUALITY: + return ldb_match_equality(ldb, msg, tree, scope); + + case LDB_OP_SUBSTRING: + return ldb_match_substring(ldb, msg, tree, scope); + + case LDB_OP_GREATER: + return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER); + + case LDB_OP_LESS: + return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS); + + case LDB_OP_PRESENT: + return ldb_match_present(ldb, msg, tree, scope); + + case LDB_OP_APPROX: + return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX); + + case LDB_OP_EXTENDED: + return ldb_match_extended(ldb, msg, tree, scope); + + } + + return 0; +} + +int ldb_match_msg(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + struct ldb_dn *base, + enum ldb_scope scope) +{ + if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) { + return 0; + } + + return ldb_match_message(ldb, msg, tree, scope); +} diff --git a/ldb/common/ldb_modules.c b/ldb/common/ldb_modules.c new file mode 100644 index 000000000..4d69dc662 --- /dev/null +++ b/ldb/common/ldb_modules.c @@ -0,0 +1,625 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb modules core + * + * Description: core modules routines + * + * Author: Simo Sorce + */ + +#include "ldb_includes.h" + +#if (_SAMBA_BUILD_ >= 4) +#include "includes.h" +#endif + +#define LDB_MODULE_PREFIX "modules:" +#define LDB_MODULE_PREFIX_LEN 8 + +void ldb_set_modules_dir(struct ldb_context *ldb, const char *path) +{ + talloc_free(ldb->modules_dir); + ldb->modules_dir = talloc_strdup(ldb, path); +} + +static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string) +{ + int i, len; + char *trimmed; + + trimmed = talloc_strdup(mem_ctx, string); + if (!trimmed) { + return NULL; + } + + len = strlen(trimmed); + for (i = 0; trimmed[i] != '\0'; i++) { + switch (trimmed[i]) { + case ' ': + case '\t': + case '\n': + memmove(&trimmed[i], &trimmed[i + 1], len -i -1); + break; + } + } + + return trimmed; +} + + +/* modules are called in inverse order on the stack. + Lets place them as an admin would think the right order is. + Modules order is important */ +const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string) +{ + char **modules = NULL; + const char **m; + char *modstr, *p; + int i; + + /* spaces not admitted */ + modstr = ldb_modules_strdup_no_spaces(mem_ctx, string); + if ( ! modstr) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_strdup_no_spaces()\n"); + return NULL; + } + + modules = talloc_realloc(mem_ctx, modules, char *, 2); + if ( ! modules ) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()\n"); + talloc_free(modstr); + return NULL; + } + talloc_steal(modules, modstr); + + i = 0; + /* The str*r*chr walks backwards: This is how we get the inverse order mentioned above */ + while ((p = strrchr(modstr, ',')) != NULL) { + *p = '\0'; + p++; + modules[i] = p; + + i++; + modules = talloc_realloc(mem_ctx, modules, char *, i + 2); + if ( ! modules ) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()\n"); + return NULL; + } + + } + modules[i] = modstr; + + modules[i + 1] = NULL; + + m = (const char **)modules; + + return m; +} + +static struct backends_list_entry { + struct ldb_backend_ops *ops; + struct backends_list_entry *prev, *next; +} *ldb_backends = NULL; + +static struct ops_list_entry { + const struct ldb_module_ops *ops; + struct ops_list_entry *next; +} *registered_modules = NULL; + +static const struct ldb_builtins { + const struct ldb_backend_ops *backend_ops; + const struct ldb_module_ops *module_ops; +} builtins[]; + +static ldb_connect_fn ldb_find_backend(const char *url) +{ + struct backends_list_entry *backend; + int i; + + for (i = 0; builtins[i].backend_ops || builtins[i].module_ops; i++) { + if (builtins[i].backend_ops == NULL) continue; + + if (strncmp(builtins[i].backend_ops->name, url, + strlen(builtins[i].backend_ops->name)) == 0) { + return builtins[i].backend_ops->connect_fn; + } + } + + for (backend = ldb_backends; backend; backend = backend->next) { + if (strncmp(backend->ops->name, url, + strlen(backend->ops->name)) == 0) { + return backend->ops->connect_fn; + } + } + + return NULL; +} + +/* + register a new ldb backend +*/ +int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn) +{ + struct ldb_backend_ops *backend; + struct backends_list_entry *entry; + + backend = talloc(talloc_autofree_context(), struct ldb_backend_ops); + if (!backend) return LDB_ERR_OPERATIONS_ERROR; + + entry = talloc(talloc_autofree_context(), struct backends_list_entry); + if (!entry) { + talloc_free(backend); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (ldb_find_backend(url_prefix)) { + return LDB_SUCCESS; + } + + /* Maybe check for duplicity here later on? */ + + backend->name = talloc_strdup(backend, url_prefix); + backend->connect_fn = connectfn; + entry->ops = backend; + DLIST_ADD(ldb_backends, entry); + + return LDB_SUCCESS; +} + +/* + Return the ldb module form of a database. + The URL can either be one of the following forms + ldb://path + ldapi://path + + flags is made up of LDB_FLG_* + + the options are passed uninterpreted to the backend, and are + backend specific. + + This allows modules to get at only the backend module, for example where a + module may wish to direct certain requests at a particular backend. +*/ +int ldb_connect_backend(struct ldb_context *ldb, + const char *url, + const char *options[], + struct ldb_module **backend_module) +{ + int ret; + char *backend; + ldb_connect_fn fn; + + if (strchr(url, ':') != NULL) { + backend = talloc_strndup(ldb, url, strchr(url, ':')-url); + } else { + /* Default to tdb */ + backend = talloc_strdup(ldb, "tdb"); + } + + fn = ldb_find_backend(backend); + + if (fn == NULL) { + struct ldb_backend_ops *ops; + char *symbol_name = talloc_asprintf(ldb, "ldb_%s_backend_ops", backend); + if (symbol_name == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ops = ldb_dso_load_symbol(ldb, backend, symbol_name); + if (ops != NULL) { + fn = ops->connect_fn; + } + talloc_free(symbol_name); + } + + talloc_free(backend); + + if (fn == NULL) { + ldb_debug(ldb, LDB_DEBUG_FATAL, + "Unable to find backend for '%s'\n", url); + return LDB_ERR_OTHER; + } + + ret = fn(ldb, url, ldb->flags, options, backend_module); + + if (ret != LDB_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "Failed to connect to '%s'\n", url); + return ret; + } + return ret; +} + +static const struct ldb_module_ops *ldb_find_module_ops(const char *name) +{ + struct ops_list_entry *e; + int i; + + for (i = 0; builtins[i].backend_ops || builtins[i].module_ops; i++) { + if (builtins[i].module_ops == NULL) continue; + + if (strcmp(builtins[i].module_ops->name, name) == 0) + return builtins[i].module_ops; + } + + for (e = registered_modules; e; e = e->next) { + if (strcmp(e->ops->name, name) == 0) + return e->ops; + } + + return NULL; +} + + +int ldb_register_module(const struct ldb_module_ops *ops) +{ + struct ops_list_entry *entry = talloc(talloc_autofree_context(), struct ops_list_entry); + + if (ldb_find_module_ops(ops->name) != NULL) + return -1; + + if (entry == NULL) + return -1; + + entry->ops = ops; + entry->next = registered_modules; + registered_modules = entry; + + return 0; +} + +void *ldb_dso_load_symbol(struct ldb_context *ldb, const char *name, + const char *symbol) +{ + char *path; + void *handle; + void *sym; + + if (ldb->modules_dir == NULL) + return NULL; + + path = talloc_asprintf(ldb, "%s/%s.%s", ldb->modules_dir, name, + SHLIBEXT); + + ldb_debug(ldb, LDB_DEBUG_TRACE, "trying to load %s from %s\n", name, path); + + handle = dlopen(path, RTLD_NOW); + if (handle == NULL) { + ldb_debug(ldb, LDB_DEBUG_WARNING, "unable to load %s from %s: %s\n", name, path, dlerror()); + return NULL; + } + + sym = (int (*)(void))dlsym(handle, symbol); + + if (sym == NULL) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol `%s' found in %s: %s\n", symbol, path, dlerror()); + return NULL; + } + + talloc_free(path); + + return sym; +} + +int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out) +{ + struct ldb_module *module; + int i; + + module = backend; + + for (i = 0; module_list[i] != NULL; i++) { + struct ldb_module *current; + const struct ldb_module_ops *ops; + + ops = ldb_find_module_ops(module_list[i]); + if (ops == NULL) { + char *symbol_name = talloc_asprintf(ldb, "ldb_%s_module_ops", + module_list[i]); + if (symbol_name == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ops = ldb_dso_load_symbol(ldb, module_list[i], symbol_name); + talloc_free(symbol_name); + } + + if (ops == NULL) { + ldb_debug(ldb, LDB_DEBUG_WARNING, "WARNING: Module [%s] not found\n", + module_list[i]); + continue; + } + + current = talloc_zero(ldb, struct ldb_module); + if (current == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + talloc_set_name(current, "ldb_module: %s", module_list[i]); + + current->ldb = ldb; + current->ops = ops; + + DLIST_ADD(module, current); + } + *out = module; + return LDB_SUCCESS; +} + +int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module) +{ + while (module && module->ops->init_context == NULL) + module = module->next; + + /* init is different in that it is not an error if modules + * do not require initialization */ + + if (module) { + int ret = module->ops->init_context(module); + if (ret != LDB_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "module %s initialization failed\n", module->ops->name); + return ret; + } + } + + return LDB_SUCCESS; +} + +int ldb_load_modules(struct ldb_context *ldb, const char *options[]) +{ + const char **modules = NULL; + int i; + int ret; + TALLOC_CTX *mem_ctx = talloc_new(ldb); + if (!mem_ctx) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* find out which modules we are requested to activate */ + + /* check if we have a custom module list passd as ldb option */ + if (options) { + for (i = 0; options[i] != NULL; i++) { + if (strncmp(options[i], LDB_MODULE_PREFIX, LDB_MODULE_PREFIX_LEN) == 0) { + modules = ldb_modules_list_from_string(ldb, mem_ctx, &options[i][LDB_MODULE_PREFIX_LEN]); + } + } + } + + /* if not overloaded by options and the backend is not ldap try to load the modules list from ldb */ + if ((modules == NULL) && (strcmp("ldap", ldb->modules->ops->name) != 0)) { + const char * const attrs[] = { "@LIST" , NULL}; + struct ldb_result *res = NULL; + struct ldb_dn *mods_dn; + + mods_dn = ldb_dn_new(mem_ctx, ldb, "@MODULES"); + if (mods_dn == NULL) { + talloc_free(mem_ctx); + return -1; + } + + ret = ldb_search_exp_fmt(ldb, mods_dn, &res, mods_dn, LDB_SCOPE_BASE, attrs, "@LIST=*"); + + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db"); + } else if (ret != LDB_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for modules, bailing out\n", ldb_errstring(ldb)); + talloc_free(mem_ctx); + return ret; + } else { + const char *module_list; + if (res->count == 0) { + ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db"); + } else if (res->count > 1) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%d), bailing out\n", res->count); + talloc_free(mem_ctx); + return -1; + } else { + module_list = ldb_msg_find_attr_as_string(res->msgs[0], "@LIST", NULL); + if (!module_list) { + ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db"); + } + modules = ldb_modules_list_from_string(ldb, mem_ctx, + module_list); + } + } + + talloc_free(mods_dn); + } + + if (modules != NULL) { + ret = ldb_load_modules_list(ldb, modules, ldb->modules, &ldb->modules); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + } else { + ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database"); + } + + ret = ldb_init_module_chain(ldb, ldb->modules); + talloc_free(mem_ctx); + return ret; +} + +/* + by using this we allow ldb modules to only implement the functions they care about, + which makes writing a module simpler, and makes it more likely to keep working + when ldb is extended +*/ +#define FIND_OP(module, op) do { \ + struct ldb_context *ldb = module->ldb; \ + module = module->next; \ + while (module && module->ops->op == NULL) module = module->next; \ + if (module == NULL) { \ + ldb_asprintf_errstring(ldb, "Unable to find backend operation for " #op ); \ + return LDB_ERR_OPERATIONS_ERROR; \ + } \ +} while (0) + + +/* + helper functions to call the next module in chain +*/ + +int ldb_next_request(struct ldb_module *module, struct ldb_request *request) +{ + int ret; + switch (request->operation) { + case LDB_SEARCH: + FIND_OP(module, search); + ret = module->ops->search(module, request); + break; + case LDB_ADD: + FIND_OP(module, add); + ret = module->ops->add(module, request); + break; + case LDB_MODIFY: + FIND_OP(module, modify); + ret = module->ops->modify(module, request); + break; + case LDB_DELETE: + FIND_OP(module, del); + ret = module->ops->del(module, request); + break; + case LDB_RENAME: + FIND_OP(module, rename); + ret = module->ops->rename(module, request); + break; + case LDB_EXTENDED: + FIND_OP(module, extended); + ret = module->ops->extended(module, request); + break; + case LDB_SEQUENCE_NUMBER: + FIND_OP(module, sequence_number); + ret = module->ops->sequence_number(module, request); + break; + default: + FIND_OP(module, request); + ret = module->ops->request(module, request); + break; + } + if (ret == LDB_SUCCESS) { + return ret; + } + if (!ldb_errstring(module->ldb)) { + /* Set a default error string, to place the blame somewhere */ + ldb_asprintf_errstring(module->ldb, "error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret); + } + return ret; +} + +int ldb_next_init(struct ldb_module *module) +{ + module = module->next; + + return ldb_init_module_chain(module->ldb, module); +} + +int ldb_next_start_trans(struct ldb_module *module) +{ + FIND_OP(module, start_transaction); + return module->ops->start_transaction(module); +} + +int ldb_next_end_trans(struct ldb_module *module) +{ + FIND_OP(module, end_transaction); + return module->ops->end_transaction(module); +} + +int ldb_next_del_trans(struct ldb_module *module) +{ + FIND_OP(module, del_transaction); + return module->ops->del_transaction(module); +} + +#ifndef STATIC_LIBLDB_MODULES + +#ifdef HAVE_LDB_LDAP +#define LDAP_BACKEND LDB_BACKEND(ldap), LDB_BACKEND(ldapi), LDB_BACKEND(ldaps), +#else +#define LDAP_BACKEND +#endif + +#ifdef HAVE_LDB_SQLITE3 +#define SQLITE3_BACKEND LDB_BACKEND(sqlite3), +#else +#define SQLITE3_BACKEND +#endif + +#define STATIC_LIBLDB_MODULES \ + LDB_BACKEND(tdb), \ + LDAP_BACKEND \ + SQLITE3_BACKEND \ + LDB_MODULE(operational), \ + LDB_MODULE(rdn_name), \ + LDB_MODULE(paged_results), \ + LDB_MODULE(server_sort), \ + LDB_MODULE(asq), \ + NULL +#endif + +/* + * this is a bit hacked, as STATIC_LIBLDB_MODULES contains ',' + * between the elements and we want to autogenerate the + * extern struct declarations, so we do some hacks and let the + * ',' appear in an unused function prototype. + */ +#undef NULL +#define NULL LDB_MODULE(NULL), + +#define LDB_BACKEND(name) \ + int); \ + extern const struct ldb_backend_ops ldb_ ## name ## _backend_ops;\ + extern void ldb_noop ## name (int +#define LDB_MODULE(name) \ + int); \ + extern const struct ldb_module_ops ldb_ ## name ## _module_ops;\ + extern void ldb_noop ## name (int + +extern void ldb_start_noop(int, +STATIC_LIBLDB_MODULES +int); + +#undef NULL +#define NULL { \ + .backend_ops = (void *)0, \ + .module_ops = (void *)0 \ +} + +#undef LDB_BACKEND +#define LDB_BACKEND(name) { \ + .backend_ops = &ldb_ ## name ## _backend_ops, \ + .module_ops = (void *)0 \ +} +#undef LDB_MODULE +#define LDB_MODULE(name) { \ + .backend_ops = (void *)0, \ + .module_ops = &ldb_ ## name ## _module_ops \ +} + +static const struct ldb_builtins builtins[] = { + STATIC_LIBLDB_MODULES +}; diff --git a/ldb/common/ldb_msg.c b/ldb/common/ldb_msg.c new file mode 100644 index 000000000..2f5fe1d18 --- /dev/null +++ b/ldb/common/ldb_msg.c @@ -0,0 +1,899 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb message component utility functions + * + * Description: functions for manipulating ldb_message structures + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" + +/* + create a new ldb_message in a given memory context (NULL for top level) +*/ +struct ldb_message *ldb_msg_new(void *mem_ctx) +{ + return talloc_zero(mem_ctx, struct ldb_message); +} + +/* + find an element in a message by attribute name +*/ +struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, + const char *attr_name) +{ + unsigned int i; + for (i=0;inum_elements;i++) { + if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) { + return &msg->elements[i]; + } + } + return NULL; +} + +/* + see if two ldb_val structures contain exactly the same data + return 1 for a match, 0 for a mis-match +*/ +int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2) +{ + if (v1->length != v2->length) return 0; + + if (v1->length == 0) return 1; + + if (memcmp(v1->data, v2->data, v1->length) == 0) { + return 1; + } + + return 0; +} + +/* + find a value in an element + assumes case sensitive comparison +*/ +struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, + struct ldb_val *val) +{ + unsigned int i; + for (i=0;inum_values;i++) { + if (ldb_val_equal_exact(val, &el->values[i])) { + return &el->values[i]; + } + } + return NULL; +} + +/* + duplicate a ldb_val structure +*/ +struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v) +{ + struct ldb_val v2; + v2.length = v->length; + if (v->data == NULL) { + v2.data = NULL; + return v2; + } + + /* the +1 is to cope with buggy C library routines like strndup + that look one byte beyond */ + v2.data = talloc_array(mem_ctx, uint8_t, v->length+1); + if (!v2.data) { + v2.length = 0; + return v2; + } + + memcpy(v2.data, v->data, v->length); + ((char *)v2.data)[v->length] = 0; + return v2; +} + +/* + add an empty element to a message +*/ +int ldb_msg_add_empty( struct ldb_message *msg, + const char *attr_name, + int flags, + struct ldb_message_element **return_el) +{ + struct ldb_message_element *els; + + els = talloc_realloc(msg, msg->elements, + struct ldb_message_element, msg->num_elements+1); + if (!els) { + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + + els[msg->num_elements].values = NULL; + els[msg->num_elements].num_values = 0; + els[msg->num_elements].flags = flags; + els[msg->num_elements].name = talloc_strdup(els, attr_name); + if (!els[msg->num_elements].name) { + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->elements = els; + msg->num_elements++; + + if (return_el) { + *return_el = &els[msg->num_elements-1]; + } + + return LDB_SUCCESS; +} + +/* + add an empty element to a message +*/ +int ldb_msg_add(struct ldb_message *msg, + const struct ldb_message_element *el, + int flags) +{ + /* We have to copy this, just in case *el is a pointer into + * what ldb_msg_add_empty() is about to realloc() */ + struct ldb_message_element el_copy = *el; + if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->elements[msg->num_elements-1] = el_copy; + msg->elements[msg->num_elements-1].flags = flags; + + return LDB_SUCCESS; +} + +/* + add a value to a message +*/ +int ldb_msg_add_value(struct ldb_message *msg, + const char *attr_name, + const struct ldb_val *val, + struct ldb_message_element **return_el) +{ + struct ldb_message_element *el; + struct ldb_val *vals; + int ret; + + el = ldb_msg_find_element(msg, attr_name); + if (!el) { + ret = ldb_msg_add_empty(msg, attr_name, 0, &el); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1); + if (!vals) { + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + el->values = vals; + el->values[el->num_values] = *val; + el->num_values++; + + if (return_el) { + *return_el = el; + } + + return LDB_SUCCESS; +} + + +/* + add a value to a message, stealing it into the 'right' place +*/ +int ldb_msg_add_steal_value(struct ldb_message *msg, + const char *attr_name, + struct ldb_val *val) +{ + int ret; + struct ldb_message_element *el; + + ret = ldb_msg_add_value(msg, attr_name, val, &el); + if (ret == LDB_SUCCESS) { + talloc_steal(el->values, val->data); + } + return ret; +} + + +/* + add a string element to a message +*/ +int ldb_msg_add_string(struct ldb_message *msg, + const char *attr_name, const char *str) +{ + struct ldb_val val; + + val.data = discard_const_p(uint8_t, str); + val.length = strlen(str); + + if (val.length == 0) { + /* allow empty strings as non-existant attributes */ + return LDB_SUCCESS; + } + + return ldb_msg_add_value(msg, attr_name, &val, NULL); +} + +/* + add a string element to a message, stealing it into the 'right' place +*/ +int ldb_msg_add_steal_string(struct ldb_message *msg, + const char *attr_name, char *str) +{ + struct ldb_val val; + + val.data = (uint8_t *)str; + val.length = strlen(str); + + return ldb_msg_add_steal_value(msg, attr_name, &val); +} + +/* + add a printf formatted element to a message +*/ +int ldb_msg_add_fmt(struct ldb_message *msg, + const char *attr_name, const char *fmt, ...) +{ + struct ldb_val val; + va_list ap; + char *str; + + va_start(ap, fmt); + str = talloc_vasprintf(msg, fmt, ap); + va_end(ap); + + if (str == NULL) return LDB_ERR_OPERATIONS_ERROR; + + val.data = (uint8_t *)str; + val.length = strlen(str); + + return ldb_msg_add_steal_value(msg, attr_name, &val); +} + +/* + compare two ldb_message_element structures + assumes case senistive comparison +*/ +int ldb_msg_element_compare(struct ldb_message_element *el1, + struct ldb_message_element *el2) +{ + unsigned int i; + + if (el1->num_values != el2->num_values) { + return el1->num_values - el2->num_values; + } + + for (i=0;inum_values;i++) { + if (!ldb_msg_find_val(el2, &el1->values[i])) { + return -1; + } + } + + return 0; +} + +/* + compare two ldb_message_element structures + comparing by element name +*/ +int ldb_msg_element_compare_name(struct ldb_message_element *el1, + struct ldb_message_element *el2) +{ + return ldb_attr_cmp(el1->name, el2->name); +} + +/* + convenience functions to return common types from a message + these return the first value if the attribute is multi-valued +*/ +const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, + const char *attr_name) +{ + struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name); + if (!el || el->num_values == 0) { + return NULL; + } + return &el->values[0]; +} + +int ldb_msg_find_attr_as_int(const struct ldb_message *msg, + const char *attr_name, + int default_value) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return default_value; + } + return strtol((const char *)v->data, NULL, 0); +} + +unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, + const char *attr_name, + unsigned int default_value) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return default_value; + } + return strtoul((const char *)v->data, NULL, 0); +} + +int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, + const char *attr_name, + int64_t default_value) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return default_value; + } + return strtoll((const char *)v->data, NULL, 0); +} + +uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, + const char *attr_name, + uint64_t default_value) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return default_value; + } + return strtoull((const char *)v->data, NULL, 0); +} + +double ldb_msg_find_attr_as_double(const struct ldb_message *msg, + const char *attr_name, + double default_value) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return default_value; + } + return strtod((const char *)v->data, NULL); +} + +int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, + const char *attr_name, + int default_value) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return default_value; + } + if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) { + return 0; + } + if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) { + return 1; + } + return default_value; +} + +const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, + const char *attr_name, + const char *default_value) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return default_value; + } + return (const char *)v->data; +} + +struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_message *msg, + const char *attr_name) +{ + struct ldb_dn *res_dn; + const struct ldb_val *v; + + v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return NULL; + } + res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v); + if ( ! ldb_dn_validate(res_dn)) { + talloc_free(res_dn); + return NULL; + } + return res_dn; +} + +/* + sort the elements of a message by name +*/ +void ldb_msg_sort_elements(struct ldb_message *msg) +{ + qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), + (comparison_fn_t)ldb_msg_element_compare_name); +} + +/* + shallow copy a message - copying only the elements array so that the caller + can safely add new elements without changing the message +*/ +struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, + const struct ldb_message *msg) +{ + struct ldb_message *msg2; + int i; + + msg2 = talloc(mem_ctx, struct ldb_message); + if (msg2 == NULL) return NULL; + + *msg2 = *msg; + + msg2->elements = talloc_array(msg2, struct ldb_message_element, + msg2->num_elements); + if (msg2->elements == NULL) goto failed; + + for (i=0;inum_elements;i++) { + msg2->elements[i] = msg->elements[i]; + } + + return msg2; + +failed: + talloc_free(msg2); + return NULL; +} + + +/* + copy a message, allocating new memory for all parts +*/ +struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, + const struct ldb_message *msg) +{ + struct ldb_message *msg2; + int i, j; + + msg2 = ldb_msg_copy_shallow(mem_ctx, msg); + if (msg2 == NULL) return NULL; + + msg2->dn = ldb_dn_copy(msg2, msg2->dn); + if (msg2->dn == NULL) goto failed; + + for (i=0;inum_elements;i++) { + struct ldb_message_element *el = &msg2->elements[i]; + struct ldb_val *values = el->values; + el->name = talloc_strdup(msg2->elements, el->name); + if (el->name == NULL) goto failed; + el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values); + for (j=0;jnum_values;j++) { + el->values[j] = ldb_val_dup(el->values, &values[j]); + if (el->values[j].data == NULL && values[j].length != 0) { + goto failed; + } + } + } + + return msg2; + +failed: + talloc_free(msg2); + return NULL; +} + + +/* + canonicalise a message, merging elements of the same name +*/ +struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, + const struct ldb_message *msg) +{ + int i; + struct ldb_message *msg2; + + msg2 = ldb_msg_copy(ldb, msg); + if (msg2 == NULL) return NULL; + + ldb_msg_sort_elements(msg2); + + for (i=1;inum_elements;i++) { + struct ldb_message_element *el1 = &msg2->elements[i-1]; + struct ldb_message_element *el2 = &msg2->elements[i]; + if (ldb_msg_element_compare_name(el1, el2) == 0) { + el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, + el1->num_values + el2->num_values); + if (el1->values == NULL) { + return NULL; + } + memcpy(el1->values + el1->num_values, + el2->values, + sizeof(struct ldb_val) * el2->num_values); + el1->num_values += el2->num_values; + talloc_free(discard_const_p(char, el2->name)); + if (i+1num_elements) { + memmove(el2, el2+1, sizeof(struct ldb_message_element) * + (msg2->num_elements - (i+1))); + } + msg2->num_elements--; + i--; + } + } + + return msg2; +} + + +/* + return a ldb_message representing the differences between msg1 and msg2. If you + then use this in a ldb_modify() call it can be used to save edits to a message +*/ +struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, + struct ldb_message *msg1, + struct ldb_message *msg2) +{ + struct ldb_message *mod; + struct ldb_message_element *el; + unsigned int i; + + mod = ldb_msg_new(ldb); + + mod->dn = msg1->dn; + mod->num_elements = 0; + mod->elements = NULL; + + msg2 = ldb_msg_canonicalize(ldb, msg2); + if (msg2 == NULL) { + return NULL; + } + + /* look in msg2 to find elements that need to be added + or modified */ + for (i=0;inum_elements;i++) { + el = ldb_msg_find_element(msg1, msg2->elements[i].name); + + if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) { + continue; + } + + if (ldb_msg_add(mod, + &msg2->elements[i], + el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) { + return NULL; + } + } + + /* look in msg1 to find elements that need to be deleted */ + for (i=0;inum_elements;i++) { + el = ldb_msg_find_element(msg2, msg1->elements[i].name); + if (!el) { + if (ldb_msg_add_empty(mod, + msg1->elements[i].name, + LDB_FLAG_MOD_DELETE, NULL) != 0) { + return NULL; + } + } + } + + return mod; +} + +int ldb_msg_sanity_check(struct ldb_context *ldb, + const struct ldb_message *msg) +{ + int i, j; + + /* basic check on DN */ + if (msg->dn == NULL) { + /* TODO: return also an error string */ + ldb_set_errstring(ldb, "ldb message lacks a DN!"); + return LDB_ERR_INVALID_DN_SYNTAX; + } + + /* basic syntax checks */ + for (i = 0; i < msg->num_elements; i++) { + for (j = 0; j < msg->elements[i].num_values; j++) { + if (msg->elements[i].values[j].length == 0) { + TALLOC_CTX *mem_ctx = talloc_new(ldb); + /* an attribute cannot be empty */ + /* TODO: return also an error string */ + ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!", + msg->elements[i].name, + ldb_dn_get_linearized(msg->dn)); + talloc_free(mem_ctx); + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + } + } + + return LDB_SUCCESS; +} + + + + +/* + copy an attribute list. This only copies the array, not the elements + (ie. the elements are left as the same pointers) +*/ +const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs) +{ + const char **ret; + int i; + for (i=0;attrs[i];i++) /* noop */ ; + ret = talloc_array(mem_ctx, const char *, i+1); + if (ret == NULL) { + return NULL; + } + for (i=0;attrs[i];i++) { + ret[i] = attrs[i]; + } + ret[i] = attrs[i]; + return ret; +} + + +/* + copy an attribute list. This only copies the array, not the elements + (ie. the elements are left as the same pointers). The new attribute is added to the list. +*/ +const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr) +{ + const char **ret; + int i; + bool found = false; + for (i=0;attrs[i];i++) { + if (ldb_attr_cmp(attrs[i], new_attr) == 0) { + found = true; + } + } + if (found) { + return ldb_attr_list_copy(mem_ctx, attrs); + } + ret = talloc_array(mem_ctx, const char *, i+2); + if (ret == NULL) { + return NULL; + } + for (i=0;attrs[i];i++) { + ret[i] = attrs[i]; + } + ret[i] = new_attr; + ret[i+1] = NULL; + return ret; +} + + +/* + return 1 if an attribute is in a list of attributes, or 0 otherwise +*/ +int ldb_attr_in_list(const char * const *attrs, const char *attr) +{ + int i; + for (i=0;attrs && attrs[i];i++) { + if (ldb_attr_cmp(attrs[i], attr) == 0) { + return 1; + } + } + return 0; +} + + +/* + rename the specified attribute in a search result +*/ +int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace) +{ + struct ldb_message_element *el = ldb_msg_find_element(msg, attr); + if (el == NULL) { + return LDB_SUCCESS; + } + el->name = talloc_strdup(msg->elements, replace); + if (el->name == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + return LDB_SUCCESS; +} + + +/* + copy the specified attribute in a search result to a new attribute +*/ +int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace) +{ + struct ldb_message_element *el = ldb_msg_find_element(msg, attr); + if (el == NULL) { + return LDB_SUCCESS; + } + if (ldb_msg_add(msg, el, 0) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + return ldb_msg_rename_attr(msg, attr, replace); +} + +/* + remove the specified element in a search result +*/ +void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el) +{ + int n = (el - msg->elements); + if (n != msg->num_elements-1) { + memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el)); + } + msg->num_elements--; +} + + +/* + remove the specified attribute in a search result +*/ +void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr) +{ + struct ldb_message_element *el = ldb_msg_find_element(msg, attr); + if (el) { + ldb_msg_remove_element(msg, el); + } +} + +/* + return a LDAP formatted GeneralizedTime string +*/ +char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t) +{ + struct tm *tm = gmtime(&t); + char *ts; + int r; + + if (!tm) { + return NULL; + } + + /* we now excatly how long this string will be */ + ts = talloc_array(mem_ctx, char, 18); + + /* formatted like: 20040408072012.0Z */ + r = snprintf(ts, 18, + "%04u%02u%02u%02u%02u%02u.0Z", + tm->tm_year+1900, tm->tm_mon+1, + tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + + if (r != 17) { + talloc_free(ts); + return NULL; + } + + return ts; +} + +/* + convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert +*/ +time_t ldb_string_to_time(const char *s) +{ + struct tm tm; + + if (s == NULL) return 0; + + memset(&tm, 0, sizeof(tm)); + if (sscanf(s, "%04u%02u%02u%02u%02u%02u", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { + return 0; + } + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + return timegm(&tm); +} + +/* + return a LDAP formatted UTCTime string +*/ +char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t) +{ + struct tm *tm = gmtime(&t); + char *ts; + int r; + + if (!tm) { + return NULL; + } + + /* we now excatly how long this string will be */ + ts = talloc_array(mem_ctx, char, 14); + + /* formatted like: 20040408072012.0Z => 040408072012Z */ + r = snprintf(ts, 14, + "%02u%02u%02u%02u%02u%02uZ", + (tm->tm_year+1900)%100, tm->tm_mon+1, + tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + + if (r != 13) { + talloc_free(ts); + return NULL; + } + + return ts; +} + +/* + convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert +*/ +time_t ldb_string_utc_to_time(const char *s) +{ + struct tm tm; + + if (s == NULL) return 0; + + memset(&tm, 0, sizeof(tm)); + if (sscanf(s, "%02u%02u%02u%02u%02u%02u", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { + return 0; + } + if (tm.tm_year < 50) { + tm.tm_year += 100; + } + tm.tm_mon -= 1; + + return timegm(&tm); +} + + +/* + dump a set of results to a file. Useful from within gdb +*/ +void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f) +{ + int i; + + for (i = 0; i < result->count; i++) { + struct ldb_ldif ldif; + fprintf(f, "# record %d\n", i+1); + ldif.changetype = LDB_CHANGETYPE_NONE; + ldif.msg = result->msgs[i]; + ldb_ldif_write_file(ldb, f, &ldif); + } +} + +int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value) +{ + struct ldb_message_element *el; + struct ldb_val val; + + el = ldb_msg_find_element(msg, name); + if (el == NULL) + return 0; + + val.data = discard_const_p(uint8_t, value); + val.length = strlen(value); + + if (ldb_msg_find_val(el, &val)) + return 1; + + return 0; +} diff --git a/ldb/common/ldb_parse.c b/ldb/common/ldb_parse.c new file mode 100644 index 000000000..8c970a442 --- /dev/null +++ b/ldb/common/ldb_parse.c @@ -0,0 +1,819 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb expression parsing + * + * Description: parse LDAP-like search expressions + * + * Author: Andrew Tridgell + */ + +/* + TODO: + - add RFC2254 binary string handling + - possibly add ~=, <= and >= handling + - expand the test suite + - add better parse error handling + +*/ + +#include "ldb_includes.h" +#include "system/locale.h" + +/* +a filter is defined by: + ::= '(' ')' + ::= | | | + ::= '&' + ::= '|' + ::= '!' + ::= | + ::= + ::= '=' | '~=' | '<=' | '>=' +*/ + +/* + decode a RFC2254 binary string representation of a buffer. + Used in LDAP filters. +*/ +struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str) +{ + int i, j; + struct ldb_val ret; + int slen = str?strlen(str):0; + + ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1); + ret.length = 0; + if (ret.data == NULL) return ret; + + for (i=j=0;idata == NULL) return NULL; + + val++; + } + + if (ret != NULL) { + ret[val] = NULL; + } + + return ret; +} + +static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s); + + +/* + parse an extended match + + possible forms: + (attr:oid:=value) + (attr:dn:oid:=value) + (attr:dn:=value) + (:dn:oid:=value) + + the ':dn' part sets the dnAttributes boolean if present + the oid sets the rule_id string + +*/ +static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret, + char *attr, char *value) +{ + char *p1, *p2; + + ret->operation = LDB_OP_EXTENDED; + ret->u.extended.value = ldb_binary_decode(ret, value); + if (ret->u.extended.value.data == NULL) goto failed; + + p1 = strchr(attr, ':'); + if (p1 == NULL) goto failed; + p2 = strchr(p1+1, ':'); + + *p1 = 0; + if (p2) *p2 = 0; + + ret->u.extended.attr = attr; + if (strcmp(p1+1, "dn") == 0) { + ret->u.extended.dnAttributes = 1; + if (p2) { + ret->u.extended.rule_id = talloc_strdup(ret, p2+1); + if (ret->u.extended.rule_id == NULL) goto failed; + } else { + ret->u.extended.rule_id = NULL; + } + } else { + ret->u.extended.dnAttributes = 0; + ret->u.extended.rule_id = talloc_strdup(ret, p1+1); + if (ret->u.extended.rule_id == NULL) goto failed; + } + + return ret; + +failed: + talloc_free(ret); + return NULL; +} + +static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char **value, const char **s) +{ + enum ldb_parse_op filter = 0; + char *name, *val, *k; + const char *p = *s; + const char *t, *t1; + + /* retrieve attributetype name */ + t = p; + + if (*p == '@') { /* for internal attributes the first char can be @ */ + p++; + } + + while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-')) { /* attribute names can only be alphanums */ + p++; + } + + if (*p == ':') { /* but extended searches have : and . chars too */ + p = strstr(p, ":="); + if (p == NULL) { /* malformed attribute name */ + return 0; + } + } + + t1 = p; + + while (isspace((unsigned char)*p)) p++; + + if (!strchr("=<>~:", *p)) { + return 0; + } + + /* save name */ + name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1); + if (name == NULL) return 0; + name[t1 - t] = '\0'; + + /* retrieve filtertype */ + + if (*p == '=') { + filter = LDB_OP_EQUALITY; + } else if (*(p + 1) == '=') { + switch (*p) { + case '<': + filter = LDB_OP_LESS; + p++; + break; + case '>': + filter = LDB_OP_GREATER; + p++; + break; + case '~': + filter = LDB_OP_APPROX; + p++; + break; + case ':': + filter = LDB_OP_EXTENDED; + p++; + break; + } + } + if (!filter) { + talloc_free(name); + return filter; + } + p++; + + while (isspace((unsigned char)*p)) p++; + + /* retieve value */ + t = p; + + while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++; + + val = (char *)talloc_memdup(mem_ctx, t, p - t + 1); + if (val == NULL) { + talloc_free(name); + return 0; + } + val[p - t] = '\0'; + + k = &(val[p - t]); + + /* remove trailing spaces from value */ + while ((k > val) && (isspace((unsigned char)*(k - 1)))) k--; + *k = '\0'; + + *type = name; + *value = val; + *s = p; + return filter; +} + +/* + ::= +*/ +static struct ldb_parse_tree *ldb_parse_simple(void *mem_ctx, const char **s) +{ + char *attr, *value; + struct ldb_parse_tree *ret; + enum ldb_parse_op filtertype; + + ret = talloc(mem_ctx, struct ldb_parse_tree); + if (!ret) { + errno = ENOMEM; + return NULL; + } + + filtertype = ldb_parse_filtertype(ret, &attr, &value, s); + if (!filtertype) { + talloc_free(ret); + return NULL; + } + + switch (filtertype) { + + case LDB_OP_PRESENT: + ret->operation = LDB_OP_PRESENT; + ret->u.present.attr = attr; + break; + + case LDB_OP_EQUALITY: + + if (strcmp(value, "*") == 0) { + ret->operation = LDB_OP_PRESENT; + ret->u.present.attr = attr; + break; + } + + if (ldb_parse_find_wildcard(value) != NULL) { + ret->operation = LDB_OP_SUBSTRING; + ret->u.substring.attr = attr; + ret->u.substring.start_with_wildcard = 0; + ret->u.substring.end_with_wildcard = 0; + ret->u.substring.chunks = ldb_wildcard_decode(ret, value); + if (ret->u.substring.chunks == NULL){ + talloc_free(ret); + return NULL; + } + if (value[0] == '*') + ret->u.substring.start_with_wildcard = 1; + if (value[strlen(value) - 1] == '*') + ret->u.substring.end_with_wildcard = 1; + talloc_free(value); + + break; + } + + ret->operation = LDB_OP_EQUALITY; + ret->u.equality.attr = attr; + ret->u.equality.value = ldb_binary_decode(ret, value); + if (ret->u.equality.value.data == NULL) { + talloc_free(ret); + return NULL; + } + talloc_free(value); + break; + + case LDB_OP_GREATER: + ret->operation = LDB_OP_GREATER; + ret->u.comparison.attr = attr; + ret->u.comparison.value = ldb_binary_decode(ret, value); + if (ret->u.comparison.value.data == NULL) { + talloc_free(ret); + return NULL; + } + talloc_free(value); + break; + + case LDB_OP_LESS: + ret->operation = LDB_OP_LESS; + ret->u.comparison.attr = attr; + ret->u.comparison.value = ldb_binary_decode(ret, value); + if (ret->u.comparison.value.data == NULL) { + talloc_free(ret); + return NULL; + } + talloc_free(value); + break; + + case LDB_OP_APPROX: + ret->operation = LDB_OP_APPROX; + ret->u.comparison.attr = attr; + ret->u.comparison.value = ldb_binary_decode(ret, value); + if (ret->u.comparison.value.data == NULL) { + talloc_free(ret); + return NULL; + } + talloc_free(value); + break; + + case LDB_OP_EXTENDED: + + ret = ldb_parse_extended(ret, attr, value); + break; + + default: + talloc_free(ret); + return NULL; + } + + return ret; +} + + +/* + parse a filterlist + ::= '&' + ::= '|' + ::= | +*/ +static struct ldb_parse_tree *ldb_parse_filterlist(void *mem_ctx, const char **s) +{ + struct ldb_parse_tree *ret, *next; + enum ldb_parse_op op; + const char *p = *s; + + switch (*p) { + case '&': + op = LDB_OP_AND; + break; + case '|': + op = LDB_OP_OR; + break; + default: + return NULL; + } + p++; + + while (isspace((unsigned char)*p)) p++; + + ret = talloc(mem_ctx, struct ldb_parse_tree); + if (!ret) { + errno = ENOMEM; + return NULL; + } + + ret->operation = op; + ret->u.list.num_elements = 1; + ret->u.list.elements = talloc(ret, struct ldb_parse_tree *); + if (!ret->u.list.elements) { + errno = ENOMEM; + talloc_free(ret); + return NULL; + } + + ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &p); + if (!ret->u.list.elements[0]) { + talloc_free(ret); + return NULL; + } + + while (isspace((unsigned char)*p)) p++; + + while (*p && (next = ldb_parse_filter(ret->u.list.elements, &p))) { + struct ldb_parse_tree **e; + e = talloc_realloc(ret, ret->u.list.elements, + struct ldb_parse_tree *, + ret->u.list.num_elements + 1); + if (!e) { + errno = ENOMEM; + talloc_free(ret); + return NULL; + } + ret->u.list.elements = e; + ret->u.list.elements[ret->u.list.num_elements] = next; + ret->u.list.num_elements++; + while (isspace((unsigned char)*p)) p++; + } + + *s = p; + + return ret; +} + + +/* + ::= '!' +*/ +static struct ldb_parse_tree *ldb_parse_not(void *mem_ctx, const char **s) +{ + struct ldb_parse_tree *ret; + const char *p = *s; + + if (*p != '!') { + return NULL; + } + p++; + + ret = talloc(mem_ctx, struct ldb_parse_tree); + if (!ret) { + errno = ENOMEM; + return NULL; + } + + ret->operation = LDB_OP_NOT; + ret->u.isnot.child = ldb_parse_filter(ret, &p); + if (!ret->u.isnot.child) { + talloc_free(ret); + return NULL; + } + + *s = p; + + return ret; +} + +/* + parse a filtercomp + ::= | | | +*/ +static struct ldb_parse_tree *ldb_parse_filtercomp(void *mem_ctx, const char **s) +{ + struct ldb_parse_tree *ret; + const char *p = *s; + + while (isspace((unsigned char)*p)) p++; + + switch (*p) { + case '&': + ret = ldb_parse_filterlist(mem_ctx, &p); + break; + + case '|': + ret = ldb_parse_filterlist(mem_ctx, &p); + break; + + case '!': + ret = ldb_parse_not(mem_ctx, &p); + break; + + case '(': + case ')': + return NULL; + + default: + ret = ldb_parse_simple(mem_ctx, &p); + + } + + *s = p; + return ret; +} + + +/* + ::= '(' ')' +*/ +static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s) +{ + struct ldb_parse_tree *ret; + const char *p = *s; + + if (*p != '(') { + return NULL; + } + p++; + + ret = ldb_parse_filtercomp(mem_ctx, &p); + + if (*p != ')') { + return NULL; + } + p++; + + while (isspace((unsigned char)*p)) { + p++; + } + + *s = p; + + return ret; +} + + +/* + main parser entry point. Takes a search string and returns a parse tree + + expression ::= | +*/ +struct ldb_parse_tree *ldb_parse_tree(void *mem_ctx, const char *s) +{ + if (s == NULL || *s == 0) { + s = "(|(objectClass=*)(distinguishedName=*))"; + } + + while (isspace((unsigned char)*s)) s++; + + if (*s == '(') { + return ldb_parse_filter(mem_ctx, &s); + } + + return ldb_parse_simple(mem_ctx, &s); +} + + +/* + construct a ldap parse filter given a parse tree +*/ +char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree) +{ + char *s, *s2, *ret; + int i; + + if (tree == NULL) { + return NULL; + } + + switch (tree->operation) { + case LDB_OP_AND: + case LDB_OP_OR: + ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|'); + if (ret == NULL) return NULL; + for (i=0;iu.list.num_elements;i++) { + s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]); + if (s == NULL) { + talloc_free(ret); + return NULL; + } + s2 = talloc_asprintf_append(ret, "%s", s); + talloc_free(s); + if (s2 == NULL) { + talloc_free(ret); + return NULL; + } + ret = s2; + } + s = talloc_asprintf_append(ret, ")"); + if (s == NULL) { + talloc_free(ret); + return NULL; + } + return s; + case LDB_OP_NOT: + s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child); + if (s == NULL) return NULL; + + ret = talloc_asprintf(mem_ctx, "(!%s)", s); + talloc_free(s); + return ret; + case LDB_OP_EQUALITY: + s = ldb_binary_encode(mem_ctx, tree->u.equality.value); + if (s == NULL) return NULL; + ret = talloc_asprintf(mem_ctx, "(%s=%s)", + tree->u.equality.attr, s); + talloc_free(s); + return ret; + case LDB_OP_SUBSTRING: + ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr, + tree->u.substring.start_with_wildcard?"*":""); + if (ret == NULL) return NULL; + for (i = 0; tree->u.substring.chunks[i]; i++) { + s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i])); + if (s2 == NULL) { + talloc_free(ret); + return NULL; + } + if (tree->u.substring.chunks[i+1] || + tree->u.substring.end_with_wildcard) { + s = talloc_asprintf_append(ret, "%s*", s2); + } else { + s = talloc_asprintf_append(ret, "%s", s2); + } + if (s == NULL) { + talloc_free(ret); + return NULL; + } + ret = s; + } + s = talloc_asprintf_append(ret, ")"); + if (s == NULL) { + talloc_free(ret); + return NULL; + } + ret = s; + return ret; + case LDB_OP_GREATER: + s = ldb_binary_encode(mem_ctx, tree->u.equality.value); + if (s == NULL) return NULL; + ret = talloc_asprintf(mem_ctx, "(%s>=%s)", + tree->u.equality.attr, s); + talloc_free(s); + return ret; + case LDB_OP_LESS: + s = ldb_binary_encode(mem_ctx, tree->u.equality.value); + if (s == NULL) return NULL; + ret = talloc_asprintf(mem_ctx, "(%s<=%s)", + tree->u.equality.attr, s); + talloc_free(s); + return ret; + case LDB_OP_PRESENT: + ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr); + return ret; + case LDB_OP_APPROX: + s = ldb_binary_encode(mem_ctx, tree->u.equality.value); + if (s == NULL) return NULL; + ret = talloc_asprintf(mem_ctx, "(%s~=%s)", + tree->u.equality.attr, s); + talloc_free(s); + return ret; + case LDB_OP_EXTENDED: + s = ldb_binary_encode(mem_ctx, tree->u.extended.value); + if (s == NULL) return NULL; + ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)", + tree->u.extended.attr?tree->u.extended.attr:"", + tree->u.extended.dnAttributes?":dn":"", + tree->u.extended.rule_id?":":"", + tree->u.extended.rule_id?tree->u.extended.rule_id:"", + s); + talloc_free(s); + return ret; + } + + return NULL; +} + + +/* + replace any occurances of an attribute name in the parse tree with a + new name +*/ +void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree, + const char *attr, + const char *replace) +{ + int i; + switch (tree->operation) { + case LDB_OP_AND: + case LDB_OP_OR: + for (i=0;iu.list.num_elements;i++) { + ldb_parse_tree_attr_replace(tree->u.list.elements[i], + attr, replace); + } + break; + case LDB_OP_NOT: + ldb_parse_tree_attr_replace(tree->u.isnot.child, attr, replace); + break; + case LDB_OP_EQUALITY: + case LDB_OP_GREATER: + case LDB_OP_LESS: + case LDB_OP_APPROX: + if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) { + tree->u.equality.attr = replace; + } + break; + case LDB_OP_SUBSTRING: + if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) { + tree->u.substring.attr = replace; + } + break; + case LDB_OP_PRESENT: + if (ldb_attr_cmp(tree->u.present.attr, attr) == 0) { + tree->u.present.attr = replace; + } + break; + case LDB_OP_EXTENDED: + if (tree->u.extended.attr && + ldb_attr_cmp(tree->u.extended.attr, attr) == 0) { + tree->u.extended.attr = replace; + } + break; + } +} diff --git a/ldb/common/ldb_utf8.c b/ldb/common/ldb_utf8.c new file mode 100644 index 000000000..69ee2b696 --- /dev/null +++ b/ldb/common/ldb_utf8.c @@ -0,0 +1,136 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb utf8 handling + * + * Description: case folding and case comparison for UTF8 strings + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" +#include "system/locale.h" + + +/* + this allow the user to pass in a caseless comparison + function to handle utf8 caseless comparisons + */ +void ldb_set_utf8_fns(struct ldb_context *ldb, + void *context, + char *(*casefold)(void *, void *, const char *, size_t)) +{ + if (context) + ldb->utf8_fns.context = context; + if (casefold) + ldb->utf8_fns.casefold = casefold; +} + +/* + a simple case folding function + NOTE: does not handle UTF8 +*/ +char *ldb_casefold_default(void *context, void *mem_ctx, const char *s, size_t n) +{ + int i; + char *ret = talloc_strndup(mem_ctx, s, n); + if (!s) { + errno = ENOMEM; + return NULL; + } + for (i=0;ret[i];i++) { + ret[i] = toupper((unsigned char)ret[i]); + } + return ret; +} + +void ldb_set_utf8_default(struct ldb_context *ldb) +{ + ldb_set_utf8_fns(ldb, NULL, ldb_casefold_default); +} + +char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s, size_t n) +{ + return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s, n); +} + +/* + check the attribute name is valid according to rfc2251 + returns 1 if the name is ok + */ + +int ldb_valid_attr_name(const char *s) +{ + int i; + + if (!s || !s[0]) + return 0; + + /* handle special ldb_tdb wildcard */ + if (strcmp(s, "*") == 0) return 1; + + for (i = 0; s[i]; i++) { + if (! isascii(s[i])) { + return 0; + } + if (i == 0) { /* first char must be an alpha (or our special '@' identifier) */ + if (! (isalpha(s[i]) || (s[i] == '@'))) { + return 0; + } + } else { + if (! (isalnum(s[i]) || (s[i] == '-'))) { + return 0; + } + } + } + return 1; +} + +char *ldb_attr_casefold(void *mem_ctx, const char *s) +{ + int i; + char *ret = talloc_strdup(mem_ctx, s); + if (!ret) { + errno = ENOMEM; + return NULL; + } + for (i = 0; ret[i]; i++) { + ret[i] = toupper((unsigned char)ret[i]); + } + return ret; +} + +/* + we accept either 'dn' or 'distinguishedName' for a distinguishedName +*/ +int ldb_attr_dn(const char *attr) +{ + if (ldb_attr_cmp(attr, "dn") == 0 || + ldb_attr_cmp(attr, "distinguishedName") == 0) { + return 0; + } + return -1; +} diff --git a/ldb/common/qsort.c b/ldb/common/qsort.c new file mode 100644 index 000000000..0fa76d3b4 --- /dev/null +++ b/ldb/common/qsort.c @@ -0,0 +1,251 @@ +/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Douglas C. Schmidt (schmidt@ics.uci.edu). + + 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 2.1 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 + Lesser 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; if not, see . */ + +/* If you consider tuning this algorithm, you should consult first: + Engineering a sort function; Jon Bentley and M. Douglas McIlroy; + Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */ + +/* Modified to be used in samba4 by + * Simo Sorce 2005 + */ + +#include "ldb_includes.h" + +/* Byte-wise swap two items of size SIZE. */ +#define SWAP(a, b, size) \ + do \ + { \ + register size_t __size = (size); \ + register char *__a = (a), *__b = (b); \ + do \ + { \ + char __tmp = *__a; \ + *__a++ = *__b; \ + *__b++ = __tmp; \ + } while (--__size > 0); \ + } while (0) + +/* Discontinue quicksort algorithm when partition gets below this size. + This particular magic number was chosen to work best on a Sun 4/260. */ +#define MAX_THRESH 4 + +/* Stack node declarations used to store unfulfilled partition obligations. */ +typedef struct + { + char *lo; + char *hi; + } stack_node; + +/* The next 4 #defines implement a very fast in-line stack abstraction. */ +/* The stack needs log (total_elements) entries (we could even subtract + log(MAX_THRESH)). Since total_elements has type size_t, we get as + upper bound for log (total_elements): + bits per byte (CHAR_BIT) * sizeof(size_t). */ +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif +#define STACK_SIZE (CHAR_BIT * sizeof(size_t)) +#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) +#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) +#define STACK_NOT_EMPTY (stack < top) + + +/* Order size using quicksort. This implementation incorporates + four optimizations discussed in Sedgewick: + + 1. Non-recursive, using an explicit stack of pointer that store the + next array partition to sort. To save time, this maximum amount + of space required to store an array of SIZE_MAX is allocated on the + stack. Assuming a 32-bit (64 bit) integer for size_t, this needs + only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes). + Pretty cheap, actually. + + 2. Chose the pivot element using a median-of-three decision tree. + This reduces the probability of selecting a bad pivot value and + eliminates certain extraneous comparisons. + + 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving + insertion sort to order the MAX_THRESH items within each partition. + This is a big win, since insertion sort is faster for small, mostly + sorted array segments. + + 4. The larger of the two sub-partitions is always pushed onto the + stack first, with the algorithm then concentrating on the + smaller partition. This *guarantees* no more than log (total_elems) + stack size is needed (actually O(1) in this case)! */ + +void ldb_qsort (void *const pbase, size_t total_elems, size_t size, + void *opaque, ldb_qsort_cmp_fn_t cmp) +{ + register char *base_ptr = (char *) pbase; + + const size_t max_thresh = MAX_THRESH * size; + + if (total_elems == 0) + /* Avoid lossage with unsigned arithmetic below. */ + return; + + if (total_elems > MAX_THRESH) + { + char *lo = base_ptr; + char *hi = &lo[size * (total_elems - 1)]; + stack_node stack[STACK_SIZE]; + stack_node *top = stack; + + PUSH (NULL, NULL); + + while (STACK_NOT_EMPTY) + { + char *left_ptr; + char *right_ptr; + + /* Select median value from among LO, MID, and HI. Rearrange + LO and HI so the three values are sorted. This lowers the + probability of picking a pathological pivot value and + skips a comparison for both the LEFT_PTR and RIGHT_PTR in + the while loops. */ + + char *mid = lo + size * ((hi - lo) / size >> 1); + + if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0) + SWAP (mid, lo, size); + if ((*cmp) ((void *) hi, (void *) mid, opaque) < 0) + SWAP (mid, hi, size); + else + goto jump_over; + if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0) + SWAP (mid, lo, size); + jump_over:; + + left_ptr = lo + size; + right_ptr = hi - size; + + /* Here's the famous ``collapse the walls'' section of quicksort. + Gotta like those tight inner loops! They are the main reason + that this algorithm runs much faster than others. */ + do + { + while ((*cmp) ((void *) left_ptr, (void *) mid, opaque) < 0) + left_ptr += size; + + while ((*cmp) ((void *) mid, (void *) right_ptr, opaque) < 0) + right_ptr -= size; + + if (left_ptr < right_ptr) + { + SWAP (left_ptr, right_ptr, size); + if (mid == left_ptr) + mid = right_ptr; + else if (mid == right_ptr) + mid = left_ptr; + left_ptr += size; + right_ptr -= size; + } + else if (left_ptr == right_ptr) + { + left_ptr += size; + right_ptr -= size; + break; + } + } + while (left_ptr <= right_ptr); + + /* Set up pointers for next iteration. First determine whether + left and right partitions are below the threshold size. If so, + ignore one or both. Otherwise, push the larger partition's + bounds on the stack and continue sorting the smaller one. */ + + if ((size_t) (right_ptr - lo) <= max_thresh) + { + if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore both small partitions. */ + POP (lo, hi); + else + /* Ignore small left partition. */ + lo = left_ptr; + } + else if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore small right partition. */ + hi = right_ptr; + else if ((right_ptr - lo) > (hi - left_ptr)) + { + /* Push larger left partition indices. */ + PUSH (lo, right_ptr); + lo = left_ptr; + } + else + { + /* Push larger right partition indices. */ + PUSH (left_ptr, hi); + hi = right_ptr; + } + } + } + + /* Once the BASE_PTR array is partially sorted by quicksort the rest + is completely sorted using insertion sort, since this is efficient + for partitions below MAX_THRESH size. BASE_PTR points to the beginning + of the array to sort, and END_PTR points at the very last element in + the array (*not* one beyond it!). */ + +#define min(x, y) ((x) < (y) ? (x) : (y)) + + { + char *const end_ptr = &base_ptr[size * (total_elems - 1)]; + char *tmp_ptr = base_ptr; + char *thresh = min(end_ptr, base_ptr + max_thresh); + register char *run_ptr; + + /* Find smallest element in first threshold and place it at the + array's beginning. This is the smallest array element, + and the operation speeds up insertion sort's inner loop. */ + + for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) + if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0) + tmp_ptr = run_ptr; + + if (tmp_ptr != base_ptr) + SWAP (tmp_ptr, base_ptr, size); + + /* Insertion sort, running from left-hand-side up to right-hand-side. */ + + run_ptr = base_ptr + size; + while ((run_ptr += size) <= end_ptr) + { + tmp_ptr = run_ptr - size; + while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0) + tmp_ptr -= size; + + tmp_ptr += size; + if (tmp_ptr != run_ptr) + { + char *trav; + + trav = run_ptr + size; + while (--trav >= run_ptr) + { + char c = *trav; + char *hi, *lo; + + for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) + *hi = *lo; + *hi = c; + } + } + } + } +} diff --git a/ldb/config.guess b/ldb/config.guess new file mode 100755 index 000000000..354dbe175 --- /dev/null +++ b/ldb/config.guess @@ -0,0 +1,1464 @@ +#! /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 Free Software Foundation, Inc. + +timestamp='2005-08-03' + +# 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 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 . +# +# 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 . +# Please send patches to . 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 ." + +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 +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 -q "$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@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 ;; + *) 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 ;; + macppc:MirBSD:*:*) + echo powerppc-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@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 ;; + 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.*:*) + echo i386-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 /* 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 + + 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:*:[45]) + 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 + #include + + 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 + 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:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*: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 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [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:*:*) + 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 | grep ^CPU=` + 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 | grep ^CPU=` + 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 ;; + 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 ;; + x86_64:Linux:*:*) + echo x86_64-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 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + 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 + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + 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' /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 i386. + echo i386-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; } ;; + 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 + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@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 ;; + 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 ;; + 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 + *86) UNAME_PROCESSOR=i686 ;; + 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 ;; +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 < +# include +#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 + 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 +# 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 < 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: diff --git a/ldb/config.mk b/ldb/config.mk new file mode 100644 index 000000000..fe3b71d1d --- /dev/null +++ b/ldb/config.mk @@ -0,0 +1,151 @@ +################################################ +# Start MODULE ldb_asq +[MODULE::ldb_asq] +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS +CFLAGS = -I$(ldbsrcdir)/include +INIT_FUNCTION = LDB_MODULE(asq) +SUBSYSTEM = LIBLDB + +ldb_asq_OBJ_FILES = $(ldbsrcdir)/modules/asq.o +# End MODULE ldb_asq +################################################ + +################################################ +# Start MODULE ldb_server_sort +[MODULE::ldb_server_sort] +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS +CFLAGS = -I$(ldbsrcdir)/include +INIT_FUNCTION = LDB_MODULE(server_sort) +SUBSYSTEM = LIBLDB + +# End MODULE ldb_sort +################################################ +ldb_server_sort_OBJ_FILES = $(ldbsrcdir)/modules/sort.o + +################################################ +# Start MODULE ldb_paged_results +[MODULE::ldb_paged_results] +INIT_FUNCTION = LDB_MODULE(paged_results) +CFLAGS = -I$(ldbsrcdir)/include +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS +SUBSYSTEM = LIBLDB +# End MODULE ldb_paged_results +################################################ + +ldb_paged_results_OBJ_FILES = $(ldbsrcdir)/modules/paged_results.o + +################################################ +# Start MODULE ldb_paged_results +[MODULE::ldb_paged_searches] +INIT_FUNCTION = LDB_MODULE(paged_searches) +CFLAGS = -I$(ldbsrcdir)/include +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS +SUBSYSTEM = LIBLDB +# End MODULE ldb_paged_results +################################################ + +ldb_paged_searches_OBJ_FILES = $(ldbsrcdir)/modules/paged_searches.o + +################################################ +# Start MODULE ldb_operational +[MODULE::ldb_operational] +SUBSYSTEM = LIBLDB +CFLAGS = -I$(ldbsrcdir)/include +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS +INIT_FUNCTION = LDB_MODULE(operational) +# End MODULE ldb_operational +################################################ + +ldb_operational_OBJ_FILES = $(ldbsrcdir)/modules/operational.o + +################################################ +# Start MODULE ldb_rdn_name +[MODULE::ldb_rdn_name] +SUBSYSTEM = LIBLDB +CFLAGS = -I$(ldbsrcdir)/include +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS +INIT_FUNCTION = LDB_MODULE(rdn_name) +# End MODULE ldb_rdn_name +################################################ + +ldb_rdn_name_OBJ_FILES = $(ldbsrcdir)/modules/rdn_name.o + +ldb_map_OBJ_FILES = $(addprefix $(ldbsrcdir)/ldb_map/, ldb_map_inbound.o ldb_map_outbound.o ldb_map.o) + +$(ldb_map_OBJ_FILES): CFLAGS+=-I$(ldbsrcdir)/ldb_map + +################################################ +# Start MODULE ldb_skel +[MODULE::ldb_skel] +SUBSYSTEM = LIBLDB +CFLAGS = -I$(ldbsrcdir)/include +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS +INIT_FUNCTION = LDB_MODULE(skel) +# End MODULE ldb_skel +################################################ + +ldb_skel_OBJ_FILES = $(ldbsrcdir)/modules/skel.o + +################################################ +# Start MODULE ldb_sqlite3 +[MODULE::ldb_sqlite3] +SUBSYSTEM = LIBLDB +CFLAGS = -I$(ldbsrcdir)/include +PRIVATE_DEPENDENCIES = LIBTALLOC SQLITE3 LIBEVENTS +INIT_FUNCTION = LDB_BACKEND(sqlite3) +# End MODULE ldb_sqlite3 +################################################ + +ldb_sqlite3_OBJ_FILES = $(ldbsrcdir)/ldb_sqlite3/ldb_sqlite3.o + +################################################ +# Start MODULE ldb_tdb +[MODULE::ldb_tdb] +SUBSYSTEM = LIBLDB +CFLAGS = -I$(ldbsrcdir)/include -I$(ldbsrcdir)/ldb_tdb +PRIVATE_DEPENDENCIES = \ + LIBTDB LIBTALLOC LIBEVENTS +INIT_FUNCTION = LDB_BACKEND(tdb) +# End MODULE ldb_tdb +################################################ + +ldb_tdb_OBJ_FILES = $(addprefix $(ldbsrcdir)/ldb_tdb/, ldb_tdb.o ldb_search.o ldb_pack.o ldb_index.o ldb_cache.o ldb_tdb_wrap.o) + + +################################################ +# Start SUBSYSTEM ldb +[LIBRARY::LIBLDB] +CFLAGS = -I$(ldbsrcdir)/include +PUBLIC_DEPENDENCIES = \ + LIBTALLOC LIBEVENTS +PRIVATE_DEPENDENCIES = \ + SOCKET_WRAPPER + +PC_FILES += $(ldbsrcdir)/ldb.pc +# +# End SUBSYSTEM ldb +################################################ + +LIBLDB_VERSION = 0.0.1 +LIBLDB_SOVERSION = 0 + +LIBLDB_OBJ_FILES = $(addprefix $(ldbsrcdir)/common/, ldb.o ldb_ldif.o ldb_parse.o ldb_msg.o ldb_utf8.o ldb_debug.o ldb_modules.o ldb_match.o ldb_attributes.o attrib_handlers.o ldb_dn.o ldb_controls.o qsort.o) $(ldb_map_OBJ_FILES) + +$(LIBLDB_OBJ_FILES): CFLAGS+=-I$(ldbsrcdir)/include + +PUBLIC_HEADERS += $(ldbsrcdir)/include/ldb.h $(ldbsrcdir)/include/ldb_errors.h + +MANPAGES += $(ldbsrcdir)/man/ldb.3 + +################################################ +# Start BINARY ldbtest +[BINARY::ldbtest] +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbtest +################################################ + +ldbtest_OBJ_FILES = $(ldbsrcdir)/tools/ldbtest.o + +mkinclude tools/config.mk +mkinclude ldb_ildap/config.mk diff --git a/ldb/config.sub b/ldb/config.sub new file mode 100755 index 000000000..23cd6fd75 --- /dev/null +++ b/ldb/config.sub @@ -0,0 +1,1577 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-08' + +# 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 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 . +# +# 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 . 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 ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +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-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-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 + ;; + -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/'` + ;; + -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 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + 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) + ;; + + # 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-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | 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[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # 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 + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + 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 + ;; + cr16c) + basic_machine=cr16c-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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + 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 + ;; + 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 + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + 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 + ;; + 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 + ;; + 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[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + 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* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -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* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -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*) + # 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 + ;; + -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 + *-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 + ;; + 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: diff --git a/ldb/configure.ac b/ldb/configure.ac new file mode 100644 index 000000000..1abb08fa8 --- /dev/null +++ b/ldb/configure.ac @@ -0,0 +1,102 @@ +AC_PREREQ(2.50) +AC_DEFUN([AC_CHECK_LIB_EXT], [ + AC_CHECK_LIB([$1],[$3],[$4],[$5],[$7]) + ac_cv_lib_ext_$1_$3=$ac_cv_lib_$1_$3 +]) +AC_DEFUN([AC_CHECK_FUNC_EXT], [ + AC_CHECK_FUNC([$1],[$3],[$4]) + ac_cv_func_ext_$1=$ac_cv_func_$1 +]) +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_INIT(ldb, 0.9.2) +AC_CONFIG_SRCDIR([common/ldb.c]) + +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 + +WITH_GCOV=0 +AC_ARG_ENABLE(gcov, + AS_HELP_STRING([--enable-gcov],[enable GCOV code coverage tests]), + [ WITH_GCOV=1]) +AC_SUBST(WITH_GCOV) +if test x"$with_gcov_support" = x"yes"; then + CFLAGS="$CFLAGS -ftest-coverage -fprofile-arcs" + LIBS="$LIBS -lgcov" +fi + +AC_PATH_PROG(XSLTPROC,xsltproc) +AC_PATH_PROG(DOXYGEN,doxygen) +AC_PATH_PROG(GCOV,gcov) +AC_PATH_PROG(SLAPD,slapd) +AC_CHECK_HEADERS(stdint.h dlfcn.h) +AC_CONFIG_HEADER(include/config.h) + +AC_DEFINE_UNQUOTED(LDB_MODULESDIR, LIBDIR "/ldb" , [Modules directory] ) +AC_SUBST(LDB_MODULESDIR) + +TESTS="" +EXTRA_OBJ="" + +m4_include(build_macros.m4) +BUILD_WITH_BUILD_INST_DIR + +m4_include(pkg.m4) +m4_include(libpopt.m4) +m4_include(libtalloc.m4) +m4_include(libtdb.m4) +m4_include(libevents.m4) + +m4_include(ldap.m4) +if test x"$with_ldap_support" = x"yes"; then + CFLAGS="$CFLAGS -DHAVE_LDB_LDAP=1" + EXTRA_OBJ="$EXTRA_OBJ ldb_ldap/ldb_ldap.o" + LDAP_LIBS="-llber -lldap" + AC_SUBST(LDAP_LIBS) + TESTS="$TESTS test-ldap.sh" +fi + +m4_include(sqlite3.m4) +if test x"$with_sqlite3_support" = x"yes"; then + LIBS="$LIBS -lsqlite3" + CFLAGS="$CFLAGS -DHAVE_LDB_SQLITE3=1" + EXTRA_OBJ="$EXTRA_OBJ ldb_sqlite3/ldb_sqlite3.o" + TESTS="$TESTS test-sqlite3.sh" +fi + +AC_SUBST(TESTS) +AC_SUBST(EXTRA_OBJ) + +AC_LD_EXPORT_DYNAMIC +AC_LD_PICFLAG +AC_LD_SHLIBEXT +AC_LD_SONAMEFLAG +AC_LIBREPLACE_SHLD +AC_LIBREPLACE_SHLD_FLAGS +AC_LIBREPLACE_MDLD +AC_LIBREPLACE_MDLD_FLAGS +AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR + +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_CHECK_TARGET="" + PYTHON_INSTALL_TARGET="" +fi + +m4_include(libldb.m4) +AC_OUTPUT(Makefile ldb.pc) diff --git a/ldb/docs/builddocs.sh b/ldb/docs/builddocs.sh new file mode 100755 index 000000000..449dcb268 --- /dev/null +++ b/ldb/docs/builddocs.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# build ldb docs +# tridge@samba.org August 2006 + +XSLTPROC="$1" +SRCDIR="$2" + +if [ -z "$XSLTPROC" ] || [ ! -x "$XSLTPROC" ]; then + echo "xsltproc not installed" + exit 0 +fi + +MANXSL="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl" +HTMLXSL="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl" + +mkdir -p man + +for f in $SRCDIR/man/*.xml; do + base=`basename $f .xml` + out=man/"`basename $base`" + if [ ! -f "$out" ] || [ "$f" -nt "$out" ]; then + echo Processing manpage $f + $XSLTPROC --nonet -o "$out" "$MANXSL" $f + ret=$? + if [ "$ret" = "4" ]; then + echo "ignoring stylesheet error 4 for $MANXSL" + exit 0 + fi + if [ "$ret" != "0" ]; then + echo "xsltproc failed with error $ret" + exit $ret + fi + fi +done + +for f in $SRCDIR/man/*.xml; do + base=`basename $f .xml` + out=man/"`basename $base`".html + if [ ! -f "$out" ] || [ "$f" -nt "$out" ]; then + echo Processing html $f + $XSLTPROC --nonet -o "$out" "$HTMLXSL" $f + ret=$? + if [ "$ret" = "4" ]; then + echo "ignoring stylesheet error 4 for $HTMLXSL" + exit 0 + fi + if [ "$ret" != "0" ]; then + echo "xsltproc failed with error $ret" + exit $ret + fi + fi +done diff --git a/ldb/docs/design.txt b/ldb/docs/design.txt new file mode 100644 index 000000000..0bb278b5b --- /dev/null +++ b/ldb/docs/design.txt @@ -0,0 +1,41 @@ +The list of indexed fields +-------------------------- + +dn=@INDEXLIST + list of field names that are indexed + + contains fields of type @IDXATTR which contain attriute names + of indexed fields + + +Data records +------------ + +for each user record in the db there is: + main record + key: DN=dn + data: packed attribute/value list + + a index record for each indexed field in the record + + +Index Records +------------- + +The index records contain the list of dn's that contain records +matching the index key + +All index records are of the form: + dn=@INDEX:field:value + +and contain fields of type @IDX which are the dns of the records +that have that value for some attribute + + +Search Expressions +------------------ + +Very similar to LDAP search expressions, but does not allow ~=, <= or >= + + attrib0 := (field=value) + attrib := attrib0 | (attrib&&attrib) | (attrib||attrib) | !attrib diff --git a/ldb/docs/installdocs.sh b/ldb/docs/installdocs.sh new file mode 100755 index 000000000..6cc7b74ad --- /dev/null +++ b/ldb/docs/installdocs.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# install ldb docs +# tridge@samba.org August 2006 + +MANDIR="$1" + +MAN1="`/bin/ls man/*.1`" +MAN3="`/bin/ls man/*.3`" + +if [ -z "$MAN1" ] && [ -z "$MAN3" ]; then + echo "No manpages have been built" + exit 0 +fi + +mkdir -p "$MANDIR/man1" "$MANDIR/man3" +cp $MAN1 "$MANDIR/man1/" || exit 1 +cp $MAN3 "$MANDIR/man3/" || exit 1 diff --git a/ldb/examples.dox b/ldb/examples.dox new file mode 100644 index 000000000..ef4b4f0a4 --- /dev/null +++ b/ldb/examples.dox @@ -0,0 +1,16 @@ +/** \example ldbreader.c + +The code below shows a simple LDB application. + +It lists / dumps the records in a LDB database to standard output. + +*/ + + +/** \example ldifreader.c + +The code below shows a simple LDB application. + +It lists / dumps the entries in an LDIF file to standard output. + +*/ diff --git a/ldb/examples/ldbreader.c b/ldb/examples/ldbreader.c new file mode 100644 index 000000000..6e5811453 --- /dev/null +++ b/ldb/examples/ldbreader.c @@ -0,0 +1,123 @@ +/* + example code for the ldb database library + + Copyright (C) Brad Hards (bradh@frogmouth.net) 2005-2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/** \example ldbreader.c + +The code below shows a simple LDB application. + +It lists / dumps the records in a LDB database to standard output. + +*/ + +#include "ldb_includes.h" +#include "ldb.h" +#include "ldb_errors.h" + +/* + ldb_ldif_write takes a function pointer to a custom output + function. This version is about as simple as the output function can + be. In a more complex example, you'd likely be doing something with + the private data function (e.g. holding a file handle). +*/ +static int vprintf_fn(void *private_data, const char *fmt, ...) +{ + int retval; + va_list ap; + + va_start(ap, fmt); + /* We just write to standard output */ + retval = vprintf(fmt, ap); + va_end(ap); + /* Note that the function should return the number of + bytes written, or a negative error code */ + return retval; +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + const char *expression = "(dn=*)"; + struct ldb_result *resultMsg; + int i; + + /* + This is the always the first thing you want to do in an LDB + application - initialise up the context structure. + + Note that you can use the context structure as a parent + for talloc allocations as well + */ + ldb = ldb_init(NULL, NULL); + + /* + We now open the database. In this example we just hard code the connection path. + + Also note that the database is being opened read-only. This means that the + call will fail unless the database already exists. + */ + if (LDB_SUCCESS != ldb_connect(ldb, "tdb://tdbtest.ldb", LDB_FLG_RDONLY, NULL) ){ + printf("Problem on connection\n"); + exit(-1); + } + + /* + At this stage we have an open database, and can start using it. It is opened + read-only, so a query is possible. + + We construct a search that just returns all the (sensible) contents. You can do + quite fine grained results with the LDAP search syntax, however it is a bit + confusing to start with. See RFC2254. + */ + if (LDB_SUCCESS != ldb_search(ldb, NULL, LDB_SCOPE_DEFAULT, + expression, NULL, &resultMsg) ) { + printf("Problem in search\n"); + exit(-1); + } + + printf("%i records returned\n", resultMsg->count); + + /* + We can now iterate through the results, writing them out + (to standard output) with our custom output routine as defined + at the top of this file + */ + for (i = 0; i < resultMsg->count; ++i) { + struct ldb_ldif ldifMsg; + + printf("Message: %i\n", i+1); + + ldifMsg.changetype = LDB_CHANGETYPE_NONE; + ldifMsg.msg = resultMsg->msgs[i]; + ldb_ldif_write(ldb, vprintf_fn, NULL, &ldifMsg); + } + + /* + There are two objects to clean up - the result from the + ldb_search() query, and the original ldb context. + */ + talloc_free(resultMsg); + + talloc_free(ldb); + + return 0; +} diff --git a/ldb/examples/ldifreader.c b/ldb/examples/ldifreader.c new file mode 100644 index 000000000..12e7a1a6f --- /dev/null +++ b/ldb/examples/ldifreader.c @@ -0,0 +1,127 @@ +/* + example code for the ldb database library + + Copyright (C) Brad Hards (bradh@frogmouth.net) 2005-2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/** \example ldifreader.c + +The code below shows a simple LDB application. + +It lists / dumps the entries in an LDIF file to standard output. + +*/ + +#include "ldb_includes.h" +#include "ldb.h" +#include "ldb_errors.h" + +/* + ldb_ldif_write takes a function pointer to a custom output + function. This version is about as simple as the output function can + be. In a more complex example, you'd likely be doing something with + the private data function (e.g. holding a file handle). +*/ +static int vprintf_fn(void *private_data, const char *fmt, ...) +{ + int retval; + va_list ap; + + va_start(ap, fmt); + /* We just write to standard output */ + retval = vprintf(fmt, ap); + va_end(ap); + /* Note that the function should return the number of + bytes written, or a negative error code */ + return retval; +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + FILE *fileStream; + struct ldb_ldif *ldifMsg; + + if (argc != 2) { + printf("Usage %s filename.ldif\n", argv[0]); + exit(1); + } + + /* + This is the always the first thing you want to do in an LDB + application - initialise up the context structure. + + Note that you can use the context structure as a parent + for talloc allocations as well + */ + ldb = ldb_init(NULL, NULL); + + fileStream = fopen(argv[1], "r"); + if (0 == fileStream) { + perror(argv[1]); + exit(1); + } + + /* + We now work through the filestream to get each entry. + */ + while ( (ldifMsg = ldb_ldif_read_file(ldb, fileStream)) ) { + /* + Each message has a particular change type. For Add, + Modify and Delete, this will also appear in the + output listing (as changetype: add, changetype: + modify or changetype:delete, respectively). + */ + switch (ldifMsg->changetype) { + case LDB_CHANGETYPE_NONE: + printf("ChangeType: None\n"); + break; + case LDB_CHANGETYPE_ADD: + printf("ChangeType: Add\n"); + break; + case LDB_CHANGETYPE_MODIFY: + printf("ChangeType: Modify\n"); + break; + case LDB_CHANGETYPE_DELETE: + printf("ChangeType: Delete\n"); + break; + default: + printf("ChangeType: Unknown\n"); + } + + /* + We can now write out the results, using our custom + output routine as defined at the top of this file. + */ + ldb_ldif_write(ldb, vprintf_fn, NULL, ldifMsg); + + /* + Clean up the message + */ + ldb_ldif_read_free(ldb, ldifMsg); + } + + /* + Clean up the context + */ + talloc_free(ldb); + + return 0; +} diff --git a/ldb/external/libevents.m4 b/ldb/external/libevents.m4 new file mode 100644 index 000000000..4fd2e71ec --- /dev/null +++ b/ldb/external/libevents.m4 @@ -0,0 +1,7 @@ +AC_SUBST(EVENTS_OBJ) +AC_SUBST(EVENTS_CFLAGS) +AC_SUBST(EVENTS_LIBS) + +AC_CHECK_HEADER(events.h, + [AC_CHECK_LIB(events, event_context_init, [EVENTS_LIBS="-levents"]) ], + [PKG_CHECK_MODULES(EVENTS, events)]) diff --git a/ldb/external/libpopt.m4 b/ldb/external/libpopt.m4 new file mode 100644 index 000000000..c5d12550a --- /dev/null +++ b/ldb/external/libpopt.m4 @@ -0,0 +1,7 @@ +POPT_OBJ="" +AC_SUBST(POPT_OBJ) +AC_SUBST(POPT_LIBS) +AC_SUBST(POPT_CFLAGS) + +AC_CHECK_HEADERS(popt.h) +AC_CHECK_LIB(popt, poptGetContext, [ POPT_LIBS="-lpopt" ]) diff --git a/ldb/external/libtalloc.m4 b/ldb/external/libtalloc.m4 new file mode 100644 index 000000000..a4c5b8a9d --- /dev/null +++ b/ldb/external/libtalloc.m4 @@ -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)]) diff --git a/ldb/external/libtdb.m4 b/ldb/external/libtdb.m4 new file mode 100644 index 000000000..8c2cab702 --- /dev/null +++ b/ldb/external/libtdb.m4 @@ -0,0 +1,7 @@ +AC_SUBST(TDB_OBJ) +AC_SUBST(TDB_CFLAGS) +AC_SUBST(TDB_LIBS) + +AC_CHECK_HEADER(tdb.h, + [AC_CHECK_LIB(tdb, tdb_open, [TDB_LIBS="-ltdb"]) ], + [PKG_CHECK_MODULES(TDB, tdb >= 1.1.0)]) diff --git a/ldb/external/pkg.m4 b/ldb/external/pkg.m4 new file mode 100644 index 000000000..a8b3d06c8 --- /dev/null +++ b/ldb/external/pkg.m4 @@ -0,0 +1,156 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant . +# +# 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 . +# +# 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 .])], + [$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 diff --git a/ldb/include/dlinklist.h b/ldb/include/dlinklist.h new file mode 100644 index 000000000..d3252751d --- /dev/null +++ b/ldb/include/dlinklist.h @@ -0,0 +1,110 @@ +/* + Unix SMB/CIFS implementation. + some simple double linked list macros + 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 . +*/ + +/* To use these macros you must have a structure containing a next and + prev pointer */ + + +/* hook into the front of the list */ +#define DLIST_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. */ +#ifndef DLIST_REMOVE +#define DLIST_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) +#endif + +/* promote an element to the top of the list */ +#define DLIST_PROMOTE(list, p) \ +do { \ + DLIST_REMOVE(list, p); \ + DLIST_ADD(list, p); \ +} while (0) + +/* hook into the end of the list - needs a tmp pointer */ +#define DLIST_ADD_END(list, p, type) \ +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) + +/* 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; \ + }\ +} while (0) + +/* demote an element to the end of the list, needs a tmp pointer */ +#define DLIST_DEMOTE(list, p, tmp) \ +do { \ + DLIST_REMOVE(list, p); \ + DLIST_ADD_END(list, p, tmp); \ +} while (0) + +/* concatenate two lists - putting all elements of the 2nd list at the + end of the first list */ +#define DLIST_CONCATENATE(list1, list2, type) \ +do { \ + if (!(list1)) { \ + (list1) = (list2); \ + } else { \ + type tmp; \ + for (tmp = (list1); tmp->next; tmp = tmp->next) ; \ + tmp->next = (list2); \ + if (list2) { \ + (list2)->prev = tmp; \ + } \ + } \ +} while (0) diff --git a/ldb/include/ldb.h b/ldb/include/ldb.h new file mode 100644 index 000000000..937029f52 --- /dev/null +++ b/ldb/include/ldb.h @@ -0,0 +1,1698 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2004 + Copyright (C) Simo Sorce 2005-2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb header + * + * Description: defines for base ldb API + * + * Author: Andrew Tridgell + * Author: Stefan Metzmacher + */ + +/** + \file ldb.h Samba's ldb database + + This header file provides the main API for ldb. +*/ + +#ifndef _LDB_H_ + +/*! \cond DOXYGEN_IGNORE */ +#define _LDB_H_ 1 +/*! \endcond */ + +/* + major restrictions as compared to normal LDAP: + + - no async calls. + - each record must have a unique key field + - the key must be representable as a NULL terminated C string and may not + contain a comma or braces + + major restrictions as compared to tdb: + + - no explicit locking calls + UPDATE: we have transactions now, better than locking --SSS. + +*/ + +#ifndef ldb_val +/** + Result value + + An individual lump of data in a result comes in this format. The + pointer will usually be to a UTF-8 string if the application is + sensible, but it can be to anything you like, including binary data + blobs of arbitrary size. + + \note the data is null (0x00) terminated, but the length does not + include the terminator. +*/ +struct ldb_val { + uint8_t *data; /*!< result data */ + size_t length; /*!< length of data */ +}; +#endif + +/*! \cond DOXYGEN_IGNORE */ +#ifndef PRINTF_ATTRIBUTE +#define PRINTF_ATTRIBUTE(a,b) +#endif +/*! \endcond */ + +/* opaque ldb_dn structures, see ldb_dn.c for internals */ +struct ldb_dn_component; +struct ldb_dn; + +/** + There are a number of flags that are used with ldap_modify() in + ldb_message_element.flags fields. The LDA_FLAGS_MOD_ADD, + LDA_FLAGS_MOD_DELETE and LDA_FLAGS_MOD_REPLACE flags are used in + ldap_modify() calls to specify whether attributes are being added, + deleted or modified respectively. +*/ +#define LDB_FLAG_MOD_MASK 0x3 + +/** + Flag value used in ldap_modify() to indicate that attributes are + being added. + + \sa LDB_FLAG_MOD_MASK +*/ +#define LDB_FLAG_MOD_ADD 1 + +/** + Flag value used in ldap_modify() to indicate that attributes are + being replaced. + + \sa LDB_FLAG_MOD_MASK +*/ +#define LDB_FLAG_MOD_REPLACE 2 + +/** + Flag value used in ldap_modify() to indicate that attributes are + being deleted. + + \sa LDB_FLAG_MOD_MASK +*/ +#define LDB_FLAG_MOD_DELETE 3 + +/** + OID for logic AND comaprison. + + This is the well known object ID for a logical AND comparitor. +*/ +#define LDB_OID_COMPARATOR_AND "1.2.840.113556.1.4.803" + +/** + OID for logic OR comparison. + + This is the well known object ID for a logical OR comparitor. +*/ +#define LDB_OID_COMPARATOR_OR "1.2.840.113556.1.4.804" + +/** + results are given back as arrays of ldb_message_element +*/ +struct ldb_message_element { + unsigned int flags; + const char *name; + unsigned int num_values; + struct ldb_val *values; +}; + + +/** + a ldb_message represents all or part of a record. It can contain an arbitrary + number of elements. +*/ +struct ldb_message { + struct ldb_dn *dn; + unsigned int num_elements; + struct ldb_message_element *elements; +}; + +enum ldb_changetype { + LDB_CHANGETYPE_NONE=0, + LDB_CHANGETYPE_ADD, + LDB_CHANGETYPE_DELETE, + LDB_CHANGETYPE_MODIFY +}; + +/** + LDIF record + + This structure contains a LDIF record, as returned from ldif_read() + and equivalent functions. +*/ +struct ldb_ldif { + enum ldb_changetype changetype; /*!< The type of change */ + struct ldb_message *msg; /*!< The changes */ +}; + +enum ldb_scope {LDB_SCOPE_DEFAULT=-1, + LDB_SCOPE_BASE=0, + LDB_SCOPE_ONELEVEL=1, + LDB_SCOPE_SUBTREE=2}; + +struct ldb_context; + +/* debugging uses one of the following levels */ +enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR, + LDB_DEBUG_WARNING, LDB_DEBUG_TRACE}; + +/** + the user can optionally supply a debug function. The function + is based on the vfprintf() style of interface, but with the addition + of a severity level +*/ +struct ldb_debug_ops { + void (*debug)(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); + void *context; +}; + +/** + The user can optionally supply a custom utf8 functions, + to handle comparisons and casefolding. +*/ +struct ldb_utf8_fns { + void *context; + char *(*casefold)(void *context, TALLOC_CTX *mem_ctx, const char *s, size_t n); +}; + +/** + Flag value for database connection mode. + + If LDB_FLG_RDONLY is used in ldb_connect, then the database will be + opened read-only, if possible. +*/ +#define LDB_FLG_RDONLY 1 + +/** + Flag value for database connection mode. + + If LDB_FLG_NOSYNC is used in ldb_connect, then the database will be + opened without synchronous operations, if possible. +*/ +#define LDB_FLG_NOSYNC 2 + +/** + Flag value to specify autoreconnect mode. + + If LDB_FLG_RECONNECT is used in ldb_connect, then the backend will + be opened in a way that makes it try to auto reconnect if the + connection is dropped (actually make sense only with ldap). +*/ +#define LDB_FLG_RECONNECT 4 + +/** + Flag to tell backends not to use mmap +*/ +#define LDB_FLG_NOMMAP 8 + +/* + structures for ldb_parse_tree handling code +*/ +enum ldb_parse_op { LDB_OP_AND=1, LDB_OP_OR=2, LDB_OP_NOT=3, + LDB_OP_EQUALITY=4, LDB_OP_SUBSTRING=5, + LDB_OP_GREATER=6, LDB_OP_LESS=7, LDB_OP_PRESENT=8, + LDB_OP_APPROX=9, LDB_OP_EXTENDED=10 }; + +struct ldb_parse_tree { + enum ldb_parse_op operation; + union { + struct { + struct ldb_parse_tree *child; + } isnot; + struct { + const char *attr; + struct ldb_val value; + } equality; + struct { + const char *attr; + int start_with_wildcard; + int end_with_wildcard; + struct ldb_val **chunks; + } substring; + struct { + const char *attr; + } present; + struct { + const char *attr; + struct ldb_val value; + } comparison; + struct { + const char *attr; + int dnAttributes; + char *rule_id; + struct ldb_val value; + } extended; + struct { + unsigned int num_elements; + struct ldb_parse_tree **elements; + } list; + } u; +}; + +struct ldb_parse_tree *ldb_parse_tree(TALLOC_CTX *mem_ctx, const char *s); +char *ldb_filter_from_tree(TALLOC_CTX *mem_ctx, struct ldb_parse_tree *tree); + +/** + Encode a binary blob + + This function encodes a binary blob using the encoding rules in RFC + 2254 (Section 4). This function also escapes any non-printable + characters. + + \param mem_ctx the memory context to allocate the return string in. + \param val the (potentially) binary data to be encoded + + \return the encoded data as a null terminated string + + \sa RFC 2252. +*/ +char *ldb_binary_encode(TALLOC_CTX *mem_ctx, struct ldb_val val); + +/** + Encode a string + + This function encodes a string using the encoding rules in RFC 2254 + (Section 4). This function also escapes any non-printable + characters. + + \param mem_ctx the memory context to allocate the return string in. + \param string the string to be encoded + + \return the encoded data as a null terminated string + + \sa RFC 2252. +*/ +char *ldb_binary_encode_string(TALLOC_CTX *mem_ctx, const char *string); + +/* + functions for controlling attribute handling +*/ +typedef int (*ldb_attr_handler_t)(struct ldb_context *, TALLOC_CTX *mem_ctx, const struct ldb_val *, struct ldb_val *); +typedef int (*ldb_attr_comparison_t)(struct ldb_context *, TALLOC_CTX *mem_ctx, const struct ldb_val *, const struct ldb_val *); + +/* + attribute handler structure + + attr -> The attribute name + flags -> LDB_ATTR_FLAG_* + ldif_read_fn -> convert from ldif to binary format + ldif_write_fn -> convert from binary to ldif format + canonicalise_fn -> canonicalise a value, for use by indexing and dn construction + comparison_fn -> compare two values +*/ + +struct ldb_schema_syntax { + const char *name; + ldb_attr_handler_t ldif_read_fn; + ldb_attr_handler_t ldif_write_fn; + ldb_attr_handler_t canonicalise_fn; + ldb_attr_comparison_t comparison_fn; +}; + +struct ldb_schema_attribute { + const char *name; + unsigned flags; + const struct ldb_schema_syntax *syntax; +}; + +const struct ldb_schema_attribute *ldb_schema_attribute_by_name(struct ldb_context *ldb, + const char *name); + +/** + The attribute is not returned by default +*/ +#define LDB_ATTR_FLAG_HIDDEN (1<<0) + +/* the attribute handler name should be freed when released */ +#define LDB_ATTR_FLAG_ALLOCATED (1<<1) + +/** + The attribute is supplied by the application and should not be removed +*/ +#define LDB_ATTR_FLAG_FIXED (1<<2) + +/** + LDAP attribute syntax for a DN + + This is the well-known LDAP attribute syntax for a DN. + + See RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_DN "1.3.6.1.4.1.1466.115.121.1.12" + +/** + LDAP attribute syntax for a Directory String + + This is the well-known LDAP attribute syntax for a Directory String. + + \sa RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_DIRECTORY_STRING "1.3.6.1.4.1.1466.115.121.1.15" + +/** + LDAP attribute syntax for an integer + + This is the well-known LDAP attribute syntax for an integer. + + See RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_INTEGER "1.3.6.1.4.1.1466.115.121.1.27" + +/** + LDAP attribute syntax for an octet string + + This is the well-known LDAP attribute syntax for an octet string. + + See RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_OCTET_STRING "1.3.6.1.4.1.1466.115.121.1.40" + +/** + LDAP attribute syntax for UTC time. + + This is the well-known LDAP attribute syntax for a UTC time. + + See RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_UTC_TIME "1.3.6.1.4.1.1466.115.121.1.53" + +#define LDB_SYNTAX_OBJECTCLASS "LDB_SYNTAX_OBJECTCLASS" + +/* sorting helpers */ +typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque); + +/** + OID for the paged results control. This control is included in the + searchRequest and searchResultDone messages as part of the controls + field of the LDAPMessage, as defined in Section 4.1.12 of + LDAP v3. + + \sa RFC 2696. +*/ +#define LDB_CONTROL_PAGED_RESULTS_OID "1.2.840.113556.1.4.319" + +/** + OID for specifying the returned elements of the ntSecurityDescriptor + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_SD_FLAGS_OID "1.2.840.113556.1.4.801" + +/** + OID for specifying an advanced scope for the search (one partition) + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_DOMAIN_SCOPE_OID "1.2.840.113556.1.4.1339" + +/** + OID for specifying an advanced scope for a search + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_SEARCH_OPTIONS_OID "1.2.840.113556.1.4.1340" + +/** + OID for notification + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_NOTIFICATION_OID "1.2.840.113556.1.4.528" + +/** + OID for getting deleted objects + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_SHOW_DELETED_OID "1.2.840.113556.1.4.417" + +/** + OID for extended DN + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_EXTENDED_DN_OID "1.2.840.113556.1.4.529" + +/** + OID for LDAP server sort result extension. + + This control is included in the searchRequest message as part of + the controls field of the LDAPMessage, as defined in Section 4.1.12 + of LDAP v3. The controlType is set to + "1.2.840.113556.1.4.473". The criticality MAY be either TRUE or + FALSE (where absent is also equivalent to FALSE) at the client's + option. + + \sa RFC 2891. +*/ +#define LDB_CONTROL_SERVER_SORT_OID "1.2.840.113556.1.4.473" + +/** + OID for LDAP server sort result response extension. + + This control is included in the searchResultDone message as part of + the controls field of the LDAPMessage, as defined in Section 4.1.12 of + LDAP v3. + + \sa RFC 2891. +*/ +#define LDB_CONTROL_SORT_RESP_OID "1.2.840.113556.1.4.474" + +/** + OID for LDAP Attribute Scoped Query extension. + + This control is included in SearchRequest or SearchResponse + messages as part of the controls field of the LDAPMessage. +*/ +#define LDB_CONTROL_ASQ_OID "1.2.840.113556.1.4.1504" + +/** + OID for LDAP Directory Sync extension. + + This control is included in SearchRequest or SearchResponse + messages as part of the controls field of the LDAPMessage. +*/ +#define LDB_CONTROL_DIRSYNC_OID "1.2.840.113556.1.4.841" + + +/** + OID for LDAP Virtual List View Request extension. + + This control is included in SearchRequest messages + as part of the controls field of the LDAPMessage. +*/ +#define LDB_CONTROL_VLV_REQ_OID "2.16.840.1.113730.3.4.9" + +/** + OID for LDAP Virtual List View Response extension. + + This control is included in SearchResponse messages + as part of the controls field of the LDAPMessage. +*/ +#define LDB_CONTROL_VLV_RESP_OID "2.16.840.1.113730.3.4.10" + +/** + OID to let modifies don't give an error when adding an existing + attribute with the same value or deleting an nonexisting one attribute + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_PERMISSIVE_MODIFY_OID "1.2.840.113556.1.4.1413" + +/** + OID for LDAP Extended Operation START_TLS. + + This Extended operation is used to start a new TLS + channel on top of a clear text channel. +*/ +#define LDB_EXTENDED_START_TLS_OID "1.3.6.1.4.1.1466.20037" + +/** +*/ +#define LDB_EXTENDED_DYNAMIC_OID "1.3.6.1.4.1.1466.101.119.1" + +/** +*/ +#define LDB_EXTENDED_FAST_BIND_OID "1.2.840.113556.1.4.1781" + +struct ldb_sd_flags_control { + /* + * request the owner 0x00000001 + * request the group 0x00000002 + * request the DACL 0x00000004 + * request the SACL 0x00000008 + */ + unsigned secinfo_flags; +}; + +/* + * DOMAIN_SCOPE 0x00000001 + * this limits the search to one partition, + * and no referrals will be returned. + * (Note this doesn't limit the entries by there + * objectSid belonging to a domain! Builtin and Foreign Sids + * are still returned) + * + * PHANTOM_ROOT 0x00000002 + * this search on the whole tree on a domain controller + * over multiple partitions without referrals. + * (This is the default behavior on the Global Catalog Port) + */ + +#define LDB_SEARCH_OPTION_DOMAIN_SCOPE 0x00000001 +#define LDB_SEARCH_OPTION_PHANTOM_ROOT 0x00000002 + +struct ldb_search_options_control { + unsigned search_options; +}; + +struct ldb_paged_control { + int size; + int cookie_len; + char *cookie; +}; + +struct ldb_extended_dn_control { + int type; +}; + +struct ldb_server_sort_control { + char *attributeName; + char *orderingRule; + int reverse; +}; + +struct ldb_sort_resp_control { + int result; + char *attr_desc; +}; + +struct ldb_asq_control { + int request; + char *source_attribute; + int src_attr_len; + int result; +}; + +struct ldb_dirsync_control { + int flags; + int max_attributes; + int cookie_len; + char *cookie; +}; + +struct ldb_vlv_req_control { + int beforeCount; + int afterCount; + int type; + union { + struct { + int offset; + int contentCount; + } byOffset; + struct { + int value_len; + char *value; + } gtOrEq; + } match; + int ctxid_len; + char *contextId; +}; + +struct ldb_vlv_resp_control { + int targetPosition; + int contentCount; + int vlv_result; + int ctxid_len; + char *contextId; +}; + +struct ldb_control { + const char *oid; + int critical; + void *data; +}; + +enum ldb_request_type { + LDB_SEARCH, + LDB_ADD, + LDB_MODIFY, + LDB_DELETE, + LDB_RENAME, + LDB_EXTENDED, + LDB_SEQUENCE_NUMBER, + LDB_REQ_REGISTER_CONTROL, + LDB_REQ_REGISTER_PARTITION +}; + +enum ldb_reply_type { + LDB_REPLY_ENTRY, + LDB_REPLY_REFERRAL, + LDB_REPLY_EXTENDED, + LDB_REPLY_DONE +}; + +enum ldb_wait_type { + LDB_WAIT_ALL, + LDB_WAIT_NONE +}; + +enum ldb_state { + LDB_ASYNC_INIT, + LDB_ASYNC_PENDING, + LDB_ASYNC_DONE +}; + +struct ldb_extended { + const char *oid; + void *data; /* NULL or a valid talloc pointer! talloc_get_type() will be used on it */ +}; + +struct ldb_result { + unsigned int count; + struct ldb_message **msgs; + char **refs; + struct ldb_extended *extended; + struct ldb_control **controls; +}; + +struct ldb_reply { + enum ldb_reply_type type; + struct ldb_message *message; + struct ldb_extended *response; + char *referral; + struct ldb_control **controls; +}; + +struct ldb_handle { + int status; + enum ldb_state state; + void *private_data; + struct ldb_module *module; +}; + +struct ldb_search { + struct ldb_dn *base; + enum ldb_scope scope; + struct ldb_parse_tree *tree; + const char * const *attrs; + struct ldb_result *res; +}; + +struct ldb_add { + const struct ldb_message *message; +}; + +struct ldb_modify { + const struct ldb_message *message; +}; + +struct ldb_delete { + struct ldb_dn *dn; +}; + +struct ldb_rename { + struct ldb_dn *olddn; + struct ldb_dn *newdn; +}; + +struct ldb_register_control { + const char *oid; +}; + +struct ldb_register_partition { + struct ldb_dn *dn; +}; + +enum ldb_sequence_type { + LDB_SEQ_HIGHEST_SEQ, + LDB_SEQ_HIGHEST_TIMESTAMP, + LDB_SEQ_NEXT +}; + +struct ldb_sequence_number { + enum ldb_sequence_type type; + uint64_t seq_num; + uint32_t flags; +}; + +typedef int (*ldb_request_callback_t)(struct ldb_context *, void *, struct ldb_reply *); +struct ldb_request { + + enum ldb_request_type operation; + + union { + struct ldb_search search; + struct ldb_add add; + struct ldb_modify mod; + struct ldb_delete del; + struct ldb_rename rename; + struct ldb_extended extended; + struct ldb_sequence_number seq_num; + struct ldb_register_control reg_control; + struct ldb_register_partition reg_partition; + } op; + + struct ldb_control **controls; + + void *context; + ldb_request_callback_t callback; + + int timeout; + time_t starttime; + struct ldb_handle *handle; +}; + +int ldb_request(struct ldb_context *ldb, struct ldb_request *request); + +int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type); + +int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout); +int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq); +void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms); +void ldb_set_modules_dir(struct ldb_context *ldb, const char *path); +struct event_context; +void ldb_set_event_context(struct ldb_context *ldb, struct event_context *ev); +struct event_context * ldb_get_event_context(struct ldb_context *ldb); + +/** + Initialise ldbs' global information + + This is required before any other LDB call + + \return 0 if initialisation succeeded, -1 otherwise +*/ +int ldb_global_init(void); + +/** + Initialise an ldb context + + This is required before any other LDB call. + + \param mem_ctx pointer to a talloc memory context. Pass NULL if there is + no suitable context available. + + \return pointer to ldb_context that should be free'd (using talloc_free()) + at the end of the program. +*/ +struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct event_context *ev_ctx); + +/** + Connect to a database. + + This is typically called soon after ldb_init(), and is required prior to + any search or database modification operations. + + The URL can be one of the following forms: + - tdb://path + - ldapi://path + - ldap://host + - sqlite://path + + \param ldb the context associated with the database (from ldb_init()) + \param url the URL of the database to connect to, as noted above + \param flags a combination of LDB_FLG_* to modify the connection behaviour + \param options backend specific options - passed uninterpreted to the backend + + \return result code (LDB_SUCCESS on success, or a failure code) + + \note It is an error to connect to a database that does not exist in readonly mode + (that is, with LDB_FLG_RDONLY). However in read-write mode, the database will be + created if it does not exist. +*/ +int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]); + +/* + return an automatic basedn from the rootDomainNamingContext of the rootDSE + This value have been set in an opaque pointer at connection time +*/ +struct ldb_dn *ldb_get_root_basedn(struct ldb_context *ldb); + +/* + return an automatic basedn from the configurationNamingContext of the rootDSE + This value have been set in an opaque pointer at connection time +*/ +struct ldb_dn *ldb_get_config_basedn(struct ldb_context *ldb); + +/* + return an automatic basedn from the schemaNamingContext of the rootDSE + This value have been set in an opaque pointer at connection time +*/ +struct ldb_dn *ldb_get_schema_basedn(struct ldb_context *ldb); + +/* + return an automatic baseDN from the defaultNamingContext of the rootDSE + This value have been set in an opaque pointer at connection time +*/ +struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb); + +/** + The default async search callback function + + \param ldb the context associated with the database (from ldb_init()) + \param context the callback context (struct ldb_result *) + \param ares a single reply from the async core + + \return result code (LDB_SUCCESS on success, or a failure code) + + \note this function expects the context to always be an struct ldb_result pointer + AND a talloc context, this function will steal on the context each message + from the ares reply passed on by the async core so that in the end all the + messages will be in the context (ldb_result) memory tree. + Freeing the passed context (ldb_result tree) will free all the resources + (the request need to be freed separately and the result doe not depend on the + request that can be freed as sson as the search request is finished) +*/ + +int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares); + +/** + Helper function to build a search request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc memory context (used as parent of ret_req) + \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one) + \param scope the search scope for the query + \param expression the search expression to use for this query + \param attrs the search attributes for the query (pass NULL if none required) + \param controls an array of controls + \param context the callback function context + \param callback the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_search_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *base, + enum ldb_scope scope, + const char *expression, + const char * const *attrs, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build an add request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc memory context (used as parent of ret_req) + \param message contains the entry to be added + \param controls an array of controls + \param context the callback function context + \param callback the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_add_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + const struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a modify request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc memory context (used as parent of ret_req) + \param message contains the entry to be modified + \param controls an array of controls + \param context the callback function context + \param callback the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_mod_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + const struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a delete request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc memory context (used as parent of ret_req) + \param dn the DN to be deleted + \param controls an array of controls + \param context the callback function context + \param callback the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_del_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a rename request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc memory context (used as parent of ret_req) + \param olddn the old DN + \param newdn the new DN + \param controls an array of controls + \param context the callback function context + \param callback the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_rename_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *olddn, + struct ldb_dn *newdn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Add a ldb_control to a ldb_request + + \param req the request struct where to add the control + \param oid the object identifier of the control as string + \param critical whether the control should be critical or not + \param data a talloc pointer to the control specific data + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ +int ldb_request_add_control(struct ldb_request *req, const char *oid, bool critical, void *data); + +/** + check if a control with the specified "oid" exist and return it + \param req the request struct where to add the control + \param oid the object identifier of the control as string + + \return the control, NULL if not found +*/ +struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char *oid); + +/** + Search the database + + This function searches the database, and returns + records that match an LDAP-like search expression + + \param ldb the context associated with the database (from ldb_init()) + \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one) + \param scope the search scope for the query + \param expression the search expression to use for this query + \param attrs the search attributes for the query (pass NULL if none required) + \param res the return result + + \return result code (LDB_SUCCESS on success, or a failure code) + + \note use talloc_free() to free the ldb_result returned +*/ +int ldb_search(struct ldb_context *ldb, + struct ldb_dn *base, + enum ldb_scope scope, + const char *expression, + const char * const *attrs, struct ldb_result **res); + +/* + * a useful search function where you can easily define the expression and + * that takes a memory context where results are allocated +*/ + +int ldb_search_exp_fmt(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, + struct ldb_result **result, struct ldb_dn *base, + enum ldb_scope scope, const char * const *attrs, + const char *exp_fmt, ...) PRINTF_ATTRIBUTE(7,8); + +/** + Add a record to the database. + + This function adds a record to the database. This function will fail + if a record with the specified class and key already exists in the + database. + + \param ldb the context associated with the database (from + ldb_init()) + \param message the message containing the record to add. + + \return result code (LDB_SUCCESS if the record was added, otherwise + a failure code) +*/ +int ldb_add(struct ldb_context *ldb, + const struct ldb_message *message); + +/** + Modify the specified attributes of a record + + This function modifies a record that is in the database. + + \param ldb the context associated with the database (from + ldb_init()) + \param message the message containing the changes required. + + \return result code (LDB_SUCCESS if the record was modified as + requested, otherwise a failure code) +*/ +int ldb_modify(struct ldb_context *ldb, + const struct ldb_message *message); + +/** + Rename a record in the database + + This function renames a record in the database. + + \param ldb the context associated with the database (from + ldb_init()) + \param olddn the DN for the record to be renamed. + \param newdn the new DN + + \return result code (LDB_SUCCESS if the record was renamed as + requested, otherwise a failure code) +*/ +int ldb_rename(struct ldb_context *ldb, struct ldb_dn *olddn, struct ldb_dn *newdn); + +/** + Delete a record from the database + + This function deletes a record from the database. + + \param ldb the context associated with the database (from + ldb_init()) + \param dn the DN for the record to be deleted. + + \return result code (LDB_SUCCESS if the record was deleted, + otherwise a failure code) +*/ +int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn); + +/** + The default async extended operation callback function + + \param ldb the context associated with the database (from ldb_init()) + \param context the callback context (struct ldb_result *) + \param ares a single reply from the async core + + \return result code (LDB_SUCCESS on success, or a failure code) + + \note this function expects the context to always be an struct ldb_result pointer + AND a talloc context, this function will steal on the context each message + from the ares reply passed on by the async core so that in the end all the + messages will be in the context (ldb_result) memory tree. + Freeing the passed context (ldb_result tree) will free all the resources + (the request need to be freed separately and the result doe not depend on the + request that can be freed as sson as the search request is finished) +*/ +int ldb_extended_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares); + +/** + Helper function to build a extended request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc memory context (used as parent of ret_req) + \param oid the OID of the extended operation. + \param data a void pointer a the extended operation specific parameters, + it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it + \param controls an array of controls + \param context the callback function context + \param callback the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ +int ldb_build_extended_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + const char *oid, + void *data,/* NULL or a valid talloc pointer! talloc_get_type() will be used on it */ + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + call an extended operation + + This function deletes a record from the database. + + \param ldb the context associated with the database (from ldb_init()) + \param oid the OID of the extended operation. + \param data a void pointer a the extended operation specific parameters, + it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it + \param res the result of the extended operation + + \return result code (LDB_SUCCESS if the extended operation returned fine, + otherwise a failure code) +*/ +int ldb_extended(struct ldb_context *ldb, + const char *oid, + void *data,/* NULL or a valid talloc pointer! talloc_get_type() will be used on it */ + struct ldb_result **res); + +/** + start a transaction +*/ +int ldb_transaction_start(struct ldb_context *ldb); + +/** + commit a transaction +*/ +int ldb_transaction_commit(struct ldb_context *ldb); + +/** + cancel a transaction +*/ +int ldb_transaction_cancel(struct ldb_context *ldb); + + +/** + return extended error information from the last call +*/ +const char *ldb_errstring(struct ldb_context *ldb); + +/** + return a string explaining what a ldb error constant meancs +*/ +const char *ldb_strerror(int ldb_err); + +/** + setup the default utf8 functions + FIXME: these functions do not yet handle utf8 +*/ +void ldb_set_utf8_default(struct ldb_context *ldb); + +/** + Casefold a string + + \param ldb the ldb context + \param mem_ctx the memory context to allocate the result string + memory from. + \param s the string that is to be folded + \return a copy of the string, converted to upper case + + \note The default function is not yet UTF8 aware. Provide your own + set of functions through ldb_set_utf8_fns() +*/ +char *ldb_casefold(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *s, size_t n); + +/** + Check the attribute name is valid according to rfc2251 + \param s the string to check + + \return 1 if the name is ok +*/ +int ldb_valid_attr_name(const char *s); + +/* + ldif manipulation functions +*/ + +/** + Write an LDIF message + + This function writes an LDIF message using a caller supplied write + function. + + \param ldb the ldb context (from ldb_init()) + \param fprintf_fn a function pointer for the write function. This must take + a private data pointer, followed by a format string, and then a variable argument + list. + \param private_data pointer that will be provided back to the write + function. This is useful for maintaining state or context. + \param ldif the message to write out + + \return the total number of bytes written, or an error code as returned + from the write function. + + \sa ldb_ldif_write_file for a more convenient way to write to a + file stream. + + \sa ldb_ldif_read for the reader equivalent to this function. +*/ +int ldb_ldif_write(struct ldb_context *ldb, + int (*fprintf_fn)(void *, const char *, ...) PRINTF_ATTRIBUTE(2,3), + void *private_data, + const struct ldb_ldif *ldif); + +/** + Clean up an LDIF message + + This function cleans up a LDIF message read using ldb_ldif_read() + or related functions (such as ldb_ldif_read_string() and + ldb_ldif_read_file(). + + \param ldb the ldb context (from ldb_init()) + \param msg the message to clean up and free + +*/ +void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *msg); + +/** + Read an LDIF message + + This function creates an LDIF message using a caller supplied read + function. + + \param ldb the ldb context (from ldb_init()) + \param fgetc_fn a function pointer for the read function. This must + take a private data pointer, and must return a pointer to an + integer corresponding to the next byte read (or EOF if there is no + more data to be read). + \param private_data pointer that will be provided back to the read + function. This is udeful for maintaining state or context. + + \return the LDIF message that has been read in + + \note You must free the LDIF message when no longer required, using + ldb_ldif_read_free(). + + \sa ldb_ldif_read_file for a more convenient way to read from a + file stream. + + \sa ldb_ldif_read_string for a more convenient way to read from a + string (char array). + + \sa ldb_ldif_write for the writer equivalent to this function. +*/ +struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb, + int (*fgetc_fn)(void *), void *private_data); + +/** + Read an LDIF message from a file + + This function reads the next LDIF message from the contents of a + file stream. If you want to get all of the LDIF messages, you will + need to repeatedly call this function, until it returns NULL. + + \param ldb the ldb context (from ldb_init()) + \param f the file stream to read from (typically from fdopen()) + + \sa ldb_ldif_read_string for an equivalent function that will read + from a string (char array). + + \sa ldb_ldif_write_file for the writer equivalent to this function. + +*/ +struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f); + +/** + Read an LDIF message from a string + + This function reads the next LDIF message from the contents of a char + array. If you want to get all of the LDIF messages, you will need + to repeatedly call this function, until it returns NULL. + + \param ldb the ldb context (from ldb_init()) + \param s pointer to the char array to read from + + \sa ldb_ldif_read_file for an equivalent function that will read + from a file stream. + + \sa ldb_ldif_write for a more general (arbitrary read function) + version of this function. +*/ +struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s); + +/** + Write an LDIF message to a file + + \param ldb the ldb context (from ldb_init()) + \param f the file stream to write to (typically from fdopen()) + \param msg the message to write out + + \return the total number of bytes written, or a negative error code + + \sa ldb_ldif_read_file for the reader equivalent to this function. +*/ +int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *msg); + +/** + Base64 encode a buffer + + \param mem_ctx the memory context that the result is allocated + from. + \param buf pointer to the array that is to be encoded + \param len the number of elements in the array to be encoded + + \return pointer to an array containing the encoded data + + \note The caller is responsible for freeing the result +*/ +char *ldb_base64_encode(TALLOC_CTX *mem_ctx, const char *buf, int len); + +/** + Base64 decode a buffer + + This function decodes a base64 encoded string in place. + + \param s the string to decode. + + \return the length of the returned (decoded) string. + + \note the string is null terminated, but the null terminator is not + included in the length. +*/ +int ldb_base64_decode(char *s); + +/* The following definitions come from lib/ldb/common/ldb_dn.c */ + +struct ldb_dn *ldb_dn_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *dn); +struct ldb_dn *ldb_dn_new_fmt(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *new_fmt, ...) PRINTF_ATTRIBUTE(3,4); +struct ldb_dn *ldb_dn_from_ldb_val(void *mem_ctx, struct ldb_context *ldb, const struct ldb_val *strdn); +bool ldb_dn_validate(struct ldb_dn *dn); + +char *ldb_dn_escape_value(TALLOC_CTX *mem_ctx, struct ldb_val value); +const char *ldb_dn_get_linearized(struct ldb_dn *dn); +const char *ldb_dn_get_casefold(struct ldb_dn *dn); +char *ldb_dn_alloc_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn); +char *ldb_dn_alloc_casefold(TALLOC_CTX *mem_ctx, struct ldb_dn *dn); + +int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn); +int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1); + +bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base); +bool ldb_dn_add_base_fmt(struct ldb_dn *dn, const char *base_fmt, ...) PRINTF_ATTRIBUTE(2,3); +bool ldb_dn_add_child(struct ldb_dn *dn, struct ldb_dn *child); +bool ldb_dn_add_child_fmt(struct ldb_dn *dn, const char *child_fmt, ...) PRINTF_ATTRIBUTE(2,3); +bool ldb_dn_remove_base_components(struct ldb_dn *dn, unsigned int num); +bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num); + +struct ldb_dn *ldb_dn_copy(TALLOC_CTX *mem_ctx, struct ldb_dn *dn); +struct ldb_dn *ldb_dn_get_parent(TALLOC_CTX *mem_ctx, struct ldb_dn *dn); +char *ldb_dn_canonical_string(TALLOC_CTX *mem_ctx, struct ldb_dn *dn); +char *ldb_dn_canonical_ex_string(TALLOC_CTX *mem_ctx, struct ldb_dn *dn); +int ldb_dn_get_comp_num(struct ldb_dn *dn); +const char *ldb_dn_get_component_name(struct ldb_dn *dn, unsigned int num); +const struct ldb_val *ldb_dn_get_component_val(struct ldb_dn *dn, unsigned int num); +const char *ldb_dn_get_rdn_name(struct ldb_dn *dn); +const struct ldb_val *ldb_dn_get_rdn_val(struct ldb_dn *dn); +int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val); + +bool ldb_dn_is_valid(struct ldb_dn *dn); +bool ldb_dn_is_special(struct ldb_dn *dn); +bool ldb_dn_check_special(struct ldb_dn *dn, const char *check); +bool ldb_dn_is_null(struct ldb_dn *dn); + + +/** + Compare two attributes + + This function compares to attribute names. Note that this is a + case-insensitive comparison. + + \param a the first attribute name to compare + \param b the second attribute name to compare + + \return 0 if the attribute names are the same, or only differ in + case; non-zero if there are any differences + + attribute names are restricted by rfc2251 so using + strcasecmp and toupper here is ok. + return 0 for match +*/ +#define ldb_attr_cmp(a, b) strcasecmp(a, b) +char *ldb_attr_casefold(TALLOC_CTX *mem_ctx, const char *s); +int ldb_attr_dn(const char *attr); + +/** + Create an empty message + + \param mem_ctx the memory context to create in. You can pass NULL + to get the top level context, however the ldb context (from + ldb_init()) may be a better choice +*/ +struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx); + +/** + Find an element within an message +*/ +struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, + const char *attr_name); + +/** + Compare two ldb_val values + + \param v1 first ldb_val structure to be tested + \param v2 second ldb_val structure to be tested + + \return 1 for a match, 0 if there is any difference +*/ +int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2); + +/** + find a value within an ldb_message_element + + \param el the element to search + \param val the value to search for + + \note This search is case sensitive +*/ +struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, + struct ldb_val *val); + +/** + add a new empty element to a ldb_message +*/ +int ldb_msg_add_empty(struct ldb_message *msg, + const char *attr_name, + int flags, + struct ldb_message_element **return_el); + +/** + add a element to a ldb_message +*/ +int ldb_msg_add(struct ldb_message *msg, + const struct ldb_message_element *el, + int flags); +int ldb_msg_add_value(struct ldb_message *msg, + const char *attr_name, + const struct ldb_val *val, + struct ldb_message_element **return_el); +int ldb_msg_add_steal_value(struct ldb_message *msg, + const char *attr_name, + struct ldb_val *val); +int ldb_msg_add_steal_string(struct ldb_message *msg, + const char *attr_name, char *str); +int ldb_msg_add_string(struct ldb_message *msg, + const char *attr_name, const char *str); +int ldb_msg_add_fmt(struct ldb_message *msg, + const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); + +/** + compare two message elements - return 0 on match +*/ +int ldb_msg_element_compare(struct ldb_message_element *el1, + struct ldb_message_element *el2); + +/** + Find elements in a message. + + This function finds elements and converts to a specific type, with + a give default value if not found. Assumes that elements are + single valued. +*/ +const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name); +int ldb_msg_find_attr_as_int(const struct ldb_message *msg, + const char *attr_name, + int default_value); +unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, + const char *attr_name, + unsigned int default_value); +int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, + const char *attr_name, + int64_t default_value); +uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, + const char *attr_name, + uint64_t default_value); +double ldb_msg_find_attr_as_double(const struct ldb_message *msg, + const char *attr_name, + double default_value); +int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, + const char *attr_name, + int default_value); +const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, + const char *attr_name, + const char *default_value); + +struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + const struct ldb_message *msg, + const char *attr_name); + +void ldb_msg_sort_elements(struct ldb_message *msg); + +struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, + const struct ldb_message *msg); +struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, + const struct ldb_message *msg); + +struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, + const struct ldb_message *msg); + + +struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, + struct ldb_message *msg1, + struct ldb_message *msg2); + +int ldb_msg_check_string_attribute(const struct ldb_message *msg, + const char *name, + const char *value); + +/** + Integrity check an ldb_message + + This function performs basic sanity / integrity checks on an + ldb_message. + + \param ldb context in which to perform the checks + \param msg the message to check + + \return LDB_SUCCESS if the message is OK, or a non-zero error code + (one of LDB_ERR_INVALID_DN_SYNTAX, LDB_ERR_ENTRY_ALREADY_EXISTS or + LDB_ERR_INVALID_ATTRIBUTE_SYNTAX) if there is a problem with a + message. +*/ +int ldb_msg_sanity_check(struct ldb_context *ldb, + const struct ldb_message *msg); + +/** + Duplicate an ldb_val structure + + This function copies an ldb value structure. + + \param mem_ctx the memory context that the duplicated value will be + allocated from + \param v the ldb_val to be duplicated. + + \return the duplicated ldb_val structure. +*/ +struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v); + +/** + this allows the user to set a debug function for error reporting +*/ +int ldb_set_debug(struct ldb_context *ldb, + void (*debug)(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0), + void *context); + +/** + this allows the user to set custom utf8 function for error reporting +*/ +void ldb_set_utf8_fns(struct ldb_context *ldb, + void *context, + char *(*casefold)(void *, void *, const char *, size_t n)); + +/** + this sets up debug to print messages on stderr +*/ +int ldb_set_debug_stderr(struct ldb_context *ldb); + +/* control backend specific opaque values */ +int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value); +void *ldb_get_opaque(struct ldb_context *ldb, const char *name); + +const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs); +const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr); +int ldb_attr_in_list(const char * const *attrs, const char *attr); + + +void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree, + const char *attr, + const char *replace); + +int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace); +int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace); +void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr); + +/** + Convert a time structure to a string + + This function converts a time_t structure to an LDAP formatted + GeneralizedTime string. + + \param mem_ctx the memory context to allocate the return string in + \param t the time structure to convert + + \return the formatted string, or NULL if the time structure could + not be converted +*/ +char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t); + +/** + Convert a string to a time structure + + This function converts an LDAP formatted GeneralizedTime string + to a time_t structure. + + \param s the string to convert + + \return the time structure, or 0 if the string cannot be converted +*/ +time_t ldb_string_to_time(const char *s); + +/** + Convert a time structure to a string + + This function converts a time_t structure to an LDAP formatted + UTCTime string. + + \param mem_ctx the memory context to allocate the return string in + \param t the time structure to convert + + \return the formatted string, or NULL if the time structure could + not be converted +*/ +char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t); + +/** + Convert a string to a time structure + + This function converts an LDAP formatted UTCTime string + to a time_t structure. + + \param s the string to convert + + \return the time structure, or 0 if the string cannot be converted +*/ +time_t ldb_string_utc_to_time(const char *s); + + +void ldb_qsort (void *const pbase, size_t total_elems, size_t size, void *opaque, ldb_qsort_cmp_fn_t cmp); + + +/** + Convert an array of string represention of a control into an array of ldb_control structures + + \param ldb LDB context + \param mem_ctx TALLOC context to return result on, and to allocate error_string on + \param control_strings Array of string-formatted controls + + \return array of ldb_control elements +*/ +struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char **control_strings); + +#endif diff --git a/ldb/include/ldb_errors.h b/ldb/include/ldb_errors.h new file mode 100644 index 000000000..9362233fd --- /dev/null +++ b/ldb/include/ldb_errors.h @@ -0,0 +1,310 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb header + * + * Description: defines error codes following RFC 2251 ldap error codes + * + * Author: Simo Sorce + */ + +#ifndef _LDB_ERRORS_H_ + +/*! \cond DOXYGEN_IGNORE */ +#define _LDB_ERRORS_H_ 1 +/*! \endcond */ + +/** + \file ldb_errors.h + + This header provides a set of result codes for LDB function calls. + + Many LDB function calls return an integer value (int). As shown in + the function documentation, those return values may indicate + whether the function call worked correctly (in which case it + returns LDB_SUCCESS) or some problem occurred (in which case some + other value will be returned). As a special case, + LDB_ERR_COMPARE_FALSE or LDB_ERR_COMPARE_TRUE may be returned, + which does not indicate an error. + + \note Not all error codes make sense for LDB, however they are + based on the LDAP error codes, and are kept for reference and to + avoid overlap. + + \note Some of this documentation is based on information in + the OpenLDAP documentation, as developed and maintained by the + The OpenLDAP Project. + */ + +/** + The function call succeeded. + + If a function returns LDB_SUCCESS, then that function, and the + underlying transactions that may have been required, completed + successfully. +*/ +#define LDB_SUCCESS 0 + +/** + The function call failed for some non-specific reason. +*/ +#define LDB_ERR_OPERATIONS_ERROR 1 + +/** + The function call failed because of a protocol violation. +*/ +#define LDB_ERR_PROTOCOL_ERROR 2 + +/** + The function call failed because a time limit was exceeded. +*/ +#define LDB_ERR_TIME_LIMIT_EXCEEDED 3 + +/** + The function call failed because a size limit was exceeded. +*/ +#define LDB_ERR_SIZE_LIMIT_EXCEEDED 4 + +/** + The function was for value comparison, and the comparison operation + returned false. + + \note This is a status value, and doesn't normally indicate an + error. +*/ +#define LDB_ERR_COMPARE_FALSE 5 + +/** + The function was for value comparison, and the comparison operation + returned true. + + \note This is a status value, and doesn't normally indicate an + error. +*/ +#define LDB_ERR_COMPARE_TRUE 6 + +/** + The function used an authentication method that is not supported by + the database. +*/ +#define LDB_ERR_AUTH_METHOD_NOT_SUPPORTED 7 + +/** + The function call required a underlying operation that required + strong authentication. + + This will normally only occur if you are using LDB with a LDAP + backend. +*/ +#define LDB_ERR_STRONG_AUTH_REQUIRED 8 +/* 9 RESERVED */ + +/** + The function resulted in a referral to another server. +*/ +#define LDB_ERR_REFERRAL 10 + +/** + The function failed because an administrative / policy limit was + exceeded. +*/ +#define LDB_ERR_ADMIN_LIMIT_EXCEEDED 11 + +/** + The function required an extension or capability that the + database cannot provide. +*/ +#define LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION 12 + +/** + The function involved a transaction or database operation that + could not be performed without a secure link. +*/ +#define LDB_ERR_CONFIDENTIALITY_REQUIRED 13 + +/** + This is an intermediate result code for SASL bind operations that + have more than one step. + + \note This is a result code that does not normally indicate an + error has occurred. +*/ +#define LDB_ERR_SASL_BIND_IN_PROGRESS 14 + +/** + The function referred to an attribute type that is not present in + the entry. +*/ +#define LDB_ERR_NO_SUCH_ATTRIBUTE 16 + +/** + The function referred to an attribute type that is invalid +*/ +#define LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE 17 + +/** + The function required a filter type that is not available for the + specified attribute. +*/ +#define LDB_ERR_INAPPROPRIATE_MATCHING 18 + +/** + The function would have violated an attribute constraint. +*/ +#define LDB_ERR_CONSTRAINT_VIOLATION 19 + +/** + The function involved an attribute type or attribute value that + already exists in the entry. +*/ +#define LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS 20 +/** + The function used an invalid (incorrect syntax) attribute value. +*/ +#define LDB_ERR_INVALID_ATTRIBUTE_SYNTAX 21 + +/* 22-31 unused */ + +/** + The function referred to an object that does not exist in the + database. +*/ +#define LDB_ERR_NO_SUCH_OBJECT 32 + +/** + The function referred to an alias which points to a non-existant + object in the database. +*/ +#define LDB_ERR_ALIAS_PROBLEM 33 + +/** + The function used a DN which was invalid (incorrect syntax). +*/ +#define LDB_ERR_INVALID_DN_SYNTAX 34 + +/* 35 RESERVED */ + +/** + The function required dereferencing of an alias, and something went + wrong during the dereferencing process. +*/ +#define LDB_ERR_ALIAS_DEREFERENCING_PROBLEM 36 + +/* 37-47 unused */ + +/** + The function passed in the wrong authentication method. +*/ +#define LDB_ERR_INAPPROPRIATE_AUTHENTICATION 48 + +/** + The function passed in or referenced incorrect credentials during + authentication. +*/ +#define LDB_ERR_INVALID_CREDENTIALS 49 + +/** + The function required access permissions that the user does not + possess. +*/ +#define LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS 50 + +/** + The function required a transaction or call that the database could + not perform because it is busy. +*/ +#define LDB_ERR_BUSY 51 + +/** + The function required a transaction or call to a database that is + not available. +*/ +#define LDB_ERR_UNAVAILABLE 52 + +/** + The function required a transaction or call to a database that the + database declined to perform. +*/ +#define LDB_ERR_UNWILLING_TO_PERFORM 53 + +/** + The function failed because it resulted in a loop being detected. +*/ +#define LDB_ERR_LOOP_DETECT 54 + +/* 55-63 unused */ + +/** + The function failed because it would have violated a naming rule. +*/ +#define LDB_ERR_NAMING_VIOLATION 64 + +/** + The function failed because it would have violated the schema. +*/ +#define LDB_ERR_OBJECT_CLASS_VIOLATION 65 + +/** + The function required an operation that is only allowed on leaf + objects, but the object is not a leaf. +*/ +#define LDB_ERR_NOT_ALLOWED_ON_NON_LEAF 66 + +/** + The function required an operation that cannot be performed on a + Relative DN, but the object is a Relative DN. +*/ +#define LDB_ERR_NOT_ALLOWED_ON_RDN 67 + +/** + The function failed because the entry already exists. +*/ +#define LDB_ERR_ENTRY_ALREADY_EXISTS 68 + +/** + The function failed because modifications to an object class are + not allowable. +*/ +#define LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED 69 + +/* 70 RESERVED FOR CLDAP */ + +/** + The function failed because it needed to be applied to multiple + databases. +*/ +#define LDB_ERR_AFFECTS_MULTIPLE_DSAS 71 + +/* 72-79 unused */ + +/** + The function failed for unknown reasons. +*/ +#define LDB_ERR_OTHER 80 + +/* 81-90 RESERVED for APIs */ + +#endif /* _LDB_ERRORS_H_ */ diff --git a/ldb/include/ldb_handlers.h b/ldb/include/ldb_handlers.h new file mode 100644 index 000000000..e1c14e679 --- /dev/null +++ b/ldb/include/ldb_handlers.h @@ -0,0 +1,67 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb header + * + * Description: defines attribute handlers + * + * Author: Simo Sorce + */ + + +int ldb_handler_copy( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out); + +int ldb_handler_fold( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out); + +int ldb_canonicalise_Integer( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out); + +int ldb_comparison_Integer( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2); + +int ldb_comparison_binary( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2); + +int ldb_comparison_fold( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2); + +int ldb_canonicalise_dn( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out); + +int ldb_comparison_dn( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2); + +int ldb_comparison_objectclass( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2); + +int ldb_comparison_utctime( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2); + +int ldb_canonicalise_utctime( struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out); + diff --git a/ldb/include/ldb_includes.h b/ldb/include/ldb_includes.h new file mode 100644 index 000000000..29c7b2dc5 --- /dev/null +++ b/ldb/include/ldb_includes.h @@ -0,0 +1,29 @@ +#ifndef _LDB_PRIVATE_INCLUDES_H_ +#define _LDB_PRIVATE_INCLUDES_H_ +/* + a temporary includes file until I work on the ldb build system +*/ + +#if (_SAMBA_BUILD_ >= 4) +/* tell ldb we have the internal ldap code */ +#define HAVE_ILDAP 1 +#endif + +#if (_SAMBA_BUILD_ <= 3) +/* allow forbidden string functions - should be replaced with _m functions */ +#undef strcasecmp +#undef strncasecmp +#define dyn_MODULESDIR dyn_LIBDIR +#endif + +#include "replace.h" +#include "system/filesys.h" +#include "system/time.h" +#include "talloc.h" +#include "events.h" +#include "ldb.h" +#include "ldb_errors.h" +#include "ldb_private.h" +#include "dlinklist.h" + +#endif /*_LDB_PRIVATE_INCLUDES_H_*/ diff --git a/ldb/include/ldb_private.h b/ldb/include/ldb_private.h new file mode 100644 index 000000000..e1026ab78 --- /dev/null +++ b/ldb/include/ldb_private.h @@ -0,0 +1,251 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2004 + Copyright (C) Simo Sorce 2004-2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb private header + * + * Description: defines internal ldb structures used by the subsystem and modules + * + * Author: Andrew Tridgell + * Author: Stefan Metzmacher + */ + +#ifndef _LDB_PRIVATE_H_ +#define _LDB_PRIVATE_H_ 1 + +struct ldb_context; + +struct ldb_module_ops; + +struct ldb_backend_ops; + +/* basic module structure */ +struct ldb_module { + struct ldb_module *prev, *next; + struct ldb_context *ldb; + void *private_data; + const struct ldb_module_ops *ops; +}; + +/* + these function pointers define the operations that a ldb module must perform + they correspond exactly to the ldb_*() interface +*/ +struct ldb_module_ops { + const char *name; + int (*init_context) (struct ldb_module *); + int (*search)(struct ldb_module *, struct ldb_request *); /* search */ + int (*add)(struct ldb_module *, struct ldb_request *); /* add */ + int (*modify)(struct ldb_module *, struct ldb_request *); /* modify */ + int (*del)(struct ldb_module *, struct ldb_request *); /* delete */ + int (*rename)(struct ldb_module *, struct ldb_request *); /* rename */ + int (*request)(struct ldb_module *, struct ldb_request *); /* match any other operation */ + int (*extended)(struct ldb_module *, struct ldb_request *); /* extended operations */ + int (*start_transaction)(struct ldb_module *); + int (*end_transaction)(struct ldb_module *); + int (*del_transaction)(struct ldb_module *); + int (*wait)(struct ldb_handle *, enum ldb_wait_type); + int (*sequence_number)(struct ldb_module *, struct ldb_request *); +}; + + +typedef int (*ldb_connect_fn) (struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[], + struct ldb_module **module); + + +struct ldb_backend_ops { + const char *name; + ldb_connect_fn connect_fn; +}; + +const char *ldb_default_modules_dir(void); + +/* + schema related information needed for matching rules +*/ +struct ldb_schema { + /* attribute handling table */ + unsigned num_attributes; + struct ldb_schema_attribute *attributes; +}; + +/* + every ldb connection is started by establishing a ldb_context +*/ +struct ldb_context { + /* the operations provided by the backend */ + struct ldb_module *modules; + + /* debugging operations */ + struct ldb_debug_ops debug_ops; + + /* custom utf8 functions */ + struct ldb_utf8_fns utf8_fns; + + /* backend specific opaque parameters */ + struct ldb_opaque { + struct ldb_opaque *next; + const char *name; + void *value; + } *opaque; + + struct ldb_schema schema; + + char *err_string; + + int transaction_active; + + int default_timeout; + + unsigned int flags; + + unsigned int create_perms; + + char *modules_dir; + + struct event_context *ev_ctx; +}; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) +#endif + +/* + simplify out of memory handling +*/ +#define ldb_oom(ldb) ldb_debug_set(ldb, LDB_DEBUG_FATAL, "ldb out of memory at %s:%d\n", __FILE__, __LINE__) + +/* The following definitions come from lib/ldb/common/ldb.c */ + +int ldb_connect_backend(struct ldb_context *ldb, const char *url, const char *options[], + struct ldb_module **backend_module); +void ldb_set_default_dns(struct ldb_context *ldb); + +/* The following definitions come from lib/ldb/common/ldb_modules.c */ + +const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string); +int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out); +int ldb_load_modules(struct ldb_context *ldb, const char *options[]); +int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module); +int ldb_next_request(struct ldb_module *module, struct ldb_request *request); +int ldb_next_start_trans(struct ldb_module *module); +int ldb_next_end_trans(struct ldb_module *module); +int ldb_next_del_trans(struct ldb_module *module); +int ldb_next_init(struct ldb_module *module); + +void ldb_set_errstring(struct ldb_context *ldb, const char *err_string); +void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) PRINTF_ATTRIBUTE(2,3); +void ldb_reset_err_string(struct ldb_context *ldb); + +int ldb_register_module(const struct ldb_module_ops *); +int ldb_register_backend(const char *url_prefix, ldb_connect_fn); +void *ldb_dso_load_symbol(struct ldb_context *ldb, const char *name, + const char *symbol); + +/* The following definitions come from lib/ldb/common/ldb_debug.c */ +void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4); +void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level, + const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4); + +/* The following definitions come from lib/ldb/common/ldb_ldif.c */ +int ldb_should_b64_encode(const struct ldb_val *val); + +extern const struct ldb_module_ops ldb_objectclass_module_ops; +extern const struct ldb_module_ops ldb_operational_module_ops; +extern const struct ldb_module_ops ldb_paged_results_module_ops; +extern const struct ldb_module_ops ldb_rdn_name_module_ops; +extern const struct ldb_module_ops ldb_schema_module_ops; +extern const struct ldb_module_ops ldb_asq_module_ops; +extern const struct ldb_module_ops ldb_server_sort_module_ops; +extern const struct ldb_module_ops ldb_ldap_module_ops; +extern const struct ldb_module_ops ldb_ildap_module_ops; +extern const struct ldb_module_ops ldb_paged_searches_module_ops; +extern const struct ldb_module_ops ldb_tdb_module_ops; +extern const struct ldb_module_ops ldb_skel_module_ops; +extern const struct ldb_module_ops ldb_subtree_rename_module_ops; +extern const struct ldb_module_ops ldb_subtree_delete_module_ops; +extern const struct ldb_module_ops ldb_sqlite3_module_ops; +extern const struct ldb_module_ops ldb_wins_ldb_module_ops; +extern const struct ldb_module_ops ldb_ranged_results_module_ops; + +extern const struct ldb_backend_ops ldb_tdb_backend_ops; +extern const struct ldb_backend_ops ldb_sqlite3_backend_ops; +extern const struct ldb_backend_ops ldb_ldap_backend_ops; +extern const struct ldb_backend_ops ldb_ldapi_backend_ops; +extern const struct ldb_backend_ops ldb_ldaps_backend_ops; + +int ldb_match_msg(struct ldb_context *ldb, + const struct ldb_message *msg, + const struct ldb_parse_tree *tree, + struct ldb_dn *base, + enum ldb_scope scope); + +const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb, + const char *syntax); + +/* The following definitions come from lib/ldb/common/ldb_attributes.c */ + +int ldb_schema_attribute_add_with_syntax(struct ldb_context *ldb, + const char *name, + unsigned flags, + const struct ldb_schema_syntax *syntax); +int ldb_schema_attribute_add(struct ldb_context *ldb, + const char *name, + unsigned flags, + const char *syntax); +void ldb_schema_attribute_remove(struct ldb_context *ldb, const char *name); +int ldb_setup_wellknown_attributes(struct ldb_context *ldb); + +const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname); +void ldb_subclass_remove(struct ldb_context *ldb, const char *classname); +int ldb_subclass_add(struct ldb_context *ldb, const char *classname, const char *subclass); + +int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out); +int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2); + +/* The following definitions come from lib/ldb/common/ldb_controls.c */ +struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid); +int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver); +int check_critical_controls(struct ldb_control **controls); + +/* The following definitions come from lib/ldb/common/ldb_utf8.c */ +char *ldb_casefold_default(void *context, void *mem_ctx, const char *s, size_t n); + +void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el); + +/** + Obtain current/next database sequence number +*/ +int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num); + +#define LDB_SEQ_GLOBAL_SEQUENCE 0x01 +#define LDB_SEQ_TIMESTAMP_SEQUENCE 0x02 + + +#endif diff --git a/ldb/install-sh b/ldb/install-sh new file mode 100755 index 000000000..58719246f --- /dev/null +++ b/ldb/install-sh @@ -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 diff --git a/ldb/ldap.m4 b/ldb/ldap.m4 new file mode 100644 index 000000000..417083ed6 --- /dev/null +++ b/ldb/ldap.m4 @@ -0,0 +1,90 @@ +######################################################## +# Compile with LDAP support? + +LDAP_LIBS="" +with_ldap_support=auto +AC_MSG_CHECKING([for LDAP support]) + +AC_ARG_WITH(ldap, +AS_HELP_STRING([--with-ldap],[LDAP backend support (default=yes)]), +[ case "$withval" in + yes|no) + with_ldap_support=$withval + ;; + esac ]) + +AC_MSG_RESULT($with_ldap_support) + +if test x"$with_ldap_support" != x"no"; then + + ################################################################## + # first test for ldap.h and lber.h + # (ldap.h is required for this test) + AC_CHECK_HEADERS(ldap.h lber.h) + + if test x"$ac_cv_header_ldap_h" != x"yes"; then + if test x"$with_ldap_support" = x"yes"; then + AC_MSG_ERROR(ldap.h is needed for LDAP support) + else + AC_MSG_WARN(ldap.h is needed for LDAP support) + fi + + with_ldap_support=no + fi +fi + +if test x"$with_ldap_support" != x"no"; then + ac_save_LIBS=$LIBS + + ################################################################## + # we might need the lber lib on some systems. To avoid link errors + # this test must be before the libldap test + AC_CHECK_LIB_EXT(lber, LDAP_LIBS, ber_scanf) + + ######################################################## + # now see if we can find the ldap libs in standard paths + AC_CHECK_LIB_EXT(ldap, LDAP_LIBS, ldap_init) + + AC_CHECK_FUNC_EXT(ldap_domain2hostlist,$LDAP_LIBS) + + ######################################################## + # If we have LDAP, does it's rebind procedure take 2 or 3 arguments? + # Check found in pam_ldap 145. + AC_CHECK_FUNC_EXT(ldap_set_rebind_proc,$LDAP_LIBS) + + LIBS="$LIBS $LDAP_LIBS" + AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, smb_ldap_cv_ldap_set_rebind_proc, [ + AC_TRY_COMPILE([ + #include + #include ], + [ldap_set_rebind_proc(0, 0, 0);], + [smb_ldap_cv_ldap_set_rebind_proc=3], + [smb_ldap_cv_ldap_set_rebind_proc=2] + ) + ]) + + AC_DEFINE_UNQUOTED(LDAP_SET_REBIND_PROC_ARGS, $smb_ldap_cv_ldap_set_rebind_proc, [Number of arguments to ldap_set_rebind_proc]) + + AC_CHECK_FUNC_EXT(ldap_initialize,$LDAP_LIBS) + + if test x"$ac_cv_lib_ext_ldap_ldap_init" = x"yes" -a x"$ac_cv_func_ext_ldap_domain2hostlist" = x"yes"; then + AC_DEFINE(HAVE_LDAP,1,[Whether ldap is available]) + AC_DEFINE(HAVE_LDB_LDAP,1,[Whether ldb_ldap is available]) + with_ldap_support=yes + AC_MSG_CHECKING(whether LDAP support is used) + AC_MSG_RESULT(yes) + SMB_ENABLE(LDAP,YES) + else + if test x"$with_ldap_support" = x"yes"; then + AC_MSG_ERROR(libldap is needed for LDAP support) + else + AC_MSG_WARN(libldap is needed for LDAP support) + fi + + LDAP_LIBS="" + with_ldap_support=no + fi + LIBS=$ac_save_LIBS +fi + +SMB_EXT_LIB(LDAP,[${LDAP_LIBS}],[${LDAP_CFLAGS}],[${LDAP_CPPFLAGS}],[${LDAP_LDFLAGS}]) diff --git a/ldb/ldb.i b/ldb/ldb.i new file mode 100644 index 000000000..4b61ddba5 --- /dev/null +++ b/ldb/ldb.i @@ -0,0 +1,931 @@ +/* + Unix SMB/CIFS implementation. + + Swig interface to ldb. + + Copyright (C) 2005,2006 Tim Potter + Copyright (C) 2006 Simo Sorce + Copyright (C) 2007-2008 Jelmer Vernooij + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +%define DOCSTRING +"An interface to LDB, a LDAP-like API that can either to talk an embedded database (TDB-based) or a standards-compliant LDAP server." +%enddef + +%module(docstring=DOCSTRING) ldb + +%{ + +#include +#include +#include "talloc.h" +#include "events.h" +#include "ldb.h" +#include "ldb_errors.h" +#include "ldb_private.h" + +typedef struct ldb_message ldb_msg; +typedef struct ldb_context ldb; +typedef struct ldb_dn ldb_dn; +typedef struct ldb_ldif ldb_ldif; +typedef struct ldb_message_element ldb_message_element; +typedef int ldb_error; +typedef int ldb_int_error; + +%} + +%import "carrays.i" +%import "typemaps.i" +%include "exception.i" +%import "stdint.i" + +/* Don't expose talloc contexts in Python code. Python does reference + counting for us, so just create a new top-level talloc context. + */ +%typemap(in, numinputs=0, noblock=1) TALLOC_CTX * { + $1 = NULL; +} + + + +%constant int SCOPE_DEFAULT = LDB_SCOPE_DEFAULT; +%constant int SCOPE_BASE = LDB_SCOPE_BASE; +%constant int SCOPE_ONELEVEL = LDB_SCOPE_ONELEVEL; +%constant int SCOPE_SUBTREE = LDB_SCOPE_SUBTREE; + +%constant int CHANGETYPE_NONE = LDB_CHANGETYPE_NONE; +%constant int CHANGETYPE_ADD = LDB_CHANGETYPE_ADD; +%constant int CHANGETYPE_DELETE = LDB_CHANGETYPE_DELETE; +%constant int CHANGETYPE_MODIFY = LDB_CHANGETYPE_MODIFY; + +/* + * Wrap struct ldb_context + */ + +/* The ldb functions will crash if a NULL ldb context is passed so + catch this before it happens. */ + +%typemap(check,noblock=1) struct ldb_context* { + if ($1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); +} + +%typemap(check,noblock=1) ldb_msg * { + if ($1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); +} + +/* + * Wrap struct ldb_val + */ + +%typemap(in,noblock=1) struct ldb_val *INPUT (struct ldb_val temp) { + $1 = &temp; + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } + $1->length = PyString_Size($input); + $1->data = PyString_AsString($input); +} + +%inline %{ +PyObject *ldb_val_to_py_object(struct ldb_context *ldb_ctx, + struct ldb_message_element *el, + struct ldb_val *val) +{ + const struct ldb_schema_attribute *a; + struct ldb_val new_val; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + PyObject *ret; + + new_val = *val; + + if (ldb_ctx != NULL) { + a = ldb_schema_attribute_by_name(ldb_ctx, el->name); + + if (a != NULL) { + if (a->syntax->ldif_write_fn(ldb_ctx, mem_ctx, val, &new_val) != 0) { + talloc_free(mem_ctx); + return NULL; + } + } + } + + ret = PyString_FromStringAndSize((const char *)new_val.data, new_val.length); + + talloc_free(mem_ctx); + + return ret; +} + +%} + +%typemap(out,noblock=1) struct ldb_val * { + $result = PyString_FromStringAndSize((const char *)$1->data, $1->length) +} + +%typemap(out,noblock=1) struct ldb_val { + $result = PyString_FromStringAndSize((const char *)$1.data, $1.length) +} + +/* + * Wrap struct ldb_result + */ + +%typemap(in,noblock=1,numinputs=0) struct ldb_result **OUT (struct ldb_result *temp_ldb_result) { + $1 = &temp_ldb_result; +} + +#ifdef SWIGPYTHON +%typemap(argout,noblock=1) struct ldb_result ** (int i) { + $result = PyList_New((*$1)->count); + for (i = 0; i < (*$1)->count; i++) { + PyList_SetItem($result, i, + SWIG_NewPointerObj((*$1)->msgs[i], SWIGTYPE_p_ldb_message, 0) + ); + } +} + +%typemap(in,noblock=1,numinputs=1) const char * const *NULL_STR_LIST { + if ($input == Py_None) { + $1 = NULL; + } else if (PySequence_Check($input)) { + int i; + $1 = talloc_array(NULL, char *, PySequence_Size($input)+1); + for(i = 0; i < PySequence_Size($input); i++) + $1[i] = PyString_AsString(PySequence_GetItem($input, i)); + $1[i] = NULL; + } else { + SWIG_exception(SWIG_TypeError, "expected sequence"); + } +} + +%typemap(freearg,noblock=1) const char * const *NULL_STR_LIST { + talloc_free($1); +} + +%apply const char * const *NULL_STR_LIST { const char * const *attrs } +%apply const char * const *NULL_STR_LIST { const char * const *control_strings } + +#endif + +%types(struct ldb_result *); + +/* + * Wrap struct ldb_dn + */ + +%rename(__str__) ldb_dn::get_linearized; +%rename(__cmp__) ldb_dn::compare; +%rename(__len__) ldb_dn::get_comp_num; +%rename(Dn) ldb_dn; +%feature("docstring") ldb_dn "A LDB distinguished name."; +typedef struct ldb_dn { + %extend { + %feature("docstring") ldb_dn "S.__init__(ldb, string)\n" \ + "Create a new DN."; + ldb_dn(ldb *ldb_ctx, const char *str) + { + ldb_dn *ret = ldb_dn_new(ldb_ctx, ldb_ctx, str); + /* ldb_dn_new() doesn't accept NULL as memory context, so + we do it this way... */ + talloc_steal(NULL, ret); + + if (ret == NULL) + SWIG_exception(SWIG_ValueError, + "unable to parse dn string"); +fail: + return ret; + } + ~ldb_dn() { talloc_free($self); } + %feature("docstring") validate "S.validate() -> bool\n" \ + "Validate DN is correct."; + bool validate(); + const char *get_casefold(); + const char *get_linearized(); + %feature("docstring") parent "S.parent() -> dn\n" \ + "Get the parent for this DN."; + ldb_dn *parent() { return ldb_dn_get_parent(NULL, $self); } + int compare(ldb_dn *other); + bool is_valid(); + %feature("docstring") is_special "S.is_special() -> bool\n" \ + "Check whether this is a special LDB DN."; + bool is_special(); + %feature("docstring") is_null "S.is_null() -> bool\n" \ + "Check whether this is a null DN."; + bool is_null(); + bool check_special(const char *name); + int get_comp_num(); + %feature("docstring") add_child "S.add_child(dn) -> None\n" \ + "Add a child DN to this DN."; + bool add_child(ldb_dn *child); + %feature("docstring") add_base "S.add_base(dn) -> None\n" \ + "Add a base DN to this DN."; + bool add_base(ldb_dn *base); + %feature("docstring") canonical_str "S.canonical_str() -> string\n" \ + "Canonical version of this DN (like a posix path)."; + const char *canonical_str() { + return ldb_dn_canonical_string($self, $self); + } + %feature("docstring") canonical_ex_str "S.canonical_ex_str() -> string\n" \ + "Canonical version of this DN (like a posix path, with terminating newline)."; + const char *canonical_ex_str() { + return ldb_dn_canonical_ex_string($self, $self); + } +#ifdef SWIGPYTHON + char *__repr__(void) + { + char *dn = ldb_dn_get_linearized($self), *ret; + asprintf(&ret, "Dn('%s')", dn); + talloc_free(dn); + return ret; + } + + ldb_dn *__add__(ldb_dn *other) + { + ldb_dn *ret = ldb_dn_copy(NULL, $self); + ldb_dn_add_child(ret, other); + return ret; + } + + /* FIXME: implement __getslice__ */ +#endif + %pythoncode { + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__cmp__(other) == 0 + if isinstance(other, str): + return str(self) == other + return False + } + } +} ldb_dn; + +#ifdef SWIGPYTHON +%{ +struct ldb_context *ldb_context_from_py_object(PyObject *py_obj) +{ + struct ldb_context *ldb_ctx; + if (SWIG_ConvertPtr(py_obj, (void *)&ldb_ctx, SWIGTYPE_p_ldb_context, 0 | 0 ) < 0) + return NULL; + return ldb_ctx; +} + +int ldb_dn_from_pyobject(TALLOC_CTX *mem_ctx, PyObject *object, + struct ldb_context *ldb_ctx, ldb_dn **dn) +{ + int ret; + struct ldb_dn *odn; + if (ldb_ctx != NULL && PyString_Check(object)) { + odn = ldb_dn_new(mem_ctx, ldb_ctx, PyString_AsString(object)); + if (!odn) { + return SWIG_ERROR; + } + *dn = odn; + return 0; + } + ret = SWIG_ConvertPtr(object, (void **)&odn, SWIGTYPE_p_ldb_dn, + SWIG_POINTER_EXCEPTION); + *dn = ldb_dn_copy(mem_ctx, odn); + if (odn && !*dn) { + return SWIG_ERROR; + } + return ret; +} + +ldb_message_element *ldb_msg_element_from_pyobject(TALLOC_CTX *mem_ctx, + PyObject *set_obj, int flags, + const char *attr_name) +{ + struct ldb_message_element *me = talloc(mem_ctx, struct ldb_message_element); + me->name = attr_name; + me->flags = flags; + if (PyString_Check(set_obj)) { + me->num_values = 1; + me->values = talloc_array(me, struct ldb_val, me->num_values); + me->values[0].length = PyString_Size(set_obj); + me->values[0].data = (uint8_t *)talloc_strdup(me->values, + PyString_AsString(set_obj)); + } else if (PySequence_Check(set_obj)) { + int i; + me->num_values = PySequence_Size(set_obj); + me->values = talloc_array(me, struct ldb_val, me->num_values); + for (i = 0; i < me->num_values; i++) { + PyObject *obj = PySequence_GetItem(set_obj, i); + me->values[i].length = PyString_Size(obj); + me->values[i].data = (uint8_t *)PyString_AsString(obj); + } + } else { + talloc_free(me); + me = NULL; + } + + return me; +} + +PyObject *ldb_msg_element_to_set(struct ldb_context *ldb_ctx, + ldb_message_element *me) +{ + int i; + PyObject *result; + + /* Python << 2.5 doesn't have PySet_New and PySet_Add. */ + result = PyList_New(me->num_values); + + for (i = 0; i < me->num_values; i++) { + PyList_SetItem(result, i, + ldb_val_to_py_object(ldb_ctx, me, &me->values[i])); + } + + return result; +} + +%} +#endif + +/* ldb_message_element */ +%rename(MessageElement) ldb_message_element; +%feature("docstring") ldb_message_element "Message element."; +typedef struct ldb_message_element { + %extend { +#ifdef SWIGPYTHON + int __cmp__(ldb_message_element *other) + { + return ldb_msg_element_compare($self, other); + } + + PyObject *__iter__(void) + { + return PyObject_GetIter(ldb_msg_element_to_set(NULL, $self)); + } + + PyObject *__set__(void) + { + return ldb_msg_element_to_set(NULL, $self); + } + + ldb_message_element(PyObject *set_obj, int flags=0, const char *name = NULL) + { + return ldb_msg_element_from_pyobject(NULL, set_obj, flags, name); + } + + int __len__() + { + return $self->num_values; + } +#endif + + PyObject *get(int i) + { + if (i < 0 || i >= $self->num_values) + return Py_None; + + return ldb_val_to_py_object(NULL, $self, &$self->values[i]); + } + + ~ldb_message_element() { talloc_free($self); } + } + %pythoncode { + def __getitem__(self, i): + ret = self.get(i) + if ret is None: + raise KeyError("no such value") + return ret + + def __repr__(self): + return "MessageElement([%s])" % (",".join(repr(x) for x in self.__set__())) + + def __eq__(self, other): + if (len(self) == 1 and self.get(0) == other): + return True + if isinstance(other, self.__class__): + return self.__cmp__(other) == 0 + o = iter(other) + for i in range(len(self)): + if self.get(i) != o.next(): + return False + return True + } +} ldb_message_element; + +/* ldb_message */ + +%feature("docstring") ldb_message "Message."; +%rename(Message) ldb_message; +#ifdef SWIGPYTHON +%rename(__delitem__) ldb_message::remove_attr; +%typemap(out) ldb_message_element * { + if ($1 == NULL) + PyErr_SetString(PyExc_KeyError, "no such element"); + else + $result = SWIG_NewPointerObj($1, SWIGTYPE_p_ldb_message_element, 0); +} + +%inline { + PyObject *ldb_msg_list_elements(ldb_msg *msg) + { + int i, j = 0; + PyObject *obj = PyList_New(msg->num_elements+(msg->dn != NULL?1:0)); + if (msg->dn != NULL) { + PyList_SetItem(obj, j, PyString_FromString("dn")); + j++; + } + for (i = 0; i < msg->num_elements; i++) { + PyList_SetItem(obj, j, PyString_FromString(msg->elements[i].name)); + j++; + } + return obj; + } +} + +#endif + +typedef struct ldb_message { + ldb_dn *dn; + + %extend { + ldb_msg(ldb_dn *dn = NULL) { + ldb_msg *ret = ldb_msg_new(NULL); + ret->dn = talloc_reference(ret, dn); + return ret; + } + ~ldb_msg() { talloc_free($self); } + ldb_message_element *find_element(const char *name); + +#ifdef SWIGPYTHON + void __setitem__(const char *attr_name, ldb_message_element *val) + { + struct ldb_message_element *el; + + ldb_msg_remove_attr($self, attr_name); + + el = talloc($self, struct ldb_message_element); + el->name = talloc_strdup(el, attr_name); + el->num_values = val->num_values; + el->values = talloc_reference(el, val->values); + + ldb_msg_add($self, el, val->flags); + } + + void __setitem__(const char *attr_name, PyObject *val) + { + struct ldb_message_element *el = ldb_msg_element_from_pyobject(NULL, + val, 0, attr_name); + talloc_steal($self, el); + ldb_msg_remove_attr($self, attr_name); + ldb_msg_add($self, el, el->flags); + } + + unsigned int __len__() { return $self->num_elements; } + + PyObject *keys(void) + { + return ldb_msg_list_elements($self); + } + + PyObject *__iter__(void) + { + return PyObject_GetIter(ldb_msg_list_elements($self)); + } +#endif + void remove_attr(const char *name); +%pythoncode { + def get(self, key, default=None): + if key == "dn": + return self.dn + return self.find_element(key) + + def __getitem__(self, key): + ret = self.get(key, None) + if ret is None: + raise KeyError("No such element") + return ret + + def iteritems(self): + for k in self.keys(): + yield k, self[k] + + def items(self): + return list(self.iteritems()) + + def __repr__(self): + return "Message(%s)" % repr(dict(self.iteritems())) +} + } +} ldb_msg; + +/* FIXME: Convert ldb_result to 3-tuple: + (msgs, refs, controls) + */ + +typedef struct ldb_ldif ldb_ldif; + +#ifdef SWIGPYTHON +%{ +static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3, 0); + +static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) +{ + char *text; + PyObject *fn = context; + + vasprintf(&text, fmt, ap); + PyObject_CallFunction(fn, (char *)"(i,s)", level, text); + free(text); +} +%} + +%typemap(in,numinputs=1,noblock=1) (void (*debug)(void *context, enum ldb_debug_level level, const char *fmt, va_list ap), void *context) { + $1 = py_ldb_debug; + /* FIXME: Should be decreased somewhere as well. Perhaps register a + destructor and tie it to the ldb context ? */ + Py_INCREF($input); + $2 = $input; +} +#endif + +%inline { + static PyObject *ldb_ldif_to_pyobject(ldb_ldif *ldif) + { + if (ldif == NULL) { + return Py_None; + } else { + return Py_BuildValue((char *)"(iO)", ldif->changetype, + SWIG_NewPointerObj(ldif->msg, SWIGTYPE_p_ldb_message, 0)); + } + } +} + +/* + * Wrap ldb errors + */ + +%{ +PyObject *PyExc_LdbError; +%} + +%pythoncode %{ + LdbError = _ldb.LdbError +%} + +%init %{ + PyExc_LdbError = PyErr_NewException((char *)"_ldb.LdbError", NULL, NULL); + PyDict_SetItemString(d, "LdbError", PyExc_LdbError); +%} + +%ignore _LDB_ERRORS_H_; +%ignore LDB_SUCCESS; +%include "include/ldb_errors.h" + +/* + * Wrap ldb functions + */ + + +%typemap(out,noblock=1) ldb_error { + if ($1 != LDB_SUCCESS) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", $1, ldb_errstring(arg1))); + SWIG_fail; + } + $result = Py_None; +}; + +%typemap(out,noblock=1) ldb_int_error { + if ($1 != LDB_SUCCESS) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", $1, ldb_strerror($1))); + SWIG_fail; + } + $result = Py_None; +}; + +%typemap(out,noblock=1) struct ldb_control ** { + if ($1 == NULL) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(s)", ldb_errstring(arg1))); + SWIG_fail; + } + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); +} + +%rename(Ldb) ldb_context; +%feature("docstring") ldb_context "Connection to a LDB database."; + +%typemap(in,noblock=1) struct ldb_dn * { + if (ldb_dn_from_pyobject(NULL, $input, arg1, &$1) != 0) { + SWIG_fail; + } +}; + +%typemap(freearg,noblock=1) struct ldb_dn * { + talloc_free($1); +}; + +%typemap(in,numinputs=1) ldb_msg *add_msg { + Py_ssize_t dict_pos, msg_pos; + ldb_message_element *msgel; + PyObject *key, *value; + + if (PyDict_Check($input)) { + PyObject *dn_value = PyDict_GetItemString($input, "dn"); + $1 = ldb_msg_new(NULL); + $1->elements = talloc_zero_array($1, struct ldb_message_element, PyDict_Size($input)); + msg_pos = dict_pos = 0; + if (dn_value) { + /* using argp1 (magic SWIG value) here is a hack */ + if (ldb_dn_from_pyobject($1, dn_value, argp1, &$1->dn) != 0) { + SWIG_exception(SWIG_TypeError, "unable to import dn object"); + } + if ($1->dn == NULL) { + SWIG_exception(SWIG_TypeError, "dn set but not found"); + } + } + + while (PyDict_Next($input, &dict_pos, &key, &value)) { + char *key_str = PyString_AsString(key); + if (strcmp(key_str, "dn") != 0) { + msgel = ldb_msg_element_from_pyobject($1->elements, value, 0, key_str); + if (msgel == NULL) { + SWIG_exception(SWIG_TypeError, "unable to import element"); + } + memcpy(&$1->elements[msg_pos], msgel, sizeof(*msgel)); + msg_pos++; + } + } + + if ($1->dn == NULL) { + SWIG_exception(SWIG_TypeError, "no dn set"); + } + + $1->num_elements = msg_pos; + } else { + if (SWIG_ConvertPtr($input, (void **)&$1, SWIGTYPE_p_ldb_message, 0) != 0) { + SWIG_exception(SWIG_TypeError, "unable to convert ldb message"); + } + } +} + +/* Top-level ldb operations */ +typedef struct ldb_context { + %extend { + ldb(void) { + return ldb_init(NULL, event_context_init(NULL)); + } + + %feature("docstring") connect "S.connect(url,flags=0,options=None) -> None\n" \ + "Connect to a LDB URL."; + ldb_error connect(const char *url, unsigned int flags = 0, + const char *options[] = NULL); + + ~ldb() { talloc_free($self); } + ldb_error search_ex(TALLOC_CTX *mem_ctx, + ldb_dn *base = NULL, + enum ldb_scope scope = LDB_SCOPE_DEFAULT, + const char *expression = NULL, + const char *const *attrs = NULL, + struct ldb_control **controls = NULL, + struct ldb_result **OUT) { + int ret; + struct ldb_result *res; + struct ldb_request *req; + res = talloc_zero(mem_ctx, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&req, $self, mem_ctx, + base?base:ldb_get_default_basedn($self), + scope, + expression, + attrs, + controls, + res, + ldb_search_default_callback); + + if (ret != LDB_SUCCESS) { + talloc_free(res); + return ret; + } + + ldb_set_timeout($self, req, 0); /* use default timeout */ + + ret = ldb_request($self, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + + *OUT = res; + return ret; + } + + %feature("docstring") delete "S.delete(dn) -> None\n" \ + "Remove an entry."; + ldb_error delete(ldb_dn *dn); + %feature("docstring") rename "S.rename(old_dn, new_dn) -> None\n" \ + "Rename an entry."; + ldb_error rename(ldb_dn *olddn, ldb_dn *newdn); + struct ldb_control **parse_control_strings(TALLOC_CTX *mem_ctx, + const char * const*control_strings); + %feature("docstring") add "S.add(message) -> None\n" \ + "Add an entry."; + ldb_error add(ldb_msg *add_msg); + %feature("docstring") modify "S.modify(message) -> None\n" \ + "Modify an entry."; + ldb_error modify(ldb_msg *message); + ldb_dn *get_config_basedn(); + ldb_dn *get_root_basedn(); + ldb_dn *get_schema_basedn(); + ldb_dn *get_default_basedn(); + PyObject *schema_format_value(const char *element_name, PyObject *val) + { + const struct ldb_schema_attribute *a; + struct ldb_val old_val; + struct ldb_val new_val; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + PyObject *ret; + + old_val.data = PyString_AsString(val); + old_val.length = PyString_Size(val); + + a = ldb_schema_attribute_by_name($self, element_name); + + if (a == NULL) { + return Py_None; + } + + if (a->syntax->ldif_write_fn($self, mem_ctx, &old_val, &new_val) != 0) { + talloc_free(mem_ctx); + return Py_None; + } + + ret = PyString_FromStringAndSize((const char *)new_val.data, new_val.length); + + talloc_free(mem_ctx); + + return ret; + } + + const char *errstring(); + %feature("docstring") set_create_perms "S.set_create_perms(mode) -> None\n" \ + "Set mode to use when creating new LDB files."; + void set_create_perms(unsigned int perms); + %feature("docstring") set_modules_dir "S.set_modules_dir(path) -> None\n" \ + "Set path LDB should search for modules"; + void set_modules_dir(const char *path); + %feature("docstring") set_debug "S.set_debug(callback) -> None\n" \ + "Set callback for LDB debug messages.\n" \ + "The callback should accept a debug level and debug text."; + ldb_error set_debug(void (*debug)(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap), + void *context); + %feature("docstring") set_opaque "S.set_opaque(name, value) -> None\n" \ + "Set an opaque value on this LDB connection. \n" + ":note: Passing incorrect values may cause crashes."; + ldb_error set_opaque(const char *name, void *value); + %feature("docstring") get_opaque "S.get_opaque(name) -> value\n" \ + "Get an opaque value set on this LDB connection. \n" + ":note: The returned value may not be useful in Python."; + void *get_opaque(const char *name); + %feature("docstring") transaction_start "S.transaction_start() -> None\n" \ + "Start a new transaction."; + ldb_error transaction_start(); + %feature("docstring") transaction_commit "S.transaction_commit() -> None\n" \ + "Commit currently active transaction."; + ldb_error transaction_commit(); + %feature("docstring") transaction_cancel "S.transaction_cancel() -> None\n" \ + "Cancel currently active transaction."; + ldb_error transaction_cancel(); + void schema_attribute_remove(const char *name); + ldb_error schema_attribute_add(const char *attribute, unsigned flags, const char *syntax); + ldb_error setup_wellknown_attributes(void); + +#ifdef SWIGPYTHON + %typemap(in,numinputs=0,noblock=1) struct ldb_result **result_as_bool (struct ldb_result *tmp) { $1 = &tmp; } + %typemap(argout,noblock=1) struct ldb_result **result_as_bool { $result = ((*$1)->count > 0)?Py_True:Py_False; } + %typemap(freearg,noblock=1) struct ldb_result **result_as_bool { talloc_free(*$1); } + ldb_error __contains__(ldb_dn *dn, struct ldb_result **result_as_bool) + { + return ldb_search($self, dn, LDB_SCOPE_BASE, NULL, NULL, + result_as_bool); + } + + %feature("docstring") parse_ldif "S.parse_ldif(ldif) -> iter(messages)\n" \ + "Parse a string formatted using LDIF."; + + PyObject *parse_ldif(const char *s) + { + PyObject *list = PyList_New(0); + struct ldb_ldif *ldif; + while ((ldif = ldb_ldif_read_string($self, &s)) != NULL) { + PyList_Append(list, ldb_ldif_to_pyobject(ldif)); + } + return PyObject_GetIter(list); + } + + char *__repr__(void) + { + char *ret; + asprintf(&ret, "", ret); + return ret; + } +#endif + } + %pythoncode { + def __init__(self, url=None, flags=0, options=None): + """Create a new LDB object. + + Will also connect to the specified URL if one was given. + """ + _ldb.Ldb_swiginit(self,_ldb.new_Ldb()) + if url is not None: + self.connect(url, flags, options) + + def search(self, base=None, scope=SCOPE_DEFAULT, expression=None, + attrs=None, controls=None): + """Search in a database. + + :param base: Optional base DN to search + :param scope: Search scope (SCOPE_BASE, SCOPE_ONELEVEL or SCOPE_SUBTREE) + :param expression: Optional search expression + :param attrs: Attributes to return (defaults to all) + :param controls: Optional list of controls + :return: Iterator over Message objects + """ + if not (attrs is None or isinstance(attrs, list)): + raise TypeError("attributes not a list") + parsed_controls = None + if controls is not None: + parsed_controls = self.parse_control_strings(controls) + return self.search_ex(base, scope, expression, attrs, + parsed_controls) + } + +} ldb; + +%typemap(in,noblock=1) struct ldb_dn *; +%typemap(freearg,noblock=1) struct ldb_dn *; + +%nodefault ldb_message; +%nodefault ldb_context; +%nodefault Dn; + +%rename(valid_attr_name) ldb_valid_attr_name; +%feature("docstring") ldb_valid_attr_name "S.valid_attr_name(name) -> bool\n" + "Check whether the supplied name is a valid attribute name."; +int ldb_valid_attr_name(const char *s); + +typedef unsigned long time_t; + +%feature("docstring") timestring "S.timestring(int) -> string\n" + "Generate a LDAP time string from a UNIX timestamp"; + +%inline %{ +static char *timestring(time_t t) +{ + char *tresult = ldb_timestring(NULL, t); + char *result = strdup(tresult); + talloc_free(tresult); + return result; +} +%} + +%rename(string_to_time) ldb_string_to_time; +%feature("docstring") ldb_string_to_time "S.string_to_time(string) -> int\n" + "Parse a LDAP time string into a UNIX timestamp."; +time_t ldb_string_to_time(const char *s); + +%typemap(in,noblock=1) const struct ldb_module_ops * { + $1 = talloc_zero(talloc_autofree_context(), struct ldb_module_ops); + + $1->name = (char *)PyObject_GetAttrString($input, (char *)"name"); +} + +%feature("docstring") ldb_register_module "S.register_module(module) -> None\n" + "Register a LDB module."; +%rename(register_module) ldb_register_module; +ldb_int_error ldb_register_module(const struct ldb_module_ops *); + +%pythoncode { +__docformat__ = "restructuredText" +} diff --git a/ldb/ldb.mk b/ldb/ldb.mk new file mode 100644 index 000000000..a7b1cb0c6 --- /dev/null +++ b/ldb/ldb.mk @@ -0,0 +1,86 @@ +LDB_LIB = -Llib -lldb + +LIB_FLAGS=$(LDFLAGS) $(LIBS) $(LDB_LIB) $(POPT_LIBS) $(TALLOC_LIBS) \ + $(TDB_LIBS) $(EVENTS_LIBS) $(LDAP_LIBS) $(LIBDL) + +LDB_TDB_DIR=ldb_tdb +LDB_TDB_OBJ=$(LDB_TDB_DIR)/ldb_tdb.o \ + $(LDB_TDB_DIR)/ldb_pack.o $(LDB_TDB_DIR)/ldb_search.o $(LDB_TDB_DIR)/ldb_index.o \ + $(LDB_TDB_DIR)/ldb_cache.o $(LDB_TDB_DIR)/ldb_tdb_wrap.o + +LDB_MAP_DIR=ldb_map +LDB_MAP_OBJ=$(LDB_MAP_DIR)/ldb_map.o $(LDB_MAP_DIR)/ldb_map_inbound.o \ + $(LDB_MAP_DIR)/ldb_map_outbound.o + +COMDIR=common +COMMON_OBJ=$(COMDIR)/ldb.o $(COMDIR)/ldb_ldif.o \ + $(COMDIR)/ldb_parse.o $(COMDIR)/ldb_msg.o $(COMDIR)/ldb_utf8.o \ + $(COMDIR)/ldb_debug.o $(COMDIR)/ldb_modules.o \ + $(COMDIR)/ldb_dn.o $(COMDIR)/ldb_match.o $(COMDIR)/ldb_attributes.o \ + $(COMDIR)/attrib_handlers.o $(COMDIR)/ldb_controls.o $(COMDIR)/qsort.o + +MODDIR=modules +MODULES_OBJ=$(MODDIR)/operational.o $(MODDIR)/rdn_name.o \ + $(MODDIR)/paged_results.o $(MODDIR)/sort.o $(MODDIR)/asq.o + +NSSDIR=nssldb +NSS_OBJ= $(NSSDIR)/ldb-nss.o $(NSSDIR)/ldb-pwd.o $(NSSDIR)/ldb-grp.o +NSS_LIB = lib/libnss_ldb.$(SHLIBEXT).2 + +lib/libldb.a: $(OBJS) + ar -rv $@ $(OBJS) + @-ranlib $@ + +sample.$(SHLIBEXT): tests/sample_module.o + $(MDLD) $(MDLD_FLAGS) -o $@ tests/sample_module.o + +bin/ldbadd: tools/ldbadd.o tools/cmdline.o + $(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) + +bin/ldbsearch: tools/ldbsearch.o tools/cmdline.o + $(CC) -o bin/ldbsearch tools/ldbsearch.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) + +bin/ldbdel: tools/ldbdel.o tools/cmdline.o + $(CC) -o bin/ldbdel tools/ldbdel.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) + +bin/ldbmodify: tools/ldbmodify.o tools/cmdline.o + $(CC) -o bin/ldbmodify tools/ldbmodify.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) + +bin/ldbedit: tools/ldbedit.o tools/cmdline.o + $(CC) -o bin/ldbedit tools/ldbedit.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) + +bin/ldbrename: tools/ldbrename.o tools/cmdline.o + $(CC) -o bin/ldbrename tools/ldbrename.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) + +bin/ldbtest: tools/ldbtest.o tools/cmdline.o + $(CC) -o bin/ldbtest tools/ldbtest.o tools/cmdline.o $(LIB_FLAGS) $(LD_EXPORT_DYNAMIC) + +examples/ldbreader: examples/ldbreader.o + $(CC) -o examples/ldbreader examples/ldbreader.o $(LIB_FLAGS) + +examples/ldifreader: examples/ldifreader.o + $(CC) -o examples/ldifreader examples/ldifreader.o $(LIB_FLAGS) + +# Python bindings +build-python:: _ldb.$(SHLIBEXT) + +ldb_wrap.o: $(ldbdir)/ldb_wrap.c + $(CC) $(PICFLAG) -c $(ldbdir)/ldb_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` + +_ldb.$(SHLIBEXT): ldb_wrap.o + $(SHLD) $(SHLD_FLAGS) -o _ldb.$(SHLIBEXT) ldb_wrap.o $(LIB_FLAGS) `$(PYTHON_CONFIG) --ldflags` + +install-python:: build-python + mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \ + $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` + cp $(ldbdir)/ldb.py $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` + cp _ldb.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` + +install-swig:: + cp ldb.i `$(SWIG) -swiglib` + +check-python:: build-python + LD_LIBRARY_PATH=lib PYTHONPATH=.:$(ldbdir) $(PYTHON) $(ldbdir)/tests/python/api.py + +clean:: + rm -f _ldb.$(SHLIBEXT) diff --git a/ldb/ldb.pc b/ldb/ldb.pc new file mode 100644 index 000000000..cf986a0f5 --- /dev/null +++ b/ldb/ldb.pc @@ -0,0 +1,16 @@ +prefix=/usr/local/samba +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include +modulesdir=${prefix}/modules + +Name: ldb +Description: An LDAP-like embedded database +Version: 4 +Requires.private: tdb +Requires: talloc +Libs: -L${libdir} -lldb +Libs.private: @LDAP_LIBS@ +Cflags: -I${includedir} +Modulesdir: ${modulesdir} +URL: http://ldb.samba.org/ diff --git a/ldb/ldb.pc.in b/ldb/ldb.pc.in new file mode 100644 index 000000000..b7e4c8584 --- /dev/null +++ b/ldb/ldb.pc.in @@ -0,0 +1,16 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +modulesdir=@modulesdir@ + +Name: ldb +Description: An LDAP-like embedded database +Version: @PACKAGE_VERSION@ +Requires.private: tdb +Requires: talloc +Libs: -L${libdir} -lldb +Libs.private: @LDAP_LIBS@ +Cflags: -I${includedir} +Modulesdir: ${modulesdir} +URL: http://ldb.samba.org/ diff --git a/ldb/ldb.py b/ldb/ldb.py new file mode 100644 index 000000000..ae2c18736 --- /dev/null +++ b/ldb/ldb.py @@ -0,0 +1,477 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 1.3.35 +# +# Don't modify this file, modify the SWIG interface instead. + +""" +An interface to LDB, a LDAP-like API that can either to talk an embedded database (TDB-based) or a standards-compliant LDAP server. +""" + +import _ldb +import new +new_instancemethod = new.instancemethod +try: + _swig_property = property +except NameError: + pass # Python < 2.2 doesn't have 'property'. +def _swig_setattr_nondynamic(self,class_type,name,value,static=1): + if (name == "thisown"): return self.this.own(value) + if (name == "this"): + if type(value).__name__ == 'PySwigObject': + self.__dict__[name] = value + return + method = class_type.__swig_setmethods__.get(name,None) + if method: return method(self,value) + if (not static) or hasattr(self,name): + self.__dict__[name] = value + else: + raise AttributeError("You cannot add attributes to %s" % self) + +def _swig_setattr(self,class_type,name,value): + return _swig_setattr_nondynamic(self,class_type,name,value,0) + +def _swig_getattr(self,class_type,name): + if (name == "thisown"): return self.this.own() + method = class_type.__swig_getmethods__.get(name,None) + if method: return method(self) + raise AttributeError,name + +def _swig_repr(self): + try: strthis = "proxy of " + self.this.__repr__() + except: strthis = "" + return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) + +import types +try: + _object = types.ObjectType + _newclass = 1 +except AttributeError: + class _object : pass + _newclass = 0 +del types + + +def _swig_setattr_nondynamic_method(set): + def set_attr(self,name,value): + if (name == "thisown"): return self.this.own(value) + if hasattr(self,name) or (name == "this"): + set(self,name,value) + else: + raise AttributeError("You cannot add attributes to %s" % self) + return set_attr + + +SCOPE_DEFAULT = _ldb.SCOPE_DEFAULT +SCOPE_BASE = _ldb.SCOPE_BASE +SCOPE_ONELEVEL = _ldb.SCOPE_ONELEVEL +SCOPE_SUBTREE = _ldb.SCOPE_SUBTREE +CHANGETYPE_NONE = _ldb.CHANGETYPE_NONE +CHANGETYPE_ADD = _ldb.CHANGETYPE_ADD +CHANGETYPE_DELETE = _ldb.CHANGETYPE_DELETE +CHANGETYPE_MODIFY = _ldb.CHANGETYPE_MODIFY +ldb_val_to_py_object = _ldb.ldb_val_to_py_object +class Dn(object): + """A LDB distinguished name.""" + thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') + def __init__(self, *args, **kwargs): + """ + S.__init__(ldb, string) + Create a new DN. + """ + _ldb.Dn_swiginit(self,_ldb.new_Dn(*args, **kwargs)) + __swig_destroy__ = _ldb.delete_Dn + def validate(*args, **kwargs): + """ + S.validate() -> bool + Validate DN is correct. + """ + return _ldb.Dn_validate(*args, **kwargs) + + def parent(*args, **kwargs): + """ + S.parent() -> dn + Get the parent for this DN. + """ + return _ldb.Dn_parent(*args, **kwargs) + + def is_special(*args, **kwargs): + """ + S.is_special() -> bool + Check whether this is a special LDB DN. + """ + return _ldb.Dn_is_special(*args, **kwargs) + + def is_null(*args, **kwargs): + """ + S.is_null() -> bool + Check whether this is a null DN. + """ + return _ldb.Dn_is_null(*args, **kwargs) + + def add_child(*args, **kwargs): + """ + S.add_child(dn) -> None + Add a child DN to this DN. + """ + return _ldb.Dn_add_child(*args, **kwargs) + + def add_base(*args, **kwargs): + """ + S.add_base(dn) -> None + Add a base DN to this DN. + """ + return _ldb.Dn_add_base(*args, **kwargs) + + def canonical_str(*args, **kwargs): + """ + S.canonical_str() -> string + Canonical version of this DN (like a posix path). + """ + return _ldb.Dn_canonical_str(*args, **kwargs) + + def canonical_ex_str(*args, **kwargs): + """ + S.canonical_ex_str() -> string + Canonical version of this DN (like a posix path, with terminating newline). + """ + return _ldb.Dn_canonical_ex_str(*args, **kwargs) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__cmp__(other) == 0 + if isinstance(other, str): + return str(self) == other + return False + +Dn.validate = new_instancemethod(_ldb.Dn_validate,None,Dn) +Dn.get_casefold = new_instancemethod(_ldb.Dn_get_casefold,None,Dn) +Dn.__str__ = new_instancemethod(_ldb.Dn___str__,None,Dn) +Dn.parent = new_instancemethod(_ldb.Dn_parent,None,Dn) +Dn.__cmp__ = new_instancemethod(_ldb.Dn___cmp__,None,Dn) +Dn.is_valid = new_instancemethod(_ldb.Dn_is_valid,None,Dn) +Dn.is_special = new_instancemethod(_ldb.Dn_is_special,None,Dn) +Dn.is_null = new_instancemethod(_ldb.Dn_is_null,None,Dn) +Dn.check_special = new_instancemethod(_ldb.Dn_check_special,None,Dn) +Dn.__len__ = new_instancemethod(_ldb.Dn___len__,None,Dn) +Dn.add_child = new_instancemethod(_ldb.Dn_add_child,None,Dn) +Dn.add_base = new_instancemethod(_ldb.Dn_add_base,None,Dn) +Dn.canonical_str = new_instancemethod(_ldb.Dn_canonical_str,None,Dn) +Dn.canonical_ex_str = new_instancemethod(_ldb.Dn_canonical_ex_str,None,Dn) +Dn.__repr__ = new_instancemethod(_ldb.Dn___repr__,None,Dn) +Dn.__add__ = new_instancemethod(_ldb.Dn___add__,None,Dn) +Dn_swigregister = _ldb.Dn_swigregister +Dn_swigregister(Dn) + +class MessageElement(object): + """Message element.""" + thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') + __repr__ = _swig_repr + def __init__(self, *args, **kwargs): + """Message element.""" + _ldb.MessageElement_swiginit(self,_ldb.new_MessageElement(*args, **kwargs)) + __swig_destroy__ = _ldb.delete_MessageElement + def __getitem__(self, i): + ret = self.get(i) + if ret is None: + raise KeyError("no such value") + return ret + + def __repr__(self): + return "MessageElement([%s])" % (",".join(repr(x) for x in self.__set__())) + + def __eq__(self, other): + if (len(self) == 1 and self.get(0) == other): + return True + if isinstance(other, self.__class__): + return self.__cmp__(other) == 0 + o = iter(other) + for i in range(len(self)): + if self.get(i) != o.next(): + return False + return True + +MessageElement.__cmp__ = new_instancemethod(_ldb.MessageElement___cmp__,None,MessageElement) +MessageElement.__iter__ = new_instancemethod(_ldb.MessageElement___iter__,None,MessageElement) +MessageElement.__set__ = new_instancemethod(_ldb.MessageElement___set__,None,MessageElement) +MessageElement.__len__ = new_instancemethod(_ldb.MessageElement___len__,None,MessageElement) +MessageElement.get = new_instancemethod(_ldb.MessageElement_get,None,MessageElement) +MessageElement_swigregister = _ldb.MessageElement_swigregister +MessageElement_swigregister(MessageElement) + +ldb_msg_list_elements = _ldb.ldb_msg_list_elements +class Message(object): + """Message.""" + thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') + __repr__ = _swig_repr + dn = _swig_property(_ldb.Message_dn_get, _ldb.Message_dn_set) + def __init__(self, *args, **kwargs): + _ldb.Message_swiginit(self,_ldb.new_Message(*args, **kwargs)) + __swig_destroy__ = _ldb.delete_Message + def get(self, key, default=None): + if key == "dn": + return self.dn + return self.find_element(key) + + def __getitem__(self, key): + ret = self.get(key, None) + if ret is None: + raise KeyError("No such element") + return ret + + def iteritems(self): + for k in self.keys(): + yield k, self[k] + + def items(self): + return list(self.iteritems()) + + def __repr__(self): + return "Message(%s)" % repr(dict(self.iteritems())) + +Message.find_element = new_instancemethod(_ldb.Message_find_element,None,Message) +Message.__setitem__ = new_instancemethod(_ldb.Message___setitem__,None,Message) +Message.__len__ = new_instancemethod(_ldb.Message___len__,None,Message) +Message.keys = new_instancemethod(_ldb.Message_keys,None,Message) +Message.__iter__ = new_instancemethod(_ldb.Message___iter__,None,Message) +Message.__delitem__ = new_instancemethod(_ldb.Message___delitem__,None,Message) +Message_swigregister = _ldb.Message_swigregister +Message_swigregister(Message) + +ldb_ldif_to_pyobject = _ldb.ldb_ldif_to_pyobject +LdbError = _ldb.LdbError + +LDB_ERR_OPERATIONS_ERROR = _ldb.LDB_ERR_OPERATIONS_ERROR +LDB_ERR_PROTOCOL_ERROR = _ldb.LDB_ERR_PROTOCOL_ERROR +LDB_ERR_TIME_LIMIT_EXCEEDED = _ldb.LDB_ERR_TIME_LIMIT_EXCEEDED +LDB_ERR_SIZE_LIMIT_EXCEEDED = _ldb.LDB_ERR_SIZE_LIMIT_EXCEEDED +LDB_ERR_COMPARE_FALSE = _ldb.LDB_ERR_COMPARE_FALSE +LDB_ERR_COMPARE_TRUE = _ldb.LDB_ERR_COMPARE_TRUE +LDB_ERR_AUTH_METHOD_NOT_SUPPORTED = _ldb.LDB_ERR_AUTH_METHOD_NOT_SUPPORTED +LDB_ERR_STRONG_AUTH_REQUIRED = _ldb.LDB_ERR_STRONG_AUTH_REQUIRED +LDB_ERR_REFERRAL = _ldb.LDB_ERR_REFERRAL +LDB_ERR_ADMIN_LIMIT_EXCEEDED = _ldb.LDB_ERR_ADMIN_LIMIT_EXCEEDED +LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION = _ldb.LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION +LDB_ERR_CONFIDENTIALITY_REQUIRED = _ldb.LDB_ERR_CONFIDENTIALITY_REQUIRED +LDB_ERR_SASL_BIND_IN_PROGRESS = _ldb.LDB_ERR_SASL_BIND_IN_PROGRESS +LDB_ERR_NO_SUCH_ATTRIBUTE = _ldb.LDB_ERR_NO_SUCH_ATTRIBUTE +LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE = _ldb.LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE +LDB_ERR_INAPPROPRIATE_MATCHING = _ldb.LDB_ERR_INAPPROPRIATE_MATCHING +LDB_ERR_CONSTRAINT_VIOLATION = _ldb.LDB_ERR_CONSTRAINT_VIOLATION +LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS = _ldb.LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS +LDB_ERR_INVALID_ATTRIBUTE_SYNTAX = _ldb.LDB_ERR_INVALID_ATTRIBUTE_SYNTAX +LDB_ERR_NO_SUCH_OBJECT = _ldb.LDB_ERR_NO_SUCH_OBJECT +LDB_ERR_ALIAS_PROBLEM = _ldb.LDB_ERR_ALIAS_PROBLEM +LDB_ERR_INVALID_DN_SYNTAX = _ldb.LDB_ERR_INVALID_DN_SYNTAX +LDB_ERR_ALIAS_DEREFERENCING_PROBLEM = _ldb.LDB_ERR_ALIAS_DEREFERENCING_PROBLEM +LDB_ERR_INAPPROPRIATE_AUTHENTICATION = _ldb.LDB_ERR_INAPPROPRIATE_AUTHENTICATION +LDB_ERR_INVALID_CREDENTIALS = _ldb.LDB_ERR_INVALID_CREDENTIALS +LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS = _ldb.LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS +LDB_ERR_BUSY = _ldb.LDB_ERR_BUSY +LDB_ERR_UNAVAILABLE = _ldb.LDB_ERR_UNAVAILABLE +LDB_ERR_UNWILLING_TO_PERFORM = _ldb.LDB_ERR_UNWILLING_TO_PERFORM +LDB_ERR_LOOP_DETECT = _ldb.LDB_ERR_LOOP_DETECT +LDB_ERR_NAMING_VIOLATION = _ldb.LDB_ERR_NAMING_VIOLATION +LDB_ERR_OBJECT_CLASS_VIOLATION = _ldb.LDB_ERR_OBJECT_CLASS_VIOLATION +LDB_ERR_NOT_ALLOWED_ON_NON_LEAF = _ldb.LDB_ERR_NOT_ALLOWED_ON_NON_LEAF +LDB_ERR_NOT_ALLOWED_ON_RDN = _ldb.LDB_ERR_NOT_ALLOWED_ON_RDN +LDB_ERR_ENTRY_ALREADY_EXISTS = _ldb.LDB_ERR_ENTRY_ALREADY_EXISTS +LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED = _ldb.LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED +LDB_ERR_AFFECTS_MULTIPLE_DSAS = _ldb.LDB_ERR_AFFECTS_MULTIPLE_DSAS +LDB_ERR_OTHER = _ldb.LDB_ERR_OTHER +class Ldb(object): + """Connection to a LDB database.""" + thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') + def __init__(self, *args, **kwargs): + _ldb.Ldb_swiginit(self,_ldb.new_Ldb(*args, **kwargs)) + def connect(*args, **kwargs): + """ + S.connect(url,flags=0,options=None) -> None + Connect to a LDB URL. + """ + return _ldb.Ldb_connect(*args, **kwargs) + + __swig_destroy__ = _ldb.delete_Ldb + def delete(*args, **kwargs): + """ + S.delete(dn) -> None + Remove an entry. + """ + return _ldb.Ldb_delete(*args, **kwargs) + + def rename(*args, **kwargs): + """ + S.rename(old_dn, new_dn) -> None + Rename an entry. + """ + return _ldb.Ldb_rename(*args, **kwargs) + + def add(*args, **kwargs): + """ + S.add(message) -> None + Add an entry. + """ + return _ldb.Ldb_add(*args, **kwargs) + + def modify(*args, **kwargs): + """ + S.modify(message) -> None + Modify an entry. + """ + return _ldb.Ldb_modify(*args, **kwargs) + + def set_create_perms(*args, **kwargs): + """ + S.set_create_perms(mode) -> None + Set mode to use when creating new LDB files. + """ + return _ldb.Ldb_set_create_perms(*args, **kwargs) + + def set_modules_dir(*args, **kwargs): + """ + S.set_modules_dir(path) -> None + Set path LDB should search for modules + """ + return _ldb.Ldb_set_modules_dir(*args, **kwargs) + + def set_debug(*args, **kwargs): + """ + S.set_debug(callback) -> None + Set callback for LDB debug messages. + The callback should accept a debug level and debug text. + """ + return _ldb.Ldb_set_debug(*args, **kwargs) + + def set_opaque(*args, **kwargs): + """ + S.set_opaque(name, value) -> None + Set an opaque value on this LDB connection. + :note: Passing incorrect values may cause crashes. + """ + return _ldb.Ldb_set_opaque(*args, **kwargs) + + def get_opaque(*args, **kwargs): + """ + S.get_opaque(name) -> value + Get an opaque value set on this LDB connection. + :note: The returned value may not be useful in Python. + """ + return _ldb.Ldb_get_opaque(*args, **kwargs) + + def transaction_start(*args, **kwargs): + """ + S.transaction_start() -> None + Start a new transaction. + """ + return _ldb.Ldb_transaction_start(*args, **kwargs) + + def transaction_commit(*args, **kwargs): + """ + S.transaction_commit() -> None + Commit currently active transaction. + """ + return _ldb.Ldb_transaction_commit(*args, **kwargs) + + def transaction_cancel(*args, **kwargs): + """ + S.transaction_cancel() -> None + Cancel currently active transaction. + """ + return _ldb.Ldb_transaction_cancel(*args, **kwargs) + + def parse_ldif(*args, **kwargs): + """ + S.parse_ldif(ldif) -> iter(messages) + Parse a string formatted using LDIF. + """ + return _ldb.Ldb_parse_ldif(*args, **kwargs) + + def __init__(self, url=None, flags=0, options=None): + """Create a new LDB object. + + Will also connect to the specified URL if one was given. + """ + _ldb.Ldb_swiginit(self,_ldb.new_Ldb()) + if url is not None: + self.connect(url, flags, options) + + def search(self, base=None, scope=SCOPE_DEFAULT, expression=None, + attrs=None, controls=None): + """Search in a database. + + :param base: Optional base DN to search + :param scope: Search scope (SCOPE_BASE, SCOPE_ONELEVEL or SCOPE_SUBTREE) + :param expression: Optional search expression + :param attrs: Attributes to return (defaults to all) + :param controls: Optional list of controls + :return: Iterator over Message objects + """ + if not (attrs is None or isinstance(attrs, list)): + raise TypeError("attributes not a list") + parsed_controls = None + if controls is not None: + parsed_controls = self.parse_control_strings(controls) + return self.search_ex(base, scope, expression, attrs, + parsed_controls) + +Ldb.connect = new_instancemethod(_ldb.Ldb_connect,None,Ldb) +Ldb.search_ex = new_instancemethod(_ldb.Ldb_search_ex,None,Ldb) +Ldb.delete = new_instancemethod(_ldb.Ldb_delete,None,Ldb) +Ldb.rename = new_instancemethod(_ldb.Ldb_rename,None,Ldb) +Ldb.parse_control_strings = new_instancemethod(_ldb.Ldb_parse_control_strings,None,Ldb) +Ldb.add = new_instancemethod(_ldb.Ldb_add,None,Ldb) +Ldb.modify = new_instancemethod(_ldb.Ldb_modify,None,Ldb) +Ldb.get_config_basedn = new_instancemethod(_ldb.Ldb_get_config_basedn,None,Ldb) +Ldb.get_root_basedn = new_instancemethod(_ldb.Ldb_get_root_basedn,None,Ldb) +Ldb.get_schema_basedn = new_instancemethod(_ldb.Ldb_get_schema_basedn,None,Ldb) +Ldb.get_default_basedn = new_instancemethod(_ldb.Ldb_get_default_basedn,None,Ldb) +Ldb.schema_format_value = new_instancemethod(_ldb.Ldb_schema_format_value,None,Ldb) +Ldb.errstring = new_instancemethod(_ldb.Ldb_errstring,None,Ldb) +Ldb.set_create_perms = new_instancemethod(_ldb.Ldb_set_create_perms,None,Ldb) +Ldb.set_modules_dir = new_instancemethod(_ldb.Ldb_set_modules_dir,None,Ldb) +Ldb.set_debug = new_instancemethod(_ldb.Ldb_set_debug,None,Ldb) +Ldb.set_opaque = new_instancemethod(_ldb.Ldb_set_opaque,None,Ldb) +Ldb.get_opaque = new_instancemethod(_ldb.Ldb_get_opaque,None,Ldb) +Ldb.transaction_start = new_instancemethod(_ldb.Ldb_transaction_start,None,Ldb) +Ldb.transaction_commit = new_instancemethod(_ldb.Ldb_transaction_commit,None,Ldb) +Ldb.transaction_cancel = new_instancemethod(_ldb.Ldb_transaction_cancel,None,Ldb) +Ldb.schema_attribute_remove = new_instancemethod(_ldb.Ldb_schema_attribute_remove,None,Ldb) +Ldb.schema_attribute_add = new_instancemethod(_ldb.Ldb_schema_attribute_add,None,Ldb) +Ldb.setup_wellknown_attributes = new_instancemethod(_ldb.Ldb_setup_wellknown_attributes,None,Ldb) +Ldb.__contains__ = new_instancemethod(_ldb.Ldb___contains__,None,Ldb) +Ldb.parse_ldif = new_instancemethod(_ldb.Ldb_parse_ldif,None,Ldb) +Ldb.__repr__ = new_instancemethod(_ldb.Ldb___repr__,None,Ldb) +Ldb_swigregister = _ldb.Ldb_swigregister +Ldb_swigregister(Ldb) + + +def valid_attr_name(*args, **kwargs): + """ + S.valid_attr_name(name) -> bool + Check whether the supplied name is a valid attribute name. + """ + return _ldb.valid_attr_name(*args, **kwargs) + +def timestring(*args, **kwargs): + """ + S.timestring(int) -> string + Generate a LDAP time string from a UNIX timestamp + """ + return _ldb.timestring(*args, **kwargs) + +def string_to_time(*args, **kwargs): + """ + S.string_to_time(string) -> int + Parse a LDAP time string into a UNIX timestamp. + """ + return _ldb.string_to_time(*args, **kwargs) + +def register_module(*args, **kwargs): + """ + S.register_module(module) -> None + Register a LDB module. + """ + return _ldb.register_module(*args, **kwargs) +__docformat__ = "restructuredText" + + + diff --git a/ldb/ldb_ildap/config.mk b/ldb/ldb_ildap/config.mk new file mode 100644 index 000000000..6a1ef8164 --- /dev/null +++ b/ldb/ldb_ildap/config.mk @@ -0,0 +1,13 @@ +################################################ +# Start MODULE ldb_ildap +[MODULE::ldb_ildap] +SUBSYSTEM = LIBLDB +CFLAGS = -I$(ldbsrcdir)/include +PRIVATE_DEPENDENCIES = LIBTALLOC LIBCLI_LDAP CREDENTIALS +INIT_FUNCTION = LDB_BACKEND(ldapi),LDB_BACKEND(ldaps),LDB_BACKEND(ldap) +ALIASES = ldapi ldaps ldap +# End MODULE ldb_ildap +################################################ + +ldb_ildap_OBJ_FILES = $(ldbsrcdir)/ldb_ildap/ldb_ildap.o + diff --git a/ldb/ldb_ildap/ldb_ildap.c b/ldb/ldb_ildap/ldb_ildap.c new file mode 100644 index 000000000..5ad671ea2 --- /dev/null +++ b/ldb/ldb_ildap/ldb_ildap.c @@ -0,0 +1,843 @@ +/* + ldb database library - ildap backend + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Simo Sorce 2008 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb_ildap + * + * Component: ldb ildap backend + * + * Description: This is a ldb backend for the internal ldap + * client library in Samba4. By using this backend we are + * independent of a system ldap library + * + * Author: Andrew Tridgell + * + * Modifications: + * + * - description: make the module use asyncronous calls + * date: Feb 2006 + * author: Simo Sorce + */ + + +#include "includes.h" +#include "ldb_includes.h" + +#include "lib/events/events.h" +#include "libcli/ldap/ldap.h" +#include "libcli/ldap/ldap_client.h" +#include "auth/auth.h" +#include "auth/credentials/credentials.h" +#include "param/param.h" + +struct ildb_private { + struct ldap_connection *ldap; + struct ldb_module *module; +}; + +struct ildb_context { + struct ildb_private *ildb; + struct ldb_handle *handle; + struct ldap_request *req; + void *context; + int (*callback)(struct ldb_context *, void *, struct ldb_reply *); +}; + +/* + convert a ldb_message structure to a list of ldap_mod structures + ready for ildap_add() or ildap_modify() +*/ +static struct ldap_mod **ildb_msg_to_mods(void *mem_ctx, int *num_mods, + const struct ldb_message *msg, + int use_flags) +{ + struct ldap_mod **mods; + unsigned int i; + int n = 0; + + /* allocate maximum number of elements needed */ + mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1); + if (!mods) { + errno = ENOMEM; + return NULL; + } + mods[0] = NULL; + + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_message_element *el = &msg->elements[i]; + + mods[n] = talloc(mods, struct ldap_mod); + if (!mods[n]) { + goto failed; + } + mods[n + 1] = NULL; + mods[n]->type = 0; + mods[n]->attrib = *el; + if (use_flags) { + switch (el->flags & LDB_FLAG_MOD_MASK) { + case LDB_FLAG_MOD_ADD: + mods[n]->type = LDAP_MODIFY_ADD; + break; + case LDB_FLAG_MOD_DELETE: + mods[n]->type = LDAP_MODIFY_DELETE; + break; + case LDB_FLAG_MOD_REPLACE: + mods[n]->type = LDAP_MODIFY_REPLACE; + break; + } + } + n++; + } + + *num_mods = n; + return mods; + +failed: + talloc_free(mods); + return NULL; +} + + +/* + map an ildap NTSTATUS to a ldb error code +*/ +static int ildb_map_error(struct ildb_private *ildb, NTSTATUS status) +{ + TALLOC_CTX *mem_ctx = talloc_new(ildb); + if (NT_STATUS_IS_OK(status)) { + return LDB_SUCCESS; + } + if (!mem_ctx) { + ldb_oom(ildb->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ldb_set_errstring(ildb->module->ldb, + ldap_errstr(ildb->ldap, mem_ctx, status)); + talloc_free(mem_ctx); + if (NT_STATUS_IS_LDAP(status)) { + return NT_STATUS_LDAP_CODE(status); + } + return LDB_ERR_OPERATIONS_ERROR; +} + +static void ildb_request_timeout(struct event_context *ev, + struct timed_event *te, + struct timeval t, void *private_data) +{ + struct ildb_context *ac; + struct ldb_handle *handle; + + ac = talloc_get_type(private_data, struct ildb_context); + handle = ac->handle; + + ac = talloc_get_type(private_data, struct ildb_context); + + if (ac->req->state == LDAP_REQUEST_PENDING) { + DLIST_REMOVE(ac->req->conn->pending, ac->req); + } + + handle->status = LDB_ERR_TIME_LIMIT_EXCEEDED; + + return; +} + +static void ildb_callback(struct ldap_request *req) +{ + struct ildb_context *ac; + struct ldb_handle *handle; + struct ildb_private *ildb; + NTSTATUS status; + int i; + + ac = talloc_get_type(req->async.private_data, struct ildb_context); + ildb = ac->ildb; + handle = ac->handle; + handle->status = LDB_SUCCESS; + + if (!NT_STATUS_IS_OK(req->status)) { + handle->status = ildb_map_error(ildb, req->status); + return; + } + + if (req->num_replies < 1) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return; + } + + switch (req->type) { + + case LDAP_TAG_ModifyRequest: + if (req->replies[0]->type != LDAP_TAG_ModifyResponse) { + handle->status = LDB_ERR_PROTOCOL_ERROR; + return; + } + status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult); + handle->status = ildb_map_error(ildb, status); + if (ac->callback && handle->status == LDB_SUCCESS) { + /* FIXME: build a corresponding ares to pass on */ + handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL); + } + handle->state = LDB_ASYNC_DONE; + break; + + case LDAP_TAG_AddRequest: + if (req->replies[0]->type != LDAP_TAG_AddResponse) { + handle->status = LDB_ERR_PROTOCOL_ERROR; + return; + } + status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult); + handle->status = ildb_map_error(ildb, status); + if (ac->callback && handle->status == LDB_SUCCESS) { + /* FIXME: build a corresponding ares to pass on */ + handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL); + } + handle->state = LDB_ASYNC_DONE; + break; + + case LDAP_TAG_DelRequest: + if (req->replies[0]->type != LDAP_TAG_DelResponse) { + handle->status = LDB_ERR_PROTOCOL_ERROR; + return; + } + status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult); + handle->status = ildb_map_error(ildb, status); + if (ac->callback && handle->status == LDB_SUCCESS) { + /* FIXME: build a corresponding ares to pass on */ + handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL); + } + handle->state = LDB_ASYNC_DONE; + break; + + case LDAP_TAG_ModifyDNRequest: + if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) { + handle->status = LDB_ERR_PROTOCOL_ERROR; + return; + } + status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult); + handle->status = ildb_map_error(ildb, status); + if (ac->callback && handle->status == LDB_SUCCESS) { + /* FIXME: build a corresponding ares to pass on */ + handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL); + } + handle->state = LDB_ASYNC_DONE; + break; + + case LDAP_TAG_SearchRequest: + /* loop over all messages */ + for (i = 0; i < req->num_replies; i++) { + struct ldap_SearchResEntry *search; + struct ldb_reply *ares = NULL; + struct ldap_message *msg; + int ret; + + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return; + } + + msg = req->replies[i]; + switch (msg->type) { + + case LDAP_TAG_SearchResultDone: + + status = ldap_check_response(req->conn, &msg->r.GeneralResult); + if (!NT_STATUS_IS_OK(status)) { + handle->status = ildb_map_error(ildb, status); + return; + } + + ares->controls = talloc_move(ares, &msg->controls); + if (msg->r.SearchResultDone.resultcode) { + if (msg->r.SearchResultDone.errormessage) { + ldb_set_errstring(ac->ildb->module->ldb, msg->r.SearchResultDone.errormessage); + } + } + + handle->status = msg->r.SearchResultDone.resultcode; + handle->state = LDB_ASYNC_DONE; + ares->type = LDB_REPLY_DONE; + break; + + case LDAP_TAG_SearchResultEntry: + + + ares->message = ldb_msg_new(ares); + if (!ares->message) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return; + } + + search = &(msg->r.SearchResultEntry); + + ares->message->dn = ldb_dn_new(ares->message, ac->ildb->module->ldb, search->dn); + if ( ! ldb_dn_validate(ares->message->dn)) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return; + } + ares->message->num_elements = search->num_attributes; + ares->message->elements = talloc_move(ares->message, + &search->attributes); + + handle->status = LDB_SUCCESS; + handle->state = LDB_ASYNC_PENDING; + ares->type = LDB_REPLY_ENTRY; + break; + + case LDAP_TAG_SearchResultReference: + + ares->referral = talloc_strdup(ares, msg->r.SearchResultReference.referral); + + handle->status = LDB_SUCCESS; + handle->state = LDB_ASYNC_PENDING; + ares->type = LDB_REPLY_REFERRAL; + break; + + default: + /* TAG not handled, fail ! */ + handle->status = LDB_ERR_PROTOCOL_ERROR; + return; + } + + ret = ac->callback(ac->ildb->module->ldb, ac->context, ares); + if (ret) { + handle->status = ret; + } + } + + talloc_free(req->replies); + req->replies = NULL; + req->num_replies = 0; + + break; + + default: + handle->status = LDB_ERR_PROTOCOL_ERROR; + return; + } +} + +static struct ildb_context *init_ildb_handle(struct ildb_private *ildb, + struct ldb_request *req) +{ + struct ildb_context *ildb_ac; + struct ldb_handle *h; + + h = talloc_zero(req, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(ildb->module->ldb, "Out of Memory"); + return NULL; + } + + h->module = ildb->module; + + ildb_ac = talloc(h, struct ildb_context); + if (ildb_ac == NULL) { + ldb_set_errstring(ildb->module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = ildb_ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ildb_ac->ildb = ildb; + ildb_ac->handle = h; + ildb_ac->context = req->context; + ildb_ac->callback = req->callback; + + req->handle = h; + return ildb_ac; +} + +static int ildb_request_send(struct ildb_private *ildb, struct ldap_message *msg, struct ldb_request *r) +{ + struct ildb_context *ildb_ac = init_ildb_handle(ildb, r); + struct ldap_request *req; + + if (!ildb_ac) { + return LDB_ERR_OPERATIONS_ERROR; + } + + req = ldap_request_send(ildb->ldap, msg); + if (req == NULL) { + ldb_set_errstring(ildb->module->ldb, "async send request failed"); + return LDB_ERR_OPERATIONS_ERROR; + } + ildb_ac->req = talloc_steal(ildb_ac, req); + + if (!req->conn) { + ldb_set_errstring(ildb->module->ldb, "connection to remote LDAP server dropped?"); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(req->time_event); + req->time_event = NULL; + if (r->timeout) { + req->time_event = event_add_timed(req->conn->event.event_ctx, ildb_ac, + timeval_current_ofs(r->timeout, 0), + ildb_request_timeout, ildb_ac); + } + + req->async.fn = ildb_callback; + req->async.private_data = ildb_ac; + + return LDB_SUCCESS; +} + +static int ildb_request_noop(struct ildb_private *ildb, struct ldb_request *req) +{ + struct ildb_context *ildb_ac = init_ildb_handle(ildb, req); + int ret = LDB_SUCCESS; + + if (!ildb_ac) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (ildb_ac->callback) { + ret = ildb_ac->callback(ildb->module->ldb, ildb_ac->context, NULL); + } + ildb_ac->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* + search for matching records using an asynchronous function + */ +static int ildb_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldap_message *msg; + int n; + + req->handle = NULL; + + if (!req->callback || !req->context) { + ldb_set_errstring(module->ldb, "Async interface called with NULL callback function or NULL context"); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (req->op.search.tree == NULL) { + ldb_set_errstring(module->ldb, "Invalid expression parse tree"); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg = new_ldap_message(req); + if (msg == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->type = LDAP_TAG_SearchRequest; + + if (req->op.search.base == NULL) { + msg->r.SearchRequest.basedn = talloc_strdup(msg, ""); + } else { + msg->r.SearchRequest.basedn = ldb_dn_alloc_linearized(msg, req->op.search.base); + } + if (msg->r.SearchRequest.basedn == NULL) { + ldb_set_errstring(module->ldb, "Unable to determine baseDN"); + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (req->op.search.scope == LDB_SCOPE_DEFAULT) { + msg->r.SearchRequest.scope = LDB_SCOPE_SUBTREE; + } else { + msg->r.SearchRequest.scope = req->op.search.scope; + } + + msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER; + msg->r.SearchRequest.timelimit = 0; + msg->r.SearchRequest.sizelimit = 0; + msg->r.SearchRequest.attributesonly = 0; + msg->r.SearchRequest.tree = discard_const(req->op.search.tree); + + for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ; + msg->r.SearchRequest.num_attributes = n; + msg->r.SearchRequest.attributes = discard_const(req->op.search.attrs); + msg->controls = req->controls; + + return ildb_request_send(ildb, msg, req); +} + +/* + add a record +*/ +static int ildb_add(struct ldb_module *module, struct ldb_request *req) +{ + struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldap_message *msg; + struct ldap_mod **mods; + int i,n; + + req->handle = NULL; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(req->op.add.message->dn)) { + return ildb_request_noop(ildb, req); + } + + msg = new_ldap_message(req); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->type = LDAP_TAG_AddRequest; + + msg->r.AddRequest.dn = ldb_dn_alloc_linearized(msg, req->op.add.message->dn); + if (msg->r.AddRequest.dn == NULL) { + talloc_free(msg); + return LDB_ERR_INVALID_DN_SYNTAX; + } + + mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0); + if (mods == NULL) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->r.AddRequest.num_attributes = n; + msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n); + if (msg->r.AddRequest.attributes == NULL) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i = 0; i < n; i++) { + msg->r.AddRequest.attributes[i] = mods[i]->attrib; + } + + return ildb_request_send(ildb, msg, req); +} + +/* + modify a record +*/ +static int ildb_modify(struct ldb_module *module, struct ldb_request *req) +{ + struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldap_message *msg; + struct ldap_mod **mods; + int i,n; + + req->handle = NULL; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(req->op.mod.message->dn)) { + return ildb_request_noop(ildb, req); + } + + msg = new_ldap_message(req); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->type = LDAP_TAG_ModifyRequest; + + msg->r.ModifyRequest.dn = ldb_dn_alloc_linearized(msg, req->op.mod.message->dn); + if (msg->r.ModifyRequest.dn == NULL) { + talloc_free(msg); + return LDB_ERR_INVALID_DN_SYNTAX; + } + + mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1); + if (mods == NULL) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->r.ModifyRequest.num_mods = n; + msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n); + if (msg->r.ModifyRequest.mods == NULL) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i = 0; i < n; i++) { + msg->r.ModifyRequest.mods[i] = *mods[i]; + } + + return ildb_request_send(ildb, msg, req); +} + +/* + delete a record +*/ +static int ildb_delete(struct ldb_module *module, struct ldb_request *req) +{ + struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldap_message *msg; + + req->handle = NULL; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(req->op.del.dn)) { + return ildb_request_noop(ildb, req); + } + + msg = new_ldap_message(req); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->type = LDAP_TAG_DelRequest; + + msg->r.DelRequest.dn = ldb_dn_alloc_linearized(msg, req->op.del.dn); + if (msg->r.DelRequest.dn == NULL) { + talloc_free(msg); + return LDB_ERR_INVALID_DN_SYNTAX; + } + + return ildb_request_send(ildb, msg, req); +} + +/* + rename a record +*/ +static int ildb_rename(struct ldb_module *module, struct ldb_request *req) +{ + struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldap_message *msg; + + req->handle = NULL; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) { + return ildb_request_noop(ildb, req); + } + + msg = new_ldap_message(req); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->type = LDAP_TAG_ModifyDNRequest; + msg->r.ModifyDNRequest.dn = ldb_dn_alloc_linearized(msg, req->op.rename.olddn); + if (msg->r.ModifyDNRequest.dn == NULL) { + talloc_free(msg); + return LDB_ERR_INVALID_DN_SYNTAX; + } + + msg->r.ModifyDNRequest.newrdn = + talloc_asprintf(msg, "%s=%s", + ldb_dn_get_rdn_name(req->op.rename.newdn), + ldb_dn_escape_value(msg, *ldb_dn_get_rdn_val(req->op.rename.newdn))); + if (msg->r.ModifyDNRequest.newrdn == NULL) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->r.ModifyDNRequest.newsuperior = + ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn)); + if (msg->r.ModifyDNRequest.newsuperior == NULL) { + talloc_free(msg); + return LDB_ERR_INVALID_DN_SYNTAX; + } + + msg->r.ModifyDNRequest.deleteolddn = true; + + return ildb_request_send(ildb, msg, req); +} + +static int ildb_start_trans(struct ldb_module *module) +{ + /* TODO implement a local locking mechanism here */ + + return LDB_SUCCESS; +} + +static int ildb_end_trans(struct ldb_module *module) +{ + /* TODO implement a local transaction mechanism here */ + + return LDB_SUCCESS; +} + +static int ildb_del_trans(struct ldb_module *module) +{ + /* TODO implement a local locking mechanism here */ + + return LDB_SUCCESS; +} + +static int ildb_request(struct ldb_module *module, struct ldb_request *req) +{ + return LDB_ERR_OPERATIONS_ERROR; +} + +static int ildb_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context); + + if (handle->state == LDB_ASYNC_DONE) { + return handle->status; + } + + if (!ac) { + return LDB_ERR_OPERATIONS_ERROR; + } + + handle->state = LDB_ASYNC_INIT; + + switch(type) { + case LDB_WAIT_NONE: + if (event_loop_once(ac->req->conn->event.event_ctx) != 0) { + return LDB_ERR_OTHER; + } + break; + case LDB_WAIT_ALL: + while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) { + if (event_loop_once(ac->req->conn->event.event_ctx) != 0) { + return LDB_ERR_OTHER; + } + } + break; + default: + return LDB_ERR_OPERATIONS_ERROR; + } + + return handle->status; +} + +static const struct ldb_module_ops ildb_ops = { + .name = "ldap", + .search = ildb_search, + .add = ildb_add, + .modify = ildb_modify, + .del = ildb_delete, + .rename = ildb_rename, + .request = ildb_request, + .start_transaction = ildb_start_trans, + .end_transaction = ildb_end_trans, + .del_transaction = ildb_del_trans, + .wait = ildb_wait +}; + +/* + connect to the database +*/ +static int ildb_connect(struct ldb_context *ldb, const char *url, + unsigned int flags, const char *options[], + struct ldb_module **_module) +{ + struct ldb_module *module; + struct ildb_private *ildb; + NTSTATUS status; + struct cli_credentials *creds; + struct event_context *event_ctx; + + module = talloc(ldb, struct ldb_module); + if (!module) { + ldb_oom(ldb); + return -1; + } + talloc_set_name_const(module, "ldb_ildap backend"); + module->ldb = ldb; + module->prev = module->next = NULL; + module->private_data = NULL; + module->ops = &ildb_ops; + + ildb = talloc(module, struct ildb_private); + if (!ildb) { + ldb_oom(ldb); + goto failed; + } + module->private_data = ildb; + ildb->module = module; + + event_ctx = ldb_get_event_context(ldb); + + ildb->ldap = ldap4_new_connection(ildb, ldb_get_opaque(ldb, "loadparm"), + event_ctx); + if (!ildb->ldap) { + ldb_oom(ldb); + goto failed; + } + + if (flags & LDB_FLG_RECONNECT) { + ldap_set_reconn_params(ildb->ldap, 10); + } + + status = ldap_connect(ildb->ldap, url); + if (!NT_STATUS_IS_OK(status)) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s\n", + url, ldap_errstr(ildb->ldap, module, status)); + goto failed; + } + + /* caller can optionally setup credentials using the opaque token 'credentials' */ + creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials); + if (creds == NULL) { + struct auth_session_info *session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info); + if (session_info) { + creds = session_info->credentials; + } + } + + if (creds != NULL && cli_credentials_authentication_requested(creds)) { + const char *bind_dn = cli_credentials_get_bind_dn(creds); + if (bind_dn) { + const char *password = cli_credentials_get_password(creds); + status = ldap_bind_simple(ildb->ldap, bind_dn, password); + if (!NT_STATUS_IS_OK(status)) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n", + ldap_errstr(ildb->ldap, module, status)); + goto failed; + } + } else { + status = ldap_bind_sasl(ildb->ldap, creds, ldb_get_opaque(ldb, "loadparm")); + if (!NT_STATUS_IS_OK(status)) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n", + ldap_errstr(ildb->ldap, module, status)); + goto failed; + } + } + } + + *_module = module; + return 0; + +failed: + talloc_free(module); + return -1; +} + +_PUBLIC_ const struct ldb_backend_ops ldb_ldap_backend_ops = { + .name = "ldap", + .connect_fn = ildb_connect +}; + +_PUBLIC_ const struct ldb_backend_ops ldb_ldapi_backend_ops = { + .name = "ldapi", + .connect_fn = ildb_connect +}; + +_PUBLIC_ const struct ldb_backend_ops ldb_ldaps_backend_ops = { + .name = "ldaps", + .connect_fn = ildb_connect +}; + diff --git a/ldb/ldb_ldap/ldb_ldap.c b/ldb/ldb_ldap/ldb_ldap.c new file mode 100644 index 000000000..a4534c549 --- /dev/null +++ b/ldb/ldb_ldap/ldb_ldap.c @@ -0,0 +1,842 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Simo Sorce 2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb_ldap + * + * Component: ldb ldap backend + * + * Description: core files for LDAP backend + * + * Author: Andrew Tridgell + * + * Modifications: + * + * - description: make the module use asyncronous calls + * date: Feb 2006 + * author: Simo Sorce + */ + +#include "ldb_includes.h" + +#define LDAP_DEPRECATED 1 +#include + +struct lldb_private { + LDAP *ldap; + struct ldb_module *module; +}; + +struct lldb_context { + struct lldb_private *lldb; + struct ldb_handle *handle; + int msgid; + int timeout; + time_t starttime; + void *context; + int (*callback)(struct ldb_context *, void *, struct ldb_reply *); +}; + +static int lldb_ldap_to_ldb(int err) { + /* Ldap errors and ldb errors are defined to the same values */ + return err; +} + +static struct lldb_context *init_lldb_handle(struct lldb_private *lldb, struct ldb_request *req) +{ + struct lldb_context *ac; + struct ldb_handle *h; + + h = talloc_zero(req, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(lldb->module->ldb, "Out of Memory"); + return NULL; + } + + h->module = lldb->module; + + ac = talloc(h, struct lldb_context); + if (ac == NULL) { + ldb_set_errstring(lldb->module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->lldb = lldb; + ac->handle = h; + ac->context = req->context; + ac->callback = req->callback; + ac->timeout = req->timeout; + ac->starttime = req->starttime; + ac->msgid = 0; + + req->handle = h; + return ac; +} +/* + convert a ldb_message structure to a list of LDAPMod structures + ready for ldap_add() or ldap_modify() +*/ +static LDAPMod **lldb_msg_to_mods(void *mem_ctx, const struct ldb_message *msg, int use_flags) +{ + LDAPMod **mods; + unsigned int i, j; + int num_mods = 0; + + /* allocate maximum number of elements needed */ + mods = talloc_array(mem_ctx, LDAPMod *, msg->num_elements+1); + if (!mods) { + errno = ENOMEM; + return NULL; + } + mods[0] = NULL; + + for (i=0;inum_elements;i++) { + const struct ldb_message_element *el = &msg->elements[i]; + + mods[num_mods] = talloc(mods, LDAPMod); + if (!mods[num_mods]) { + goto failed; + } + mods[num_mods+1] = NULL; + mods[num_mods]->mod_op = LDAP_MOD_BVALUES; + if (use_flags) { + switch (el->flags & LDB_FLAG_MOD_MASK) { + case LDB_FLAG_MOD_ADD: + mods[num_mods]->mod_op |= LDAP_MOD_ADD; + break; + case LDB_FLAG_MOD_DELETE: + mods[num_mods]->mod_op |= LDAP_MOD_DELETE; + break; + case LDB_FLAG_MOD_REPLACE: + mods[num_mods]->mod_op |= LDAP_MOD_REPLACE; + break; + } + } + mods[num_mods]->mod_type = discard_const_p(char, el->name); + mods[num_mods]->mod_vals.modv_bvals = talloc_array(mods[num_mods], + struct berval *, + 1+el->num_values); + if (!mods[num_mods]->mod_vals.modv_bvals) { + goto failed; + } + + for (j=0;jnum_values;j++) { + mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals, + struct berval); + if (!mods[num_mods]->mod_vals.modv_bvals[j]) { + goto failed; + } + mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data; + mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length; + } + mods[num_mods]->mod_vals.modv_bvals[j] = NULL; + num_mods++; + } + + return mods; + +failed: + talloc_free(mods); + return NULL; +} + +/* + add a single set of ldap message values to a ldb_message +*/ +static int lldb_add_msg_attr(struct ldb_context *ldb, + struct ldb_message *msg, + const char *attr, struct berval **bval) +{ + int count, i; + struct ldb_message_element *el; + + count = ldap_count_values_len(bval); + + if (count <= 0) { + return -1; + } + + el = talloc_realloc(msg, msg->elements, struct ldb_message_element, + msg->num_elements + 1); + if (!el) { + errno = ENOMEM; + return -1; + } + + msg->elements = el; + + el = &msg->elements[msg->num_elements]; + + el->name = talloc_strdup(msg->elements, attr); + if (!el->name) { + errno = ENOMEM; + return -1; + } + el->flags = 0; + + el->num_values = 0; + el->values = talloc_array(msg->elements, struct ldb_val, count); + if (!el->values) { + errno = ENOMEM; + return -1; + } + + for (i=0;ivalues[i].data = talloc_size(el->values, bval[i]->bv_len+1); + if (!el->values[i].data) { + errno = ENOMEM; + return -1; + } + memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len); + el->values[i].data[bval[i]->bv_len] = 0; + el->values[i].length = bval[i]->bv_len; + el->num_values++; + } + + msg->num_elements++; + + return 0; +} + +/* + search for matching records +*/ +static int lldb_search(struct ldb_module *module, struct ldb_request *req) +{ + struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); + struct lldb_context *lldb_ac; + struct timeval tv; + int ldap_scope; + char *search_base; + char *expression; + int ret; + + if (!req->callback || !req->context) { + ldb_set_errstring(module->ldb, "Async interface called with NULL callback function or NULL context"); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (req->op.search.tree == NULL) { + ldb_set_errstring(module->ldb, "Invalid expression parse tree"); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!\n"); + } + + lldb_ac = init_lldb_handle(lldb, req); + if (lldb_ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + search_base = ldb_dn_alloc_linearized(lldb_ac, req->op.search.base); + if (req->op.search.base == NULL) { + search_base = talloc_strdup(lldb_ac, ""); + } + if (search_base == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + expression = ldb_filter_from_tree(lldb_ac, req->op.search.tree); + if (expression == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + switch (req->op.search.scope) { + case LDB_SCOPE_BASE: + ldap_scope = LDAP_SCOPE_BASE; + break; + case LDB_SCOPE_ONELEVEL: + ldap_scope = LDAP_SCOPE_ONELEVEL; + break; + default: + ldap_scope = LDAP_SCOPE_SUBTREE; + break; + } + + tv.tv_sec = req->timeout; + tv.tv_usec = 0; + + ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope, + expression, + discard_const_p(char *, req->op.search.attrs), + 0, + NULL, + NULL, + &tv, + LDAP_NO_LIMIT, + &lldb_ac->msgid); + + if (ret != LDAP_SUCCESS) { + ldb_set_errstring(module->ldb, ldap_err2string(ret)); + } + + return lldb_ldap_to_ldb(ret); +} + +/* + add a record +*/ +static int lldb_add(struct ldb_module *module, struct ldb_request *req) +{ + struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); + struct lldb_context *lldb_ac; + LDAPMod **mods; + char *dn; + int ret; + + /* ltdb specials should not reach this point */ + if (ldb_dn_is_special(req->op.add.message->dn)) { + return LDB_ERR_INVALID_DN_SYNTAX; + } + + lldb_ac = init_lldb_handle(lldb, req); + if (lldb_ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + mods = lldb_msg_to_mods(lldb_ac, req->op.add.message, 0); + if (mods == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + dn = ldb_dn_alloc_linearized(lldb_ac, req->op.add.message->dn); + if (dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldap_add_ext(lldb->ldap, dn, mods, + NULL, + NULL, + &lldb_ac->msgid); + + if (ret != LDAP_SUCCESS) { + ldb_set_errstring(module->ldb, ldap_err2string(ret)); + } + + return lldb_ldap_to_ldb(ret); +} + +/* + modify a record +*/ +static int lldb_modify(struct ldb_module *module, struct ldb_request *req) +{ + struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); + struct lldb_context *lldb_ac; + LDAPMod **mods; + char *dn; + int ret; + + /* ltdb specials should not reach this point */ + if (ldb_dn_is_special(req->op.mod.message->dn)) { + return LDB_ERR_INVALID_DN_SYNTAX; + } + + lldb_ac = init_lldb_handle(lldb, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1); + if (mods == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + dn = ldb_dn_alloc_linearized(lldb_ac, req->op.mod.message->dn); + if (dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldap_modify_ext(lldb->ldap, dn, mods, + NULL, + NULL, + &lldb_ac->msgid); + + if (ret != LDAP_SUCCESS) { + ldb_set_errstring(module->ldb, ldap_err2string(ret)); + } + + return lldb_ldap_to_ldb(ret); +} + +/* + delete a record +*/ +static int lldb_delete(struct ldb_module *module, struct ldb_request *req) +{ + struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); + struct lldb_context *lldb_ac; + char *dnstr; + int ret; + + /* ltdb specials should not reach this point */ + if (ldb_dn_is_special(req->op.del.dn)) { + return LDB_ERR_INVALID_DN_SYNTAX; + } + + lldb_ac = init_lldb_handle(lldb, req); + if (lldb_ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + dnstr = ldb_dn_alloc_linearized(lldb_ac, req->op.del.dn); + + ret = ldap_delete_ext(lldb->ldap, dnstr, + NULL, + NULL, + &lldb_ac->msgid); + + if (ret != LDAP_SUCCESS) { + ldb_set_errstring(module->ldb, ldap_err2string(ret)); + } + + return lldb_ldap_to_ldb(ret); +} + +/* + rename a record +*/ +static int lldb_rename(struct ldb_module *module, struct ldb_request *req) +{ + struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); + struct lldb_context *lldb_ac; + char *old_dn; + char *newrdn; + char *parentdn; + int ret; + + /* ltdb specials should not reach this point */ + if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) { + return LDB_ERR_INVALID_DN_SYNTAX; + } + + lldb_ac = init_lldb_handle(lldb, req); + if (lldb_ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + old_dn = ldb_dn_alloc_linearized(lldb_ac, req->op.rename.olddn); + if (old_dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + newrdn = talloc_asprintf(lldb_ac, "%s=%s", + ldb_dn_get_rdn_name(req->op.rename.newdn), + ldb_dn_escape_value(lldb, *(ldb_dn_get_rdn_val(req->op.rename.newdn)))); + if (!newrdn) { + return LDB_ERR_OPERATIONS_ERROR; + } + + parentdn = ldb_dn_alloc_linearized(lldb_ac, ldb_dn_get_parent(lldb_ac, req->op.rename.newdn)); + if (!parentdn) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldap_rename(lldb->ldap, old_dn, newrdn, parentdn, + 1, NULL, NULL, + &lldb_ac->msgid); + + if (ret != LDAP_SUCCESS) { + ldb_set_errstring(module->ldb, ldap_err2string(ret)); + } + + return lldb_ldap_to_ldb(ret); +} + +static int lldb_parse_result(struct lldb_context *ac, LDAPMessage *result) +{ + struct ldb_handle *handle = ac->handle; + struct lldb_private *lldb = ac->lldb; + struct ldb_reply *ares = NULL; + LDAPMessage *msg; + int type; + char *matcheddnp = NULL; + char *errmsgp = NULL; + char **referralsp = NULL; + LDAPControl **serverctrlsp = NULL; + int ret = LDB_SUCCESS; + + type = ldap_msgtype(result); + + handle->status = 0; + + switch (type) { + + case LDAP_RES_SEARCH_ENTRY: + msg = ldap_first_entry(lldb->ldap, result); + if (msg != NULL) { + BerElement *berptr = NULL; + char *attr, *dn; + + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + + ares->message = ldb_msg_new(ares); + if (!ares->message) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + + dn = ldap_get_dn(lldb->ldap, msg); + if (!dn) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + ares->message->dn = ldb_dn_new(ares->message, ac->lldb->module->ldb, dn); + if ( ! ldb_dn_validate(ares->message->dn)) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + ldap_memfree(dn); + + ares->message->num_elements = 0; + ares->message->elements = NULL; + + /* loop over all attributes */ + for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr); + attr; + attr=ldap_next_attribute(lldb->ldap, msg, berptr)) { + struct berval **bval; + bval = ldap_get_values_len(lldb->ldap, msg, attr); + + if (bval) { + lldb_add_msg_attr(ac->lldb->module->ldb, ares->message, attr, bval); + ldap_value_free_len(bval); + } + } + if (berptr) ber_free(berptr, 0); + + + ares->type = LDB_REPLY_ENTRY; + ret = ac->callback(ac->lldb->module->ldb, ac->context, ares); + } else { + handle->status = LDB_ERR_PROTOCOL_ERROR; + handle->state = LDB_ASYNC_DONE; + } + break; + + case LDAP_RES_SEARCH_REFERENCE: + if (ldap_parse_result(lldb->ldap, result, &handle->status, + &matcheddnp, &errmsgp, + &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + if (referralsp == NULL) { + handle->status = LDB_ERR_PROTOCOL_ERROR; + goto error; + } + + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + + ares->referral = talloc_strdup(ares, *referralsp); + ares->type = LDB_REPLY_REFERRAL; + ret = ac->callback(ac->lldb->module->ldb, ac->context, ares); + + break; + + case LDAP_RES_SEARCH_RESULT: + if (ldap_parse_result(lldb->ldap, result, &handle->status, + &matcheddnp, &errmsgp, + &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + + if (serverctrlsp != NULL) { + /* FIXME: transform the LDAPControl list into an ldb_control one */ + ares->controls = NULL; + } + + ares->type = LDB_REPLY_DONE; + handle->state = LDB_ASYNC_DONE; + ret = ac->callback(ac->lldb->module->ldb, ac->context, ares); + + break; + + case LDAP_RES_MODIFY: + case LDAP_RES_ADD: + case LDAP_RES_DELETE: + case LDAP_RES_MODDN: + if (ldap_parse_result(lldb->ldap, result, &handle->status, + &matcheddnp, &errmsgp, + &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + goto error; + } + if (ac->callback && handle->status == LDB_SUCCESS) { + ares = NULL; /* FIXME: build a corresponding ares to pass on */ + ret = ac->callback(ac->lldb->module->ldb, ac->context, ares); + } + handle->state = LDB_ASYNC_DONE; + break; + + default: + ret = LDB_ERR_PROTOCOL_ERROR; + goto error; + } + + if (matcheddnp) ldap_memfree(matcheddnp); + if (errmsgp && *errmsgp) { + ldb_set_errstring(ac->lldb->module->ldb, errmsgp); + } else if (handle->status) { + ldb_set_errstring(ac->lldb->module->ldb, ldap_err2string(handle->status)); + } + if (errmsgp) { + ldap_memfree(errmsgp); + } + if (referralsp) ldap_value_free(referralsp); + if (serverctrlsp) ldap_controls_free(serverctrlsp); + + ldap_msgfree(result); + return lldb_ldap_to_ldb(handle->status); + +error: + handle->state = LDB_ASYNC_DONE; + ldap_msgfree(result); + return ret; +} + +static int lldb_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + struct lldb_context *ac = talloc_get_type(handle->private_data, struct lldb_context); + struct lldb_private *lldb = ac->lldb; + struct timeval timeout; + LDAPMessage *result; + int ret, lret; + + if (handle->state == LDB_ASYNC_DONE) { + return handle->status; + } + + if (!ac || !ac->msgid) { + return LDB_ERR_OPERATIONS_ERROR; + } + + handle->state = LDB_ASYNC_PENDING; + handle->status = LDB_SUCCESS; + + switch(type) { + case LDB_WAIT_NONE: + + if ((ac->timeout != -1) && + ((ac->starttime + ac->timeout) > time(NULL))) { + return LDB_ERR_TIME_LIMIT_EXCEEDED; + } + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result); + if (lret == -1) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (lret == 0) { + ret = LDB_SUCCESS; + goto done; + } + + return lldb_parse_result(ac, result); + + case LDB_WAIT_ALL: + timeout.tv_usec = 0; + ret = LDB_ERR_OPERATIONS_ERROR; + + while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) { + + if (ac->timeout == -1) { + lret = ldap_result(lldb->ldap, ac->msgid, 0, NULL, &result); + } else { + timeout.tv_sec = ac->timeout - (time(NULL) - ac->starttime); + if (timeout.tv_sec <= 0) + return LDB_ERR_TIME_LIMIT_EXCEEDED; + lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result); + } + if (lret == -1) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (lret == 0) { + return LDB_ERR_TIME_LIMIT_EXCEEDED; + } + + ret = lldb_parse_result(ac, result); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + break; + + default: + handle->state = LDB_ASYNC_DONE; + ret = LDB_ERR_OPERATIONS_ERROR; + } + +done: + return ret; +} + +static int lldb_start_trans(struct ldb_module *module) +{ + /* TODO implement a local transaction mechanism here */ + + return LDB_SUCCESS; +} + +static int lldb_end_trans(struct ldb_module *module) +{ + /* TODO implement a local transaction mechanism here */ + + return LDB_SUCCESS; +} + +static int lldb_del_trans(struct ldb_module *module) +{ + /* TODO implement a local transaction mechanism here */ + + return LDB_SUCCESS; +} + +static int lldb_request(struct ldb_module *module, struct ldb_request *req) +{ + return LDB_ERR_OPERATIONS_ERROR; +} + +static const struct ldb_module_ops lldb_ops = { + .name = "ldap", + .search = lldb_search, + .add = lldb_add, + .modify = lldb_modify, + .del = lldb_delete, + .rename = lldb_rename, + .request = lldb_request, + .start_transaction = lldb_start_trans, + .end_transaction = lldb_end_trans, + .del_transaction = lldb_del_trans, + .wait = lldb_wait +}; + + +static int lldb_destructor(struct lldb_private *lldb) +{ + ldap_unbind(lldb->ldap); + return 0; +} + +/* + connect to the database +*/ +static int lldb_connect(struct ldb_context *ldb, + const char *url, + unsigned int flags, + const char *options[], + struct ldb_module **_module) +{ + struct ldb_module *module; + struct lldb_private *lldb; + int version = 3; + int ret; + + module = talloc(ldb, struct ldb_module); + if (module == NULL) { + ldb_oom(ldb); + talloc_free(lldb); + return -1; + } + talloc_set_name_const(module, "ldb_ldap backend"); + module->ldb = ldb; + module->prev = module->next = NULL; + module->private_data = NULL; + module->ops = &lldb_ops; + + lldb = talloc(module, struct lldb_private); + if (!lldb) { + ldb_oom(ldb); + goto failed; + } + module->private_data = lldb; + lldb->module = module; + lldb->ldap = NULL; + + ret = ldap_initialize(&lldb->ldap, url); + if (ret != LDAP_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_initialize failed for URL '%s' - %s\n", + url, ldap_err2string(ret)); + goto failed; + } + + talloc_set_destructor(lldb, lldb_destructor); + + ret = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version); + if (ret != LDAP_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_set_option failed - %s\n", + ldap_err2string(ret)); + goto failed; + } + + *_module = module; + return 0; + +failed: + talloc_free(module); + return -1; +} + +const struct ldb_backend_ops ldb_ldap_backend_ops = { + .name = "ldap", + .connect_fn = lldb_connect +}; + +const struct ldb_backend_ops ldb_ldapi_backend_ops = { + .name = "ldapi", + .connect_fn = lldb_connect +}; + +const struct ldb_backend_ops ldb_ldaps_backend_ops = { + .name = "ldaps", + .connect_fn = lldb_connect +}; diff --git a/ldb/ldb_map/ldb_map.c b/ldb/ldb_map/ldb_map.c new file mode 100644 index 000000000..b3f639dc6 --- /dev/null +++ b/ldb/ldb_map/ldb_map.c @@ -0,0 +1,1380 @@ +/* + ldb database mapping module + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Martin Kuehl 2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . + +*/ + +/* + * Name: ldb + * + * Component: ldb ldb_map module + * + * Description: Map portions of data into a different format on a + * remote partition. + * + * Author: Jelmer Vernooij, Martin Kuehl + */ + +#include "ldb_includes.h" + +#include "ldb_map.h" +#include "ldb_map_private.h" + +#ifndef _PUBLIC_ +#define _PUBLIC_ +#endif + +/* Description of the provided ldb requests: + - special attribute 'isMapped' + + - search: + - if parse tree can be split + - search remote records w/ remote attrs and parse tree + - otherwise + - enumerate all remote records + - for each remote result + - map remote result to local message + - search local result + - is present + - merge local into remote result + - run callback on merged result + - otherwise + - run callback on remote result + + - add: + - split message into local and remote part + - if local message is not empty + - add isMapped to local message + - add local message + - add remote message + + - modify: + - split message into local and remote part + - if local message is not empty + - add isMapped to local message + - search for local record + - if present + - modify local record + - otherwise + - add local message + - modify remote record + + - delete: + - search for local record + - if present + - delete local record + - delete remote record + + - rename: + - search for local record + - if present + - rename local record + - modify local isMapped + - rename remote record +*/ + + + +/* Private data structures + * ======================= */ + +/* Global private data */ +/* Extract mappings from private data. */ +const struct ldb_map_context *map_get_context(struct ldb_module *module) +{ + const struct map_private *data = talloc_get_type(module->private_data, struct map_private); + return data->context; +} + +/* Create a generic request context. */ +static struct map_context *map_init_context(struct ldb_handle *h, struct ldb_request *req) +{ + struct map_context *ac; + + ac = talloc_zero(h, struct map_context); + if (ac == NULL) { + map_oom(h->module); + return NULL; + } + + ac->module = h->module; + ac->orig_req = req; + + return ac; +} + +/* Create a search request context. */ +struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares) +{ + struct map_search_context *sc; + + sc = talloc_zero(ac, struct map_search_context); + if (sc == NULL) { + map_oom(ac->module); + return NULL; + } + + sc->ac = ac; + sc->local_res = NULL; + sc->remote_res = ares; + + return sc; +} + +/* Create a request context and handle. */ +struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module) +{ + struct map_context *ac; + struct ldb_handle *h; + + h = talloc_zero(req, struct ldb_handle); + if (h == NULL) { + map_oom(module); + return NULL; + } + + h->module = module; + + ac = map_init_context(h, req); + if (ac == NULL) { + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + return h; +} + + +/* Dealing with DNs for different partitions + * ========================================= */ + +/* Check whether any data should be stored in the local partition. */ +bool map_check_local_db(struct ldb_module *module) +{ + const struct ldb_map_context *data = map_get_context(module); + + if (!data->remote_base_dn || !data->local_base_dn) { + return false; + } + + return true; +} + +/* Copy a DN with the base DN of the local partition. */ +static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn) +{ + struct ldb_dn *new_dn; + + new_dn = ldb_dn_copy(mem_ctx, dn); + if ( ! ldb_dn_validate(new_dn)) { + talloc_free(new_dn); + return NULL; + } + + /* may be we don't need to rebase at all */ + if ( ! data->remote_base_dn || ! data->local_base_dn) { + return new_dn; + } + + if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->remote_base_dn))) { + talloc_free(new_dn); + return NULL; + } + + if ( ! ldb_dn_add_base(new_dn, data->local_base_dn)) { + talloc_free(new_dn); + return NULL; + } + + return new_dn; +} + +/* Copy a DN with the base DN of the remote partition. */ +static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn) +{ + struct ldb_dn *new_dn; + + new_dn = ldb_dn_copy(mem_ctx, dn); + if ( ! ldb_dn_validate(new_dn)) { + talloc_free(new_dn); + return NULL; + } + + /* may be we don't need to rebase at all */ + if ( ! data->remote_base_dn || ! data->local_base_dn) { + return new_dn; + } + + if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->local_base_dn))) { + talloc_free(new_dn); + return NULL; + } + + if ( ! ldb_dn_add_base(new_dn, data->remote_base_dn)) { + talloc_free(new_dn); + return NULL; + } + + return new_dn; +} + +/* Run a request and make sure it targets the remote partition. */ +/* TODO: free old DNs and messages? */ +int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_message *msg; + + switch (request->operation) { + case LDB_SEARCH: + if (request->op.search.base) { + request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base); + } else { + request->op.search.base = data->remote_base_dn; + /* TODO: adjust scope? */ + } + break; + + case LDB_ADD: + msg = ldb_msg_copy_shallow(request, request->op.add.message); + msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn); + request->op.add.message = msg; + break; + + case LDB_MODIFY: + msg = ldb_msg_copy_shallow(request, request->op.mod.message); + msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn); + request->op.mod.message = msg; + break; + + case LDB_DELETE: + request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn); + break; + + case LDB_RENAME: + request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn); + request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn); + break; + + default: + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Invalid remote request!\n"); + return LDB_ERR_OPERATIONS_ERROR; + } + + return ldb_next_request(module, request); +} + + +/* Finding mappings for attributes and objectClasses + * ================================================= */ + +/* Find an objectClass mapping by the local name. */ +static const struct ldb_map_objectclass *map_objectclass_find_local(const struct ldb_map_context *data, const char *name) +{ + int i; + + for (i = 0; data->objectclass_maps && data->objectclass_maps[i].local_name; i++) { + if (ldb_attr_cmp(data->objectclass_maps[i].local_name, name) == 0) { + return &data->objectclass_maps[i]; + } + } + + return NULL; +} + +/* Find an objectClass mapping by the remote name. */ +static const struct ldb_map_objectclass *map_objectclass_find_remote(const struct ldb_map_context *data, const char *name) +{ + int i; + + for (i = 0; data->objectclass_maps && data->objectclass_maps[i].remote_name; i++) { + if (ldb_attr_cmp(data->objectclass_maps[i].remote_name, name) == 0) { + return &data->objectclass_maps[i]; + } + } + + return NULL; +} + +/* Find an attribute mapping by the local name. */ +const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name) +{ + int i; + + for (i = 0; data->attribute_maps[i].local_name; i++) { + if (ldb_attr_cmp(data->attribute_maps[i].local_name, name) == 0) { + return &data->attribute_maps[i]; + } + } + for (i = 0; data->attribute_maps[i].local_name; i++) { + if (ldb_attr_cmp(data->attribute_maps[i].local_name, "*") == 0) { + return &data->attribute_maps[i]; + } + } + + return NULL; +} + +/* Find an attribute mapping by the remote name. */ +const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name) +{ + const struct ldb_map_attribute *map; + const struct ldb_map_attribute *wildcard = NULL; + int i, j; + + for (i = 0; data->attribute_maps[i].local_name; i++) { + map = &data->attribute_maps[i]; + if (ldb_attr_cmp(map->local_name, "*") == 0) { + wildcard = &data->attribute_maps[i]; + } + + switch (map->type) { + case MAP_IGNORE: + break; + + case MAP_KEEP: + if (ldb_attr_cmp(map->local_name, name) == 0) { + return map; + } + break; + + case MAP_RENAME: + case MAP_CONVERT: + if (ldb_attr_cmp(map->u.rename.remote_name, name) == 0) { + return map; + } + break; + + case MAP_GENERATE: + for (j = 0; map->u.generate.remote_names && map->u.generate.remote_names[j]; j++) { + if (ldb_attr_cmp(map->u.generate.remote_names[j], name) == 0) { + return map; + } + } + break; + } + } + + /* We didn't find it, so return the wildcard record if one was configured */ + return wildcard; +} + + +/* Mapping attributes + * ================== */ + +/* Check whether an attribute will be mapped into the remote partition. */ +bool map_attr_check_remote(const struct ldb_map_context *data, const char *attr) +{ + const struct ldb_map_attribute *map = map_attr_find_local(data, attr); + + if (map == NULL) { + return false; + } + if (map->type == MAP_IGNORE) { + return false; + } + + return true; +} + +/* Map an attribute name into the remote partition. */ +const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr) +{ + if (map == NULL) { + return talloc_strdup(mem_ctx, attr); + } + + switch (map->type) { + case MAP_KEEP: + return talloc_strdup(mem_ctx, attr); + + case MAP_RENAME: + case MAP_CONVERT: + return talloc_strdup(mem_ctx, map->u.rename.remote_name); + + default: + return NULL; + } +} + +/* Map an attribute name back into the local partition. */ +const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr) +{ + if (map == NULL) { + return talloc_strdup(mem_ctx, attr); + } + + if (map->type == MAP_KEEP) { + return talloc_strdup(mem_ctx, attr); + } + + return talloc_strdup(mem_ctx, map->local_name); +} + + +/* Merge two lists of attributes into a single one. */ +int map_attrs_merge(struct ldb_module *module, void *mem_ctx, + const char ***attrs, const char * const *more_attrs) +{ + int i, j, k; + + for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ; + for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ; + + *attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1); + if (*attrs == NULL) { + map_oom(module); + return -1; + } + + for (k = 0; k < j; k++) { + (*attrs)[i + k] = more_attrs[k]; + } + + (*attrs)[i+k] = NULL; + + return 0; +} + +/* Mapping ldb values + * ================== */ + +/* Map an ldb value into the remote partition. */ +struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, + const struct ldb_map_attribute *map, const struct ldb_val *val) +{ + if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) { + return map->u.convert.convert_local(module, mem_ctx, val); + } + + return ldb_val_dup(mem_ctx, val); +} + +/* Map an ldb value back into the local partition. */ +struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, + const struct ldb_map_attribute *map, const struct ldb_val *val) +{ + if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) { + return map->u.convert.convert_remote(module, mem_ctx, val); + } + + return ldb_val_dup(mem_ctx, val); +} + + +/* Mapping DNs + * =========== */ + +/* Check whether a DN is below the local baseDN. */ +bool ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn) +{ + const struct ldb_map_context *data = map_get_context(module); + + if (!data->local_base_dn) { + return true; + } + + return ldb_dn_compare_base(data->local_base_dn, dn) == 0; +} + +/* Map a DN into the remote partition. */ +struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_dn *newdn; + const struct ldb_map_attribute *map; + enum ldb_map_attr_type map_type; + const char *name; + struct ldb_val value; + int i, ret; + + if (dn == NULL) { + return NULL; + } + + newdn = ldb_dn_copy(mem_ctx, dn); + if (newdn == NULL) { + map_oom(module); + return NULL; + } + + /* For each RDN, map the component name and possibly the value */ + for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) { + map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i)); + + /* Unknown attribute - leave this RDN as is and hope the best... */ + if (map == NULL) { + map_type = MAP_KEEP; + } else { + map_type = map->type; + } + + switch (map_type) { + case MAP_IGNORE: + case MAP_GENERATE: + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "MAP_IGNORE/MAP_GENERATE attribute '%s' " + "used in DN!\n", ldb_dn_get_component_name(dn, i)); + goto failed; + + case MAP_CONVERT: + if (map->u.convert.convert_local == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "'convert_local' not set for attribute '%s' " + "used in DN!\n", ldb_dn_get_component_name(dn, i)); + goto failed; + } + /* fall through */ + case MAP_KEEP: + case MAP_RENAME: + name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i)); + if (name == NULL) goto failed; + + value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i)); + if (value.data == NULL) goto failed; + + ret = ldb_dn_set_component(newdn, i, name, value); + if (ret != LDB_SUCCESS) { + goto failed; + } + + break; + } + } + + return newdn; + +failed: + talloc_free(newdn); + return NULL; +} + +/* Map a DN into the local partition. */ +struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_dn *newdn; + const struct ldb_map_attribute *map; + enum ldb_map_attr_type map_type; + const char *name; + struct ldb_val value; + int i, ret; + + if (dn == NULL) { + return NULL; + } + + newdn = ldb_dn_copy(mem_ctx, dn); + if (newdn == NULL) { + map_oom(module); + return NULL; + } + + /* For each RDN, map the component name and possibly the value */ + for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) { + map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i)); + + /* Unknown attribute - leave this RDN as is and hope the best... */ + if (map == NULL) { + map_type = MAP_KEEP; + } else { + map_type = map->type; + } + + switch (map_type) { + case MAP_IGNORE: + case MAP_GENERATE: + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "MAP_IGNORE/MAP_GENERATE attribute '%s' " + "used in DN!\n", ldb_dn_get_component_name(dn, i)); + goto failed; + + case MAP_CONVERT: + if (map->u.convert.convert_remote == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "'convert_remote' not set for attribute '%s' " + "used in DN!\n", ldb_dn_get_component_name(dn, i)); + goto failed; + } + /* fall through */ + case MAP_KEEP: + case MAP_RENAME: + name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i)); + if (name == NULL) goto failed; + + value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i)); + if (value.data == NULL) goto failed; + + ret = ldb_dn_set_component(newdn, i, name, value); + if (ret != LDB_SUCCESS) { + goto failed; + } + + break; + } + } + + return newdn; + +failed: + talloc_free(newdn); + return NULL; +} + +/* Map a DN and its base into the local partition. */ +/* TODO: This should not be required with GUIDs. */ +struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_dn *dn1, *dn2; + + dn1 = ldb_dn_rebase_local(mem_ctx, data, dn); + dn2 = ldb_dn_map_remote(module, mem_ctx, dn1); + + talloc_free(dn1); + return dn2; +} + + +/* Converting DNs and objectClasses (as ldb values) + * ================================================ */ + +/* Map a DN contained in an ldb value into the remote partition. */ +static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) +{ + struct ldb_dn *dn, *newdn; + struct ldb_val newval; + + dn = ldb_dn_new(mem_ctx, module->ldb, (char *)val->data); + if (! ldb_dn_validate(dn)) { + newval.length = 0; + newval.data = NULL; + talloc_free(dn); + return newval; + } + newdn = ldb_dn_map_local(module, mem_ctx, dn); + talloc_free(dn); + + newval.length = 0; + newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn); + if (newval.data) { + newval.length = strlen((char *)newval.data); + } + talloc_free(newdn); + + return newval; +} + +/* Map a DN contained in an ldb value into the local partition. */ +static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) +{ + struct ldb_dn *dn, *newdn; + struct ldb_val newval; + + dn = ldb_dn_new(mem_ctx, module->ldb, (char *)val->data); + if (! ldb_dn_validate(dn)) { + newval.length = 0; + newval.data = NULL; + talloc_free(dn); + return newval; + } + newdn = ldb_dn_map_remote(module, mem_ctx, dn); + talloc_free(dn); + + newval.length = 0; + newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn); + if (newval.data) { + newval.length = strlen((char *)newval.data); + } + talloc_free(newdn); + + return newval; +} + +/* Map an objectClass into the remote partition. */ +static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) +{ + const struct ldb_map_context *data = map_get_context(module); + const char *name = (char *)val->data; + const struct ldb_map_objectclass *map = map_objectclass_find_local(data, name); + struct ldb_val newval; + + if (map) { + newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->remote_name); + newval.length = strlen((char *)newval.data); + return newval; + } + + return ldb_val_dup(mem_ctx, val); +} + +/* Generate a remote message with a mapped objectClass. */ +static void map_objectclass_generate_remote(struct ldb_module *module, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_message_element *el, *oc; + struct ldb_val val; + bool found_extensibleObject = false; + int i; + + /* Find old local objectClass */ + oc = ldb_msg_find_element(old, "objectClass"); + if (oc == NULL) { + return; + } + + /* Prepare new element */ + el = talloc_zero(remote, struct ldb_message_element); + if (el == NULL) { + ldb_oom(module->ldb); + return; /* TODO: fail? */ + } + + /* Copy local objectClass element, reverse space for an extra value */ + el->num_values = oc->num_values + 1; + el->values = talloc_array(el, struct ldb_val, el->num_values); + if (el->values == NULL) { + talloc_free(el); + ldb_oom(module->ldb); + return; /* TODO: fail? */ + } + + /* Copy local element name "objectClass" */ + el->name = talloc_strdup(el, local_attr); + + /* Convert all local objectClasses */ + for (i = 0; i < el->num_values - 1; i++) { + el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]); + if (ldb_attr_cmp((char *)el->values[i].data, data->add_objectclass) == 0) { + found_extensibleObject = true; + } + } + + if (!found_extensibleObject) { + val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass); + val.length = strlen((char *)val.data); + + /* Append additional objectClass data->add_objectclass */ + el->values[i] = val; + } else { + el->num_values--; + } + + /* Add new objectClass to remote message */ + ldb_msg_add(remote, el, 0); +} + +/* Map an objectClass into the local partition. */ +static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) +{ + const struct ldb_map_context *data = map_get_context(module); + const char *name = (char *)val->data; + const struct ldb_map_objectclass *map = map_objectclass_find_remote(data, name); + struct ldb_val newval; + + if (map) { + newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->local_name); + newval.length = strlen((char *)newval.data); + return newval; + } + + return ldb_val_dup(mem_ctx, val); +} + +/* Generate a local message with a mapped objectClass. */ +static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *local_attr, const struct ldb_message *remote) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_message_element *el, *oc; + struct ldb_val val; + int i; + + /* Find old remote objectClass */ + oc = ldb_msg_find_element(remote, "objectClass"); + if (oc == NULL) { + return NULL; + } + + /* Prepare new element */ + el = talloc_zero(mem_ctx, struct ldb_message_element); + if (el == NULL) { + ldb_oom(module->ldb); + return NULL; + } + + /* Copy remote objectClass element */ + el->num_values = oc->num_values; + el->values = talloc_array(el, struct ldb_val, el->num_values); + if (el->values == NULL) { + talloc_free(el); + ldb_oom(module->ldb); + return NULL; + } + + /* Copy remote element name "objectClass" */ + el->name = talloc_strdup(el, local_attr); + + /* Convert all remote objectClasses */ + for (i = 0; i < el->num_values; i++) { + el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]); + } + + val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass); + val.length = strlen((char *)val.data); + + /* Remove last value if it was the string in data->add_objectclass (eg samba4top, extensibleObject) */ + if (ldb_val_equal_exact(&val, &el->values[i-1])) { + el->num_values--; + el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values); + if (el->values == NULL) { + talloc_free(el); + ldb_oom(module->ldb); + return NULL; + } + } + + return el; +} + +static const struct ldb_map_attribute objectclass_convert_map = { + .local_name = "objectClass", + .type = MAP_CONVERT, + .u = { + .convert = { + .remote_name = "objectClass", + .convert_local = map_objectclass_convert_local, + .convert_remote = map_objectclass_convert_remote, + }, + }, +}; + + +/* Mappings for searches on objectClass= assuming a one-to-one + * mapping. Needed because this is a generate operator for the + * add/modify code */ +static int map_objectclass_convert_operator(struct ldb_module *module, void *mem_ctx, + struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + + return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_convert_map); +} + +/* Auxiliary request construction + * ============================== */ + +/* Store the DN of a single search result in context. */ +static int map_search_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct map_context *ac; + + if (context == NULL || ares == NULL) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback")); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac = talloc_get_type(context, struct map_context); + + /* We are interested only in the single reply */ + if (ares->type != LDB_REPLY_ENTRY) { + talloc_free(ares); + return LDB_SUCCESS; + } + + /* We have already found a remote DN */ + if (ac->local_dn) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search")); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Store local DN */ + ac->local_dn = ares->message->dn; + + return LDB_SUCCESS; +} + +/* Build a request to search a record by its DN. */ +struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback) +{ + struct ldb_request *req; + + req = talloc_zero(ac, struct ldb_request); + if (req == NULL) { + map_oom(ac->module); + return NULL; + } + + req->operation = LDB_SEARCH; + req->op.search.base = dn; + req->op.search.scope = LDB_SCOPE_BASE; + req->op.search.attrs = attrs; + + if (tree) { + req->op.search.tree = tree; + } else { + req->op.search.tree = ldb_parse_tree(req, NULL); + if (req->op.search.tree == NULL) { + talloc_free(req); + return NULL; + } + } + + req->controls = NULL; + req->context = context; + req->callback = callback; + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req); + + return req; +} + +/* Build a request to search the local record by its DN. */ +struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn) +{ + /* attrs[] is returned from this function in + * ac->search_req->op.search.attrs, so it must be static, as + * otherwise the compiler can put it on the stack */ + static const char * const attrs[] = { IS_MAPPED, NULL }; + struct ldb_parse_tree *tree; + + /* Limit search to records with 'IS_MAPPED' present */ + /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */ + tree = talloc_zero(ac, struct ldb_parse_tree); + if (tree == NULL) { + map_oom(ac->module); + return NULL; + } + + tree->operation = LDB_OP_PRESENT; + tree->u.present.attr = talloc_strdup(tree, IS_MAPPED); + + return map_search_base_req(ac, dn, attrs, tree, ac, map_search_self_callback); +} + +/* Build a request to update the 'IS_MAPPED' attribute */ +struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn) +{ + struct ldb_request *req; + struct ldb_message *msg; + const char *dn; + + /* Prepare request */ + req = talloc_zero(ac, struct ldb_request); + if (req == NULL) { + map_oom(ac->module); + return NULL; + } + + /* Prepare message */ + msg = ldb_msg_new(req); + if (msg == NULL) { + map_oom(ac->module); + goto failed; + } + + /* Update local 'IS_MAPPED' to the new remote DN */ + msg->dn = ldb_dn_copy(msg, olddn); + dn = ldb_dn_alloc_linearized(msg, newdn); + if ( ! dn || ! ldb_dn_validate(msg->dn)) { + goto failed; + } + if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) { + goto failed; + } + if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) { + goto failed; + } + + req->operation = LDB_MODIFY; + req->op.mod.message = msg; + req->controls = NULL; + req->handle = NULL; + req->context = NULL; + req->callback = NULL; + + return req; + +failed: + talloc_free(req); + return NULL; +} + + +/* Asynchronous call structure + * =========================== */ + +/* Figure out which request is currently pending. */ +static struct ldb_request *map_get_req(struct map_context *ac) +{ + switch (ac->step) { + case MAP_SEARCH_SELF_MODIFY: + case MAP_SEARCH_SELF_DELETE: + case MAP_SEARCH_SELF_RENAME: + return ac->search_req; + + case MAP_ADD_REMOTE: + case MAP_MODIFY_REMOTE: + case MAP_DELETE_REMOTE: + case MAP_RENAME_REMOTE: + return ac->remote_req; + + case MAP_RENAME_FIXUP: + return ac->down_req; + + case MAP_ADD_LOCAL: + case MAP_MODIFY_LOCAL: + case MAP_DELETE_LOCAL: + case MAP_RENAME_LOCAL: + return ac->local_req; + + case MAP_SEARCH_REMOTE: + /* Can't happen */ + break; + } + + return NULL; /* unreachable; silences a warning */ +} + +typedef int (*map_next_function)(struct ldb_handle *handle); + +/* Figure out the next request to run. */ +static map_next_function map_get_next(struct map_context *ac) +{ + switch (ac->step) { + case MAP_SEARCH_REMOTE: + return NULL; + + case MAP_ADD_LOCAL: + return map_add_do_remote; + case MAP_ADD_REMOTE: + return NULL; + + case MAP_SEARCH_SELF_MODIFY: + return map_modify_do_local; + case MAP_MODIFY_LOCAL: + return map_modify_do_remote; + case MAP_MODIFY_REMOTE: + return NULL; + + case MAP_SEARCH_SELF_DELETE: + return map_delete_do_local; + case MAP_DELETE_LOCAL: + return map_delete_do_remote; + case MAP_DELETE_REMOTE: + return NULL; + + case MAP_SEARCH_SELF_RENAME: + return map_rename_do_local; + case MAP_RENAME_LOCAL: + return map_rename_do_fixup; + case MAP_RENAME_FIXUP: + return map_rename_do_remote; + case MAP_RENAME_REMOTE: + return NULL; + } + + return NULL; /* unreachable; silences a warning */ +} + +/* Wait for the current pending request to finish and continue with the next. */ +static int map_wait_next(struct ldb_handle *handle) +{ + struct map_context *ac; + struct ldb_request *req; + map_next_function next; + int ret; + + if (handle == NULL || handle->private_data == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (handle->state == LDB_ASYNC_DONE) { + return handle->status; + } + + handle->state = LDB_ASYNC_PENDING; + handle->status = LDB_SUCCESS; + + ac = talloc_get_type(handle->private_data, struct map_context); + + if (ac->step == MAP_SEARCH_REMOTE) { + int i; + for (i = 0; i < ac->num_searches; i++) { + req = ac->search_reqs[i]; + ret = ldb_wait(req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (req->handle->status != LDB_SUCCESS) { + handle->status = req->handle->status; + goto done; + } + if (req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + } + } else { + + req = map_get_req(ac); + + ret = ldb_wait(req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (req->handle->status != LDB_SUCCESS) { + handle->status = req->handle->status; + goto done; + } + if (req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + next = map_get_next(ac); + if (next) { + return next(handle); + } + } + + ret = LDB_SUCCESS; + +done: + handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* Wait for all current pending requests to finish. */ +static int map_wait_all(struct ldb_handle *handle) +{ + int ret; + + while (handle->state != LDB_ASYNC_DONE) { + ret = map_wait_next(handle); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return handle->status; +} + +/* Wait for pending requests to finish. */ +int map_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + if (type == LDB_WAIT_ALL) { + return map_wait_all(handle); + } else { + return map_wait_next(handle); + } +} + + +/* Module initialization + * ===================== */ + + +/* Builtin mappings for DNs and objectClasses */ +static const struct ldb_map_attribute builtin_attribute_maps[] = { + { + .local_name = "dn", + .type = MAP_CONVERT, + .u = { + .convert = { + .remote_name = "dn", + .convert_local = ldb_dn_convert_local, + .convert_remote = ldb_dn_convert_remote, + }, + }, + }, + { + .local_name = NULL, + } +}; + +static const struct ldb_map_attribute objectclass_attribute_map = { + .local_name = "objectClass", + .type = MAP_GENERATE, + .convert_operator = map_objectclass_convert_operator, + .u = { + .generate = { + .remote_names = { "objectClass", NULL }, + .generate_local = map_objectclass_generate_local, + .generate_remote = map_objectclass_generate_remote, + }, + }, +}; + + +/* Find the special 'MAP_DN_NAME' record and store local and remote + * base DNs in private data. */ +static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name) +{ + static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL }; + struct ldb_dn *dn; + struct ldb_message *msg; + struct ldb_result *res; + int ret; + + if (!name) { + data->local_base_dn = NULL; + data->remote_base_dn = NULL; + return LDB_SUCCESS; + } + + dn = ldb_dn_new_fmt(data, module->ldb, "%s=%s", MAP_DN_NAME, name); + if ( ! ldb_dn_validate(dn)) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Failed to construct '%s' DN!\n", MAP_DN_NAME); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, attrs, &res); + talloc_free(dn); + if (ret != LDB_SUCCESS) { + return ret; + } + if (res->count == 0) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "No results for '%s=%s'!\n", MAP_DN_NAME, name); + talloc_free(res); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + if (res->count > 1) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Too many results for '%s=%s'!\n", MAP_DN_NAME, name); + talloc_free(res); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + msg = res->msgs[0]; + data->local_base_dn = ldb_msg_find_attr_as_dn(module->ldb, data, msg, MAP_DN_FROM); + data->remote_base_dn = ldb_msg_find_attr_as_dn(module->ldb, data, msg, MAP_DN_TO); + talloc_free(res); + + return LDB_SUCCESS; +} + +/* Store attribute maps and objectClass maps in private data. */ +static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data, + const struct ldb_map_attribute *attrs, + const struct ldb_map_objectclass *ocls, + const char * const *wildcard_attributes) +{ + int i, j, last; + last = 0; + + /* Count specified attribute maps */ + for (i = 0; attrs[i].local_name; i++) /* noop */ ; + /* Count built-in attribute maps */ + for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ; + + /* Store list of attribute maps */ + data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+2); + if (data->attribute_maps == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Specified ones go first */ + for (i = 0; attrs[i].local_name; i++) { + data->attribute_maps[last] = attrs[i]; + last++; + } + + /* Built-in ones go last */ + for (i = 0; builtin_attribute_maps[i].local_name; i++) { + data->attribute_maps[last] = builtin_attribute_maps[i]; + last++; + } + + if (data->add_objectclass) { + /* ObjectClass one is very last, if required */ + data->attribute_maps[last] = objectclass_attribute_map; + last++; + } else if (ocls) { + data->attribute_maps[last] = objectclass_convert_map; + last++; + } + + /* Ensure 'local_name == NULL' for the last entry */ + memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute)); + + /* Store list of objectClass maps */ + data->objectclass_maps = ocls; + + data->wildcard_attributes = wildcard_attributes; + + return LDB_SUCCESS; +} + +/* Initialize global private data. */ +_PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, + const struct ldb_map_objectclass *ocls, + const char * const *wildcard_attributes, + const char *add_objectclass, + const char *name) +{ + struct map_private *data; + int ret; + + /* Prepare private data */ + data = talloc_zero(module, struct map_private); + if (data == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + module->private_data = data; + + data->context = talloc_zero(data, struct ldb_map_context); + if (!data->context) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Store local and remote baseDNs */ + ret = map_init_dns(module, data->context, name); + if (ret != LDB_SUCCESS) { + talloc_free(data); + return ret; + } + + data->context->add_objectclass = add_objectclass; + + /* Store list of attribute and objectClass maps */ + ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes); + if (ret != LDB_SUCCESS) { + talloc_free(data); + return ret; + } + + return LDB_SUCCESS; +} diff --git a/ldb/ldb_map/ldb_map.h b/ldb/ldb_map/ldb_map.h new file mode 100644 index 000000000..e40bb9cd7 --- /dev/null +++ b/ldb/ldb_map/ldb_map.h @@ -0,0 +1,173 @@ +/* + ldb database mapping module + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Martin Kuehl 2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . + +*/ + +#ifndef __LDB_MAP_H__ +#define __LDB_MAP_H__ + +/* ldb_map is a skeleton LDB module that can be used for any other modules + * that need to map attributes. + * + * The term 'remote' in this header refers to the connection where the + * original schema is used on while 'local' means the local connection + * that any upper layers will use. + * + * All local attributes will have to have a definition. Not all remote + * attributes need a definition as LDB is a lot less strict than LDAP + * (in other words, sending unknown attributes to an LDAP server hurts us, + * while returning too many attributes in ldb_search() doesn't) + */ + + +/* Name of the internal attribute pointing from the local to the + * remote part of a record */ +#define IS_MAPPED "isMapped" + + +struct ldb_map_context; + +/* convert a local ldb_val to a remote ldb_val */ +typedef struct ldb_val (*ldb_map_convert_func) (struct ldb_module *module, void *mem_ctx, const struct ldb_val *val); + +#define LDB_MAP_MAX_REMOTE_NAMES 10 + +/* map from local to remote attribute */ +struct ldb_map_attribute { + const char *local_name; /* local name */ + + enum ldb_map_attr_type { + MAP_IGNORE, /* Ignore this local attribute. Doesn't exist remotely. */ + MAP_KEEP, /* Keep as is. Same name locally and remotely. */ + MAP_RENAME, /* Simply rename the attribute. Name changes, data is the same */ + MAP_CONVERT, /* Rename + convert data */ + MAP_GENERATE /* Use generate function for generating new name/data. + Used for generating attributes based on + multiple remote attributes. */ + } type; + + /* if set, will be called for search expressions that contain this attribute */ + int (*convert_operator)(struct ldb_module *, TALLOC_CTX *ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *); + + union { + struct { + const char *remote_name; + } rename; + + struct { + const char *remote_name; + + /* Convert local to remote data */ + ldb_map_convert_func convert_local; + + /* Convert remote to local data */ + /* an entry can have convert_remote set to NULL, as long as there as an entry with the same local_name + * that is non-NULL before it. */ + ldb_map_convert_func convert_remote; + } convert; + + struct { + /* Generate the local attribute from remote message */ + struct ldb_message_element *(*generate_local)(struct ldb_module *, TALLOC_CTX *mem_ctx, const char *remote_attr, const struct ldb_message *remote); + + /* Update remote message with information from local message */ + void (*generate_remote)(struct ldb_module *, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local); + + /* Name(s) for this attribute on the remote server. This is an array since + * one local attribute's data can be split up into several attributes + * remotely */ + const char *remote_names[LDB_MAP_MAX_REMOTE_NAMES]; + + /* Names of additional remote attributes + * required for the generation. NULL + * indicates that `local_attr' suffices. */ + /* +#define LDB_MAP_MAX_SELF_ATTRIBUTES 10 + const char *self_attrs[LDB_MAP_MAX_SELF_ATTRIBUTES]; + */ + } generate; + } u; +}; + + +#define LDB_MAP_MAX_SUBCLASSES 10 +#define LDB_MAP_MAX_MUSTS 10 +#define LDB_MAP_MAX_MAYS 50 + +/* map from local to remote objectClass */ +struct ldb_map_objectclass { + const char *local_name; + const char *remote_name; + const char *base_classes[LDB_MAP_MAX_SUBCLASSES]; + const char *musts[LDB_MAP_MAX_MUSTS]; + const char *mays[LDB_MAP_MAX_MAYS]; +}; + + +/* private context data */ +struct ldb_map_context { + struct ldb_map_attribute *attribute_maps; + /* NOTE: Always declare base classes first here */ + const struct ldb_map_objectclass *objectclass_maps; + + /* Remote (often operational) attributes that should be added + * to any wildcard search */ + const char * const *wildcard_attributes; + + /* ObjectClass (if any) to be added to remote attributes on add */ + const char *add_objectclass; + + /* struct ldb_context *mapped_ldb; */ + struct ldb_dn *local_base_dn; + struct ldb_dn *remote_base_dn; +}; + +/* Global private data */ +struct map_private { + void *caller_private; + struct ldb_map_context *context; +}; + +/* Initialize global private data. */ +int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, + const struct ldb_map_objectclass *ocls, + const char * const *wildcard_attributes, + const char *add_objectclass, + const char *name); + +int map_add(struct ldb_module *module, struct ldb_request *req); +int map_search(struct ldb_module *module, struct ldb_request *req); +int map_rename(struct ldb_module *module, struct ldb_request *req); +int map_delete(struct ldb_module *module, struct ldb_request *req); +int map_modify(struct ldb_module *module, struct ldb_request *req); +int map_wait(struct ldb_handle *handle, enum ldb_wait_type type); + +#define LDB_MAP_OPS \ + .add = map_add, \ + .modify = map_modify, \ + .del = map_delete, \ + .rename = map_rename, \ + .search = map_search, \ + .wait = map_wait, + +#endif /* __LDB_MAP_H__ */ diff --git a/ldb/ldb_map/ldb_map_inbound.c b/ldb/ldb_map/ldb_map_inbound.c new file mode 100644 index 000000000..7fc3ac4ed --- /dev/null +++ b/ldb/ldb_map/ldb_map_inbound.c @@ -0,0 +1,723 @@ +/* + ldb database mapping module + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Martin Kuehl 2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . + +*/ + +#include "ldb_includes.h" + +#include "ldb_map.h" +#include "ldb_map_private.h" + + +/* Mapping message elements + * ======================== */ + +/* Map a message element into the remote partition. */ +static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old) +{ + struct ldb_message_element *el; + int i; + + el = talloc_zero(mem_ctx, struct ldb_message_element); + if (el == NULL) { + map_oom(module); + return NULL; + } + + el->num_values = old->num_values; + el->values = talloc_array(el, struct ldb_val, el->num_values); + if (el->values == NULL) { + talloc_free(el); + map_oom(module); + return NULL; + } + + el->name = map_attr_map_local(el, map, old->name); + + for (i = 0; i < el->num_values; i++) { + el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]); + } + + return el; +} + +/* Add a message element either to a local or to a remote message, + * depending on whether it goes into the local or remote partition. */ +static int ldb_msg_el_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old) +{ + const struct ldb_map_context *data = map_get_context(module); + const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name); + struct ldb_message_element *el=NULL; + + /* Unknown attribute: ignore */ + if (map == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " + "Not mapping attribute '%s': no mapping found\n", + old->name); + goto local; + } + + switch (map->type) { + case MAP_IGNORE: + goto local; + + case MAP_CONVERT: + if (map->u.convert.convert_local == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " + "Not mapping attribute '%s': " + "'convert_local' not set\n", + map->local_name); + goto local; + } + /* fall through */ + case MAP_KEEP: + case MAP_RENAME: + el = ldb_msg_el_map_local(module, remote, map, old); + break; + + case MAP_GENERATE: + if (map->u.generate.generate_remote == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " + "Not mapping attribute '%s': " + "'generate_remote' not set\n", + map->local_name); + goto local; + } + + /* TODO: if this attr requires context: + * make sure all context attrs are mappable (in 'names') + * make sure all context attrs have already been mapped? + * maybe postpone generation until they have been mapped? + */ + + map->u.generate.generate_remote(module, map->local_name, msg, remote, local); + return 0; + } + + if (el == NULL) { + return -1; + } + + return ldb_msg_add(remote, el, old->flags); + +local: + el = talloc(local, struct ldb_message_element); + if (el == NULL) { + map_oom(module); + return -1; + } + + *el = *old; /* copy the old element */ + + return ldb_msg_add(local, el, old->flags); +} + +/* Mapping messages + * ================ */ + +/* Check whether a message will be (partially) mapped into the remote partition. */ +static bool ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg) +{ + const struct ldb_map_context *data = map_get_context(module); + bool ret; + int i; + + for (i = 0; i < msg->num_elements; i++) { + ret = map_attr_check_remote(data, msg->elements[i].name); + if (ret) { + return ret; + } + } + + return false; +} + +/* Split message elements that stay in the local partition from those + * that are mapped into the remote partition. */ +static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg) +{ + /* const char * const names[]; */ + int i, ret; + + for (i = 0; i < msg->num_elements; i++) { + /* Skip 'IS_MAPPED' */ + if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " + "Skipping attribute '%s'\n", + msg->elements[i].name); + continue; + } + + ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]); + if (ret) { + return ret; + } + } + + return 0; +} + + +/* Inbound requests: add, modify, rename, delete + * ============================================= */ + +/* Add the remote record. */ +int map_add_do_remote(struct ldb_handle *handle) +{ + struct map_context *ac; + + ac = talloc_get_type(handle->private_data, struct map_context); + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req); + + ac->step = MAP_ADD_REMOTE; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_remote_request(ac->module, ac->remote_req); +} + +/* Add the local record. */ +int map_add_do_local(struct ldb_handle *handle) +{ + struct map_context *ac; + + ac = talloc_get_type(handle->private_data, struct map_context); + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); + + ac->step = MAP_ADD_LOCAL; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_request(ac->module, ac->local_req); +} + +/* Add a record. */ +int map_add(struct ldb_module *module, struct ldb_request *req) +{ + const struct ldb_message *msg = req->op.add.message; + struct ldb_handle *h; + struct map_context *ac; + struct ldb_message *local, *remote; + const char *dn; + + /* Do not manipulate our control entries */ + if (ldb_dn_is_special(msg->dn)) { + return ldb_next_request(module, req); + } + + /* No mapping requested (perhaps no DN mapping specified), skip to next module */ + if (!ldb_dn_check_local(module, msg->dn)) { + return ldb_next_request(module, req); + } + + /* No mapping needed, fail */ + if (!ldb_msg_check_remote(module, msg)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Prepare context and handle */ + h = map_init_handle(req, module); + if (h == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct map_context); + + /* Prepare the local operation */ + ac->local_req = talloc(ac, struct ldb_request); + if (ac->local_req == NULL) { + goto oom; + } + + *(ac->local_req) = *req; /* copy the request */ + + ac->local_req->context = NULL; + ac->local_req->callback = NULL; + + /* Prepare the remote operation */ + ac->remote_req = talloc(ac, struct ldb_request); + if (ac->remote_req == NULL) { + goto oom; + } + + *(ac->remote_req) = *req; /* copy the request */ + + ac->remote_req->context = NULL; + ac->remote_req->callback = NULL; + + /* Prepare the local message */ + local = ldb_msg_new(ac->local_req); + if (local == NULL) { + goto oom; + } + local->dn = msg->dn; + + /* Prepare the remote message */ + remote = ldb_msg_new(ac->remote_req); + if (remote == NULL) { + goto oom; + } + remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn); + + /* Split local from remote message */ + ldb_msg_partition(module, local, remote, msg); + ac->local_req->op.add.message = local; + ac->remote_req->op.add.message = remote; + + if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) { + /* No local data or db, just run the remote request */ + talloc_free(ac->local_req); + req->handle = h; /* return our own handle to deal with this call */ + return map_add_do_remote(h); + } + + /* Store remote DN in 'IS_MAPPED' */ + /* TODO: use GUIDs here instead */ + dn = ldb_dn_alloc_linearized(local, remote->dn); + if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) { + goto failed; + } + + req->handle = h; /* return our own handle to deal with this call */ + return map_add_do_local(h); + +oom: + map_oom(module); +failed: + talloc_free(h); + return LDB_ERR_OPERATIONS_ERROR; +} + +/* Modify the remote record. */ +int map_modify_do_remote(struct ldb_handle *handle) +{ + struct map_context *ac; + + ac = talloc_get_type(handle->private_data, struct map_context); + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req); + + ac->step = MAP_MODIFY_REMOTE; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_remote_request(ac->module, ac->remote_req); +} + +/* Modify the local record. */ +int map_modify_do_local(struct ldb_handle *handle) +{ + struct map_context *ac; + struct ldb_message *msg; + char *dn; + + ac = talloc_get_type(handle->private_data, struct map_context); + + if (ac->local_dn == NULL) { + /* No local record present, add it instead */ + msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message); + + /* Add local 'IS_MAPPED' */ + /* TODO: use GUIDs here instead */ + if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + dn = ldb_dn_alloc_linearized(msg, ac->remote_req->op.mod.message->dn); + if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Turn request into 'add' */ + ac->local_req->operation = LDB_ADD; + ac->local_req->op.add.message = msg; + /* TODO: Could I just leave msg in there? I think so, + * but it looks clearer this way. */ + } + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); + + ac->step = MAP_MODIFY_LOCAL; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_request(ac->module, ac->local_req); +} + +/* Modify a record. */ +int map_modify(struct ldb_module *module, struct ldb_request *req) +{ + const struct ldb_message *msg = req->op.mod.message; + struct ldb_handle *h; + struct map_context *ac; + struct ldb_message *local, *remote; + + /* Do not manipulate our control entries */ + if (ldb_dn_is_special(msg->dn)) { + return ldb_next_request(module, req); + } + + /* No mapping requested (perhaps no DN mapping specified), skip to next module */ + if (!ldb_dn_check_local(module, msg->dn)) { + return ldb_next_request(module, req); + } + + /* No mapping needed, skip to next module */ + /* TODO: What if the remote part exists, the local doesn't, + * and this request wants to modify local data and thus + * add the local record? */ + if (!ldb_msg_check_remote(module, msg)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Prepare context and handle */ + h = map_init_handle(req, module); + if (h == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct map_context); + + /* Prepare the local operation */ + ac->local_req = talloc(ac, struct ldb_request); + if (ac->local_req == NULL) { + goto oom; + } + + *(ac->local_req) = *req; /* copy the request */ + + ac->local_req->context = NULL; + ac->local_req->callback = NULL; + + /* Prepare the remote operation */ + ac->remote_req = talloc(ac, struct ldb_request); + if (ac->remote_req == NULL) { + goto oom; + } + + *(ac->remote_req) = *req; /* copy the request */ + + ac->remote_req->context = NULL; + ac->remote_req->callback = NULL; + + /* Prepare the local message */ + local = ldb_msg_new(ac->local_req); + if (local == NULL) { + goto oom; + } + local->dn = msg->dn; + + /* Prepare the remote message */ + remote = ldb_msg_new(ac->remote_req); + if (remote == NULL) { + goto oom; + } + remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn); + + /* Split local from remote message */ + ldb_msg_partition(module, local, remote, msg); + ac->local_req->op.mod.message = local; + ac->remote_req->op.mod.message = remote; + + if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) { + /* No local data or db, just run the remote request */ + talloc_free(ac->local_req); + req->handle = h; /* return our own handle to deal with this call */ + return map_modify_do_remote(h); + } + + /* prepare the search operation */ + ac->search_req = map_search_self_req(ac, msg->dn); + if (ac->search_req == NULL) { + goto failed; + } + + ac->step = MAP_SEARCH_SELF_MODIFY; + + req->handle = h; /* return our own handle to deal with this call */ + return ldb_next_request(module, ac->search_req); + +oom: + map_oom(module); +failed: + talloc_free(h); + return LDB_ERR_OPERATIONS_ERROR; +} + +/* Delete the remote record. */ +int map_delete_do_remote(struct ldb_handle *handle) +{ + struct map_context *ac; + + ac = talloc_get_type(handle->private_data, struct map_context); + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req); + + ac->step = MAP_DELETE_REMOTE; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_remote_request(ac->module, ac->remote_req); +} + +/* Delete the local record. */ +int map_delete_do_local(struct ldb_handle *handle) +{ + struct map_context *ac; + + ac = talloc_get_type(handle->private_data, struct map_context); + + /* No local record, continue remotely */ + if (ac->local_dn == NULL) { + return map_delete_do_remote(handle); + } + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); + + ac->step = MAP_DELETE_LOCAL; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_request(ac->module, ac->local_req); +} + +/* Delete a record. */ +int map_delete(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_handle *h; + struct map_context *ac; + + /* Do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.del.dn)) { + return ldb_next_request(module, req); + } + + /* No mapping requested (perhaps no DN mapping specified), skip to next module */ + if (!ldb_dn_check_local(module, req->op.del.dn)) { + return ldb_next_request(module, req); + } + + /* Prepare context and handle */ + h = map_init_handle(req, module); + if (h == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct map_context); + + /* Prepare the local operation */ + ac->local_req = talloc(ac, struct ldb_request); + if (ac->local_req == NULL) { + goto oom; + } + + *(ac->local_req) = *req; /* copy the request */ + ac->local_req->op.del.dn = req->op.del.dn; + + ac->local_req->context = NULL; + ac->local_req->callback = NULL; + + /* Prepare the remote operation */ + ac->remote_req = talloc(ac, struct ldb_request); + if (ac->remote_req == NULL) { + goto oom; + } + + *(ac->remote_req) = *req; /* copy the request */ + ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn); + + /* No local db, just run the remote request */ + if (!map_check_local_db(ac->module)) { + req->handle = h; /* return our own handle to deal with this call */ + return map_delete_do_remote(h); + } + + ac->remote_req->context = NULL; + ac->remote_req->callback = NULL; + + /* Prepare the search operation */ + ac->search_req = map_search_self_req(ac, req->op.del.dn); + if (ac->search_req == NULL) { + goto failed; + } + + req->handle = h; /* return our own handle to deal with this call */ + + ac->step = MAP_SEARCH_SELF_DELETE; + + return ldb_next_request(module, ac->search_req); + +oom: + map_oom(module); +failed: + talloc_free(h); + return LDB_ERR_OPERATIONS_ERROR; +} + +/* Rename the remote record. */ +int map_rename_do_remote(struct ldb_handle *handle) +{ + struct map_context *ac; + + ac = talloc_get_type(handle->private_data, struct map_context); + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req); + + ac->step = MAP_RENAME_REMOTE; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_remote_request(ac->module, ac->remote_req); +} + +/* Update the local 'IS_MAPPED' attribute. */ +int map_rename_do_fixup(struct ldb_handle *handle) +{ + struct map_context *ac; + + ac = talloc_get_type(handle->private_data, struct map_context); + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req); + + ac->step = MAP_RENAME_FIXUP; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_request(ac->module, ac->down_req); +} + +/* Rename the local record. */ +int map_rename_do_local(struct ldb_handle *handle) +{ + struct map_context *ac; + + ac = talloc_get_type(handle->private_data, struct map_context); + + /* No local record, continue remotely */ + if (ac->local_dn == NULL) { + return map_rename_do_remote(handle); + } + + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); + + ac->step = MAP_RENAME_LOCAL; + + handle->state = LDB_ASYNC_INIT; + handle->status = LDB_SUCCESS; + + return ldb_next_request(ac->module, ac->local_req); +} + +/* Rename a record. */ +int map_rename(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_handle *h; + struct map_context *ac; + + /* Do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.rename.olddn)) { + return ldb_next_request(module, req); + } + + /* No mapping requested (perhaps no DN mapping specified), skip to next module */ + if ((!ldb_dn_check_local(module, req->op.rename.olddn)) && + (!ldb_dn_check_local(module, req->op.rename.newdn))) { + return ldb_next_request(module, req); + } + + /* Rename into/out of the mapped partition requested, bail out */ + if (!ldb_dn_check_local(module, req->op.rename.olddn) || + !ldb_dn_check_local(module, req->op.rename.newdn)) { + return LDB_ERR_AFFECTS_MULTIPLE_DSAS; + } + + /* Prepare context and handle */ + h = map_init_handle(req, module); + if (h == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct map_context); + + /* Prepare the local operation */ + ac->local_req = talloc(ac, struct ldb_request); + if (ac->local_req == NULL) { + goto oom; + } + + *(ac->local_req) = *req; /* copy the request */ + ac->local_req->op.rename.olddn = req->op.rename.olddn; + ac->local_req->op.rename.newdn = req->op.rename.newdn; + + ac->local_req->context = NULL; + ac->local_req->callback = NULL; + + /* Prepare the remote operation */ + ac->remote_req = talloc(ac, struct ldb_request); + if (ac->remote_req == NULL) { + goto oom; + } + + *(ac->remote_req) = *req; /* copy the request */ + ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn); + ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn); + + ac->remote_req->context = NULL; + ac->remote_req->callback = NULL; + + /* No local db, just run the remote request */ + if (!map_check_local_db(ac->module)) { + req->handle = h; /* return our own handle to deal with this call */ + return map_rename_do_remote(h); + } + + /* Prepare the fixup operation */ + /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */ + ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn); + if (ac->down_req == NULL) { + goto failed; + } + + /* Prepare the search operation */ + ac->search_req = map_search_self_req(ac, req->op.rename.olddn); + if (ac->search_req == NULL) { + goto failed; + } + + req->handle = h; /* return our own handle to deal with this call */ + + ac->step = MAP_SEARCH_SELF_RENAME; + + return ldb_next_request(module, ac->search_req); + +oom: + map_oom(module); +failed: + talloc_free(h); + return LDB_ERR_OPERATIONS_ERROR; +} diff --git a/ldb/ldb_map/ldb_map_outbound.c b/ldb/ldb_map/ldb_map_outbound.c new file mode 100644 index 000000000..fbc097f31 --- /dev/null +++ b/ldb/ldb_map/ldb_map_outbound.c @@ -0,0 +1,1289 @@ +/* + ldb database mapping module + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Martin Kuehl 2006 + Copyright (C) Andrew Bartlett 2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . + +*/ + +#include "ldb_includes.h" + +#include "ldb_map.h" +#include "ldb_map_private.h" + + +/* Mapping attributes + * ================== */ + +/* Select attributes that stay in the local partition. */ +static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs) +{ + const struct ldb_map_context *data = map_get_context(module); + const char **result; + int i, last; + + if (attrs == NULL) + return NULL; + + last = 0; + result = talloc_array(mem_ctx, const char *, 1); + if (result == NULL) { + goto failed; + } + result[0] = NULL; + + for (i = 0; attrs[i]; i++) { + /* Wildcards and ignored attributes are kept locally */ + if ((ldb_attr_cmp(attrs[i], "*") == 0) || + (!map_attr_check_remote(data, attrs[i]))) { + result = talloc_realloc(mem_ctx, result, const char *, last+2); + if (result == NULL) { + goto failed; + } + + result[last] = talloc_strdup(result, attrs[i]); + result[last+1] = NULL; + last++; + } + } + + return result; + +failed: + talloc_free(result); + map_oom(module); + return NULL; +} + +/* Collect attributes that are mapped into the remote partition. */ +static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx, + const char * const *attrs) +{ + const struct ldb_map_context *data = map_get_context(module); + const char **result; + const struct ldb_map_attribute *map; + const char *name=NULL; + int i, j, last; + int ret; + + last = 0; + result = talloc_array(mem_ctx, const char *, 1); + if (result == NULL) { + goto failed; + } + result[0] = NULL; + + for (i = 0; attrs[i]; i++) { + /* Wildcards are kept remotely, too */ + if (ldb_attr_cmp(attrs[i], "*") == 0) { + const char **new_attrs = NULL; + ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs); + if (ret != LDB_SUCCESS) { + goto failed; + } + ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes); + if (ret != LDB_SUCCESS) { + goto failed; + } + + attrs = new_attrs; + break; + } + } + + for (i = 0; attrs[i]; i++) { + /* Wildcards are kept remotely, too */ + if (ldb_attr_cmp(attrs[i], "*") == 0) { + /* Add all 'include in wildcard' attributes */ + name = attrs[i]; + goto named; + } + + /* Add remote names of mapped attrs */ + map = map_attr_find_local(data, attrs[i]); + if (map == NULL) { + continue; + } + + switch (map->type) { + case MAP_IGNORE: + continue; + + case MAP_KEEP: + name = attrs[i]; + goto named; + + case MAP_RENAME: + case MAP_CONVERT: + name = map->u.rename.remote_name; + goto named; + + case MAP_GENERATE: + /* Add all remote names of "generate" attrs */ + for (j = 0; map->u.generate.remote_names[j]; j++) { + result = talloc_realloc(mem_ctx, result, const char *, last+2); + if (result == NULL) { + goto failed; + } + + result[last] = talloc_strdup(result, map->u.generate.remote_names[j]); + result[last+1] = NULL; + last++; + } + continue; + } + + named: /* We found a single remote name, add that */ + result = talloc_realloc(mem_ctx, result, const char *, last+2); + if (result == NULL) { + goto failed; + } + + result[last] = talloc_strdup(result, name); + result[last+1] = NULL; + last++; + } + + return result; + +failed: + talloc_free(result); + map_oom(module); + return NULL; +} + +/* Split attributes that stay in the local partition from those that + * are mapped into the remote partition. */ +static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs) +{ + *local_attrs = map_attrs_select_local(module, mem_ctx, attrs); + *remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs); + + return 0; +} + +/* Mapping message elements + * ======================== */ + +/* Add an element to a message, overwriting any old identically named elements. */ +static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el) +{ + struct ldb_message_element *old; + + old = ldb_msg_find_element(msg, el->name); + + /* no local result, add as new element */ + if (old == NULL) { + if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) { + return -1; + } + talloc_free(discard_const_p(char, old->name)); + } + + /* copy new element */ + *old = *el; + + /* and make sure we reference the contents */ + if (!talloc_reference(msg->elements, el->name)) { + return -1; + } + if (!talloc_reference(msg->elements, el->values)) { + return -1; + } + + return 0; +} + +/* Map a message element back into the local partition. */ +static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module, + void *mem_ctx, + const struct ldb_map_attribute *map, + const char *attr_name, + const struct ldb_message_element *old) +{ + struct ldb_message_element *el; + int i; + + el = talloc_zero(mem_ctx, struct ldb_message_element); + if (el == NULL) { + map_oom(module); + return NULL; + } + + el->values = talloc_array(el, struct ldb_val, old->num_values); + if (el->values == NULL) { + talloc_free(el); + map_oom(module); + return NULL; + } + + el->name = talloc_strdup(el, attr_name); + if (el->name == NULL) { + talloc_free(el); + map_oom(module); + return NULL; + } + + for (i = 0; i < old->num_values; i++) { + el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]); + /* Conversions might fail, in which case bail */ + if (!el->values[i].data) { + talloc_free(el); + return NULL; + } + el->num_values++; + } + + return el; +} + +/* Merge a remote message element into a local message. */ +static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local, + struct ldb_message *remote, const char *attr_name) +{ + const struct ldb_map_context *data = map_get_context(module); + const struct ldb_map_attribute *map; + struct ldb_message_element *old, *el=NULL; + const char *remote_name = NULL; + + /* We handle wildcards in ldb_msg_el_merge_wildcard */ + if (ldb_attr_cmp(attr_name, "*") == 0) { + return LDB_SUCCESS; + } + + map = map_attr_find_local(data, attr_name); + + /* Unknown attribute in remote message: + * skip, attribute was probably auto-generated */ + if (map == NULL) { + return LDB_SUCCESS; + } + + switch (map->type) { + case MAP_IGNORE: + break; + case MAP_CONVERT: + remote_name = map->u.convert.remote_name; + break; + case MAP_KEEP: + remote_name = attr_name; + break; + case MAP_RENAME: + remote_name = map->u.rename.remote_name; + break; + case MAP_GENERATE: + break; + } + + switch (map->type) { + case MAP_IGNORE: + return LDB_SUCCESS; + + case MAP_CONVERT: + if (map->u.convert.convert_remote == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Skipping attribute '%s': " + "'convert_remote' not set\n", + attr_name); + return LDB_SUCCESS; + } + /* fall through */ + case MAP_KEEP: + case MAP_RENAME: + old = ldb_msg_find_element(remote, remote_name); + if (old) { + el = ldb_msg_el_map_remote(module, local, map, attr_name, old); + } else { + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + break; + + case MAP_GENERATE: + if (map->u.generate.generate_local == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Skipping attribute '%s': " + "'generate_local' not set\n", + attr_name); + return LDB_SUCCESS; + } + + el = map->u.generate.generate_local(module, local, attr_name, remote); + if (!el) { + /* Generation failure is probably due to lack of source attributes */ + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + break; + } + + if (el == NULL) { + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + + return ldb_msg_replace(local, el); +} + +/* Handle wildcard parts of merging a remote message element into a local message. */ +static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local, + struct ldb_message *remote) +{ + const struct ldb_map_context *data = map_get_context(module); + const struct ldb_map_attribute *map = map_attr_find_local(data, "*"); + struct ldb_message_element *el=NULL; + int i, ret; + + /* Perhaps we have a mapping for "*" */ + if (map && map->type == MAP_KEEP) { + /* We copy everything over, and hope that anything with a + more specific rule is overwritten */ + for (i = 0; i < remote->num_elements; i++) { + el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name, + &remote->elements[i]); + if (el == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_msg_replace(local, el); + if (ret) { + return ret; + } + } + } + + /* Now walk the list of possible mappings, and apply each */ + for (i = 0; data->attribute_maps[i].local_name; i++) { + ret = ldb_msg_el_merge(module, local, remote, + data->attribute_maps[i].local_name); + if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { + continue; + } else if (ret) { + return ret; + } else { + continue; + } + } + + return LDB_SUCCESS; +} + +/* Mapping messages + * ================ */ + +/* Merge two local messages into a single one. */ +static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2) +{ + int i, ret; + + for (i = 0; i < msg2->num_elements; i++) { + ret = ldb_msg_replace(msg1, &msg2->elements[i]); + if (ret) { + return ret; + } + } + + return LDB_SUCCESS; +} + +/* Merge a local and a remote message into a single local one. */ +static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local, + struct ldb_message *remote) +{ + int i, ret; + const char * const *attrs = ac->all_attrs; + if (!attrs) { + ret = ldb_msg_el_merge_wildcard(ac->module, local, remote); + if (ret) { + return ret; + } + } + + for (i = 0; attrs && attrs[i]; i++) { + if (ldb_attr_cmp(attrs[i], "*") == 0) { + ret = ldb_msg_el_merge_wildcard(ac->module, local, remote); + if (ret) { + return ret; + } + break; + } + } + + /* Try to map each attribute back; + * Add to local message is possible, + * Overwrite old local attribute if necessary */ + for (i = 0; attrs && attrs[i]; i++) { + ret = ldb_msg_el_merge(ac->module, local, remote, + attrs[i]); + if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { + } else if (ret) { + return ret; + } + } + + return LDB_SUCCESS; +} + +/* Mapping search results + * ====================== */ + +/* Map a search result back into the local partition. */ +static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares) +{ + struct ldb_message *msg; + struct ldb_dn *dn; + int ret; + + /* There is no result message, skip */ + if (ares->type != LDB_REPLY_ENTRY) { + return 0; + } + + /* Create a new result message */ + msg = ldb_msg_new(ares); + if (msg == NULL) { + map_oom(ac->module); + return -1; + } + + /* Merge remote message into new message */ + ret = ldb_msg_merge_remote(ac, msg, ares->message); + if (ret) { + talloc_free(msg); + return ret; + } + + /* Create corresponding local DN */ + dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn); + if (dn == NULL) { + talloc_free(msg); + return -1; + } + msg->dn = dn; + + /* Store new message with new DN as the result */ + talloc_free(ares->message); + ares->message = msg; + + return 0; +} + +/* Mapping parse trees + * =================== */ + +/* Check whether a parse tree can safely be split in two. */ +static bool ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree) +{ + const struct ldb_parse_tree *subtree = tree; + bool negate = false; + + while (subtree) { + switch (subtree->operation) { + case LDB_OP_NOT: + negate = !negate; + subtree = subtree->u.isnot.child; + continue; + + case LDB_OP_AND: + return !negate; /* if negate: False */ + + case LDB_OP_OR: + return negate; /* if negate: True */ + + default: + return true; /* simple parse tree */ + } + } + + return true; /* no parse tree */ +} + +/* Collect a list of attributes required to match a given parse tree. */ +static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree) +{ + const char **new_attrs; + int i, ret; + + if (tree == NULL) { + return 0; + } + + switch (tree->operation) { + case LDB_OP_OR: + case LDB_OP_AND: /* attributes stored in list of subtrees */ + for (i = 0; i < tree->u.list.num_elements; i++) { + ret = ldb_parse_tree_collect_attrs(module, mem_ctx, + attrs, tree->u.list.elements[i]); + if (ret) { + return ret; + } + } + return 0; + + case LDB_OP_NOT: /* attributes stored in single subtree */ + return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child); + + default: /* single attribute in tree */ + new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, tree->u.equality.attr); + talloc_free(*attrs); + *attrs = new_attrs; + return 0; + } + + return -1; +} + +static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree); + +/* Select a negated subtree that queries attributes in the local partition */ +static int map_subtree_select_local_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + struct ldb_parse_tree *child; + int ret; + + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + /* Generate new subtree */ + ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child); + if (ret) { + talloc_free(*new); + return ret; + } + + /* Prune tree without subtree */ + if (child == NULL) { + talloc_free(*new); + *new = NULL; + return 0; + } + + (*new)->u.isnot.child = child; + + return ret; +} + +/* Select a list of subtrees that query attributes in the local partition */ +static int map_subtree_select_local_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + int i, j, ret=0; + + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + /* Prepare list of subtrees */ + (*new)->u.list.num_elements = 0; + (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements); + if ((*new)->u.list.elements == NULL) { + map_oom(module); + talloc_free(*new); + return -1; + } + + /* Generate new list of subtrees */ + j = 0; + for (i = 0; i < tree->u.list.num_elements; i++) { + struct ldb_parse_tree *child; + ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]); + if (ret) { + talloc_free(*new); + return ret; + } + + if (child) { + (*new)->u.list.elements[j] = child; + j++; + } + } + + /* Prune tree without subtrees */ + if (j == 0) { + talloc_free(*new); + *new = NULL; + return 0; + } + + /* Fix subtree list size */ + (*new)->u.list.num_elements = j; + (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements); + + return ret; +} + +/* Select a simple subtree that queries attributes in the local partition */ +static int map_subtree_select_local_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + return 0; +} + +/* Select subtrees that query attributes in the local partition */ +static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + const struct ldb_map_context *data = map_get_context(module); + + if (tree == NULL) { + return 0; + } + + if (tree->operation == LDB_OP_NOT) { + return map_subtree_select_local_not(module, mem_ctx, new, tree); + } + + if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) { + return map_subtree_select_local_list(module, mem_ctx, new, tree); + } + + if (map_attr_check_remote(data, tree->u.equality.attr)) { + *new = NULL; + return 0; + } + + return map_subtree_select_local_simple(module, mem_ctx, new, tree); +} + +static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree); + +/* Collect a negated subtree that queries attributes in the remote partition */ +static int map_subtree_collect_remote_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + struct ldb_parse_tree *child; + int ret; + + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + /* Generate new subtree */ + ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child); + if (ret) { + talloc_free(*new); + return ret; + } + + /* Prune tree without subtree */ + if (child == NULL) { + talloc_free(*new); + *new = NULL; + return 0; + } + + (*new)->u.isnot.child = child; + + return ret; +} + +/* Collect a list of subtrees that query attributes in the remote partition */ +static int map_subtree_collect_remote_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + int i, j, ret=0; + + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + /* Prepare list of subtrees */ + (*new)->u.list.num_elements = 0; + (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements); + if ((*new)->u.list.elements == NULL) { + map_oom(module); + talloc_free(*new); + return -1; + } + + /* Generate new list of subtrees */ + j = 0; + for (i = 0; i < tree->u.list.num_elements; i++) { + struct ldb_parse_tree *child; + ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]); + if (ret) { + talloc_free(*new); + return ret; + } + + if (child) { + (*new)->u.list.elements[j] = child; + j++; + } + } + + /* Prune tree without subtrees */ + if (j == 0) { + talloc_free(*new); + *new = NULL; + return 0; + } + + /* Fix subtree list size */ + (*new)->u.list.num_elements = j; + (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements); + + return ret; +} + +/* Collect a simple subtree that queries attributes in the remote partition */ +int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map) +{ + const char *attr; + + /* Prepare new tree */ + *new = talloc(mem_ctx, struct ldb_parse_tree); + if (*new == NULL) { + map_oom(module); + return -1; + } + **new = *tree; + + if (map->type == MAP_KEEP) { + /* Nothing to do here */ + return 0; + } + + /* Store attribute and value in new tree */ + switch (tree->operation) { + case LDB_OP_PRESENT: + attr = map_attr_map_local(*new, map, tree->u.present.attr); + (*new)->u.present.attr = attr; + break; + case LDB_OP_SUBSTRING: + { + attr = map_attr_map_local(*new, map, tree->u.substring.attr); + (*new)->u.substring.attr = attr; + break; + } + case LDB_OP_EQUALITY: + attr = map_attr_map_local(*new, map, tree->u.equality.attr); + (*new)->u.equality.attr = attr; + break; + case LDB_OP_LESS: + case LDB_OP_GREATER: + case LDB_OP_APPROX: + attr = map_attr_map_local(*new, map, tree->u.comparison.attr); + (*new)->u.comparison.attr = attr; + break; + case LDB_OP_EXTENDED: + attr = map_attr_map_local(*new, map, tree->u.extended.attr); + (*new)->u.extended.attr = attr; + break; + default: /* unknown kind of simple subtree */ + talloc_free(*new); + return -1; + } + + if (attr == NULL) { + talloc_free(*new); + *new = NULL; + return 0; + } + + if (map->type == MAP_RENAME) { + /* Nothing more to do here, the attribute has been renamed */ + return 0; + } + + /* Store attribute and value in new tree */ + switch (tree->operation) { + case LDB_OP_PRESENT: + break; + case LDB_OP_SUBSTRING: + { + int i; + /* Map value */ + (*new)->u.substring.chunks = NULL; + for (i=0; tree->u.substring.chunks[i]; i++) { + (*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2); + if (!(*new)->u.substring.chunks) { + talloc_free(*new); + *new = NULL; + return 0; + } + (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val); + if (!(*new)->u.substring.chunks[i]) { + talloc_free(*new); + *new = NULL; + return 0; + } + *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]); + (*new)->u.substring.chunks[i+1] = NULL; + } + break; + } + case LDB_OP_EQUALITY: + (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value); + break; + case LDB_OP_LESS: + case LDB_OP_GREATER: + case LDB_OP_APPROX: + (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value); + break; + case LDB_OP_EXTENDED: + (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value); + (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id); + break; + default: /* unknown kind of simple subtree */ + talloc_free(*new); + return -1; + } + + return 0; +} + +/* Collect subtrees that query attributes in the remote partition */ +static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + const struct ldb_map_context *data = map_get_context(module); + const struct ldb_map_attribute *map; + + if (tree == NULL) { + return 0; + } + + if (tree->operation == LDB_OP_NOT) { + return map_subtree_collect_remote_not(module, mem_ctx, new, tree); + } + + if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) { + return map_subtree_collect_remote_list(module, mem_ctx, new, tree); + } + + if (!map_attr_check_remote(data, tree->u.equality.attr)) { + *new = NULL; + return 0; + } + + map = map_attr_find_local(data, tree->u.equality.attr); + if (map->convert_operator) { + return map->convert_operator(module, mem_ctx, new, tree); + } + + if (map->type == MAP_GENERATE) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " + "Skipping attribute '%s': " + "'convert_operator' not set\n", + tree->u.equality.attr); + *new = NULL; + return 0; + } + + return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map); +} + +/* Split subtrees that query attributes in the local partition from + * those that query the remote partition. */ +static int ldb_parse_tree_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, struct ldb_parse_tree **local_tree, struct ldb_parse_tree **remote_tree, const struct ldb_parse_tree *tree) +{ + int ret; + + *local_tree = NULL; + *remote_tree = NULL; + + /* No original tree */ + if (tree == NULL) { + return 0; + } + + /* Generate local tree */ + ret = map_subtree_select_local(module, local_ctx, local_tree, tree); + if (ret) { + return ret; + } + + /* Generate remote tree */ + ret = map_subtree_collect_remote(module, remote_ctx, remote_tree, tree); + if (ret) { + talloc_free(*local_tree); + return ret; + } + + return 0; +} + +/* Collect a list of attributes required either explicitly from a + * given list or implicitly from a given parse tree; split the + * collected list into local and remote parts. */ +static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac, + const char * const *search_attrs, + const struct ldb_parse_tree *tree) +{ + void *tmp_ctx; + const char **tree_attrs; + const char **remote_attrs; + const char **local_attrs; + int ret; + + /* There is no tree, just partition the searched attributes */ + if (tree == NULL) { + ret = map_attrs_partition(module, ac, + &local_attrs, &remote_attrs, search_attrs); + if (ret == 0) { + ac->local_attrs = local_attrs; + ac->remote_attrs = remote_attrs; + ac->all_attrs = search_attrs; + } + return ret; + } + + /* Create context for temporary memory */ + tmp_ctx = talloc_new(ac); + if (tmp_ctx == NULL) { + goto oom; + } + + /* Prepare list of attributes from tree */ + tree_attrs = talloc_array(tmp_ctx, const char *, 1); + if (tree_attrs == NULL) { + talloc_free(tmp_ctx); + goto oom; + } + tree_attrs[0] = NULL; + + /* Collect attributes from tree */ + ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree); + if (ret) { + goto done; + } + + /* Merge attributes from search operation */ + ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs); + if (ret) { + goto done; + } + + /* Split local from remote attributes */ + ret = map_attrs_partition(module, ac, &local_attrs, + &remote_attrs, tree_attrs); + + if (ret == 0) { + ac->local_attrs = local_attrs; + ac->remote_attrs = remote_attrs; + talloc_steal(ac, tree_attrs); + ac->all_attrs = tree_attrs; + } +done: + /* Free temporary memory */ + talloc_free(tmp_ctx); + return ret; + +oom: + map_oom(module); + return -1; +} + + +/* Outbound requests: search + * ========================= */ + +/* Pass a merged search result up the callback chain. */ +int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, struct ldb_reply *ares) +{ + int i; + + /* No callback registered, stop */ + if (req->callback == NULL) { + return LDB_SUCCESS; + } + + /* Only records need special treatment */ + if (ares->type != LDB_REPLY_ENTRY) { + return req->callback(ldb, req->context, ares); + } + + /* Merged result doesn't match original query, skip */ + if (!ldb_match_msg(ldb, ares->message, req->op.search.tree, req->op.search.base, req->op.search.scope)) { + ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: " + "Skipping record '%s': " + "doesn't match original search\n", + ldb_dn_get_linearized(ares->message->dn)); + return LDB_SUCCESS; + } + + /* Limit result to requested attrs */ + if ((req->op.search.attrs) && (!ldb_attr_in_list(req->op.search.attrs, "*"))) { + for (i = 0; i < ares->message->num_elements; ) { + struct ldb_message_element *el = &ares->message->elements[i]; + if (!ldb_attr_in_list(req->op.search.attrs, el->name)) { + ldb_msg_remove_element(ares->message, el); + } else { + i++; + } + } + } + + return req->callback(ldb, req->context, ares); +} + +/* Merge the remote and local parts of a search result. */ +int map_local_merge_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct map_search_context *sc; + int ret; + + if (context == NULL || ares == NULL) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " + "NULL Context or Result in `map_local_merge_callback`")); + return LDB_ERR_OPERATIONS_ERROR; + } + + sc = talloc_get_type(context, struct map_search_context); + + switch (ares->type) { + case LDB_REPLY_ENTRY: + /* We have already found a local record */ + if (sc->local_res) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " + "Too many results to base search for local entry")); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Store local result */ + sc->local_res = ares; + + /* Merge remote into local message */ + ret = ldb_msg_merge_local(sc->ac->module, ares->message, sc->remote_res->message); + if (ret) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + return map_up_callback(ldb, sc->ac->orig_req, ares); + + case LDB_REPLY_DONE: + /* No local record found, continue with remote record */ + if (sc->local_res == NULL) { + return map_up_callback(ldb, sc->ac->orig_req, sc->remote_res); + } + return LDB_SUCCESS; + + default: + ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " + "Unexpected result type in base search for local entry")); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } +} + +/* Search the local part of a remote search result. */ +int map_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct map_context *ac; + struct map_search_context *sc; + struct ldb_request *req; + int ret; + + if (context == NULL || ares == NULL) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " + "NULL Context or Result in `map_remote_search_callback`")); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac = talloc_get_type(context, struct map_context); + + /* It's not a record, stop searching */ + if (ares->type != LDB_REPLY_ENTRY) { + return map_up_callback(ldb, ac->orig_req, ares); + } + + /* Map result record into a local message */ + ret = map_reply_remote(ac, ares); + if (ret) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* There is no local db, stop searching */ + if (!map_check_local_db(ac->module)) { + return map_up_callback(ldb, ac->orig_req, ares); + } + + /* Prepare local search context */ + sc = map_init_search_context(ac, ares); + if (sc == NULL) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Prepare local search request */ + /* TODO: use GUIDs here instead? */ + + ac->search_reqs = talloc_realloc(ac, ac->search_reqs, struct ldb_request *, ac->num_searches + 2); + if (ac->search_reqs == NULL) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->search_reqs[ac->num_searches] + = req = map_search_base_req(ac, ares->message->dn, + NULL, NULL, sc, map_local_merge_callback); + if (req == NULL) { + talloc_free(sc); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->num_searches++; + ac->search_reqs[ac->num_searches] = NULL; + + return ldb_next_request(ac->module, req); +} + +/* Search a record. */ +int map_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_handle *h; + struct map_context *ac; + struct ldb_parse_tree *local_tree, *remote_tree; + int ret; + + const char *wildcard[] = { "*", NULL }; + const char * const *attrs; + + if (!module->private_data) /* if we're not yet initialized, go to the next module */ + return ldb_next_request(module, req); + + /* Do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.search.base)) + return ldb_next_request(module, req); + + /* No mapping requested, skip to next module */ + if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) { + return ldb_next_request(module, req); + } + + /* TODO: How can we be sure about which partition we are + * targetting when there is no search base? */ + + /* Prepare context and handle */ + h = map_init_handle(req, module); + if (h == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct map_context); + + ac->search_reqs = talloc_array(ac, struct ldb_request *, 2); + if (ac->search_reqs == NULL) { + talloc_free(h); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->num_searches = 1; + ac->search_reqs[1] = NULL; + + /* Prepare the remote operation */ + ac->search_reqs[0] = talloc(ac, struct ldb_request); + if (ac->search_reqs[0] == NULL) { + goto oom; + } + + *(ac->search_reqs[0]) = *req; /* copy the request */ + + ac->search_reqs[0]->handle = h; /* return our own handle to deal with this call */ + + ac->search_reqs[0]->context = ac; + ac->search_reqs[0]->callback = map_remote_search_callback; + + /* It is easier to deal with the two different ways of + * expressing the wildcard in the same codepath */ + attrs = req->op.search.attrs; + if (attrs == NULL) { + attrs = wildcard; + } + + /* Split local from remote attrs */ + ret = map_attrs_collect_and_partition(module, ac, + attrs, req->op.search.tree); + if (ret) { + goto failed; + } + + ac->search_reqs[0]->op.search.attrs = ac->remote_attrs; + + /* Split local from remote tree */ + ret = ldb_parse_tree_partition(module, ac, ac->search_reqs[0], + &local_tree, &remote_tree, + req->op.search.tree); + if (ret) { + goto failed; + } + + if (((local_tree != NULL) && (remote_tree != NULL)) && + (!ldb_parse_tree_check_splittable(req->op.search.tree))) { + /* The query can't safely be split, enumerate the remote partition */ + local_tree = NULL; + remote_tree = NULL; + } + + if (local_tree == NULL) { + /* Construct default local parse tree */ + local_tree = talloc_zero(ac, struct ldb_parse_tree); + if (local_tree == NULL) { + map_oom(ac->module); + goto failed; + } + + local_tree->operation = LDB_OP_PRESENT; + local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED); + } + if (remote_tree == NULL) { + /* Construct default remote parse tree */ + remote_tree = ldb_parse_tree(ac->search_reqs[0], NULL); + if (remote_tree == NULL) { + goto failed; + } + } + + ac->local_tree = local_tree; + ac->search_reqs[0]->op.search.tree = remote_tree; + + ldb_set_timeout_from_prev_req(module->ldb, req, ac->search_reqs[0]); + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->step = MAP_SEARCH_REMOTE; + + ret = ldb_next_remote_request(module, ac->search_reqs[0]); + if (ret == LDB_SUCCESS) { + req->handle = h; + } + return ret; + +oom: + map_oom(module); +failed: + talloc_free(h); + return LDB_ERR_OPERATIONS_ERROR; +} diff --git a/ldb/ldb_map/ldb_map_private.h b/ldb/ldb_map/ldb_map_private.h new file mode 100644 index 000000000..58a9f2704 --- /dev/null +++ b/ldb/ldb_map/ldb_map_private.h @@ -0,0 +1,110 @@ + +/* A handy macro to report Out of Memory conditions */ +#define map_oom(module) ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); + +/* The type of search callback functions */ +typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_reply *); + +/* The special DN from which the local and remote base DNs are fetched */ +#define MAP_DN_NAME "@MAP" +#define MAP_DN_FROM "@FROM" +#define MAP_DN_TO "@TO" + +/* Private data structures + * ======================= */ + +/* Context data for mapped requests */ +struct map_context { + enum map_step { + MAP_SEARCH_REMOTE, + MAP_ADD_REMOTE, + MAP_ADD_LOCAL, + MAP_SEARCH_SELF_MODIFY, + MAP_MODIFY_REMOTE, + MAP_MODIFY_LOCAL, + MAP_SEARCH_SELF_DELETE, + MAP_DELETE_REMOTE, + MAP_DELETE_LOCAL, + MAP_SEARCH_SELF_RENAME, + MAP_RENAME_REMOTE, + MAP_RENAME_FIXUP, + MAP_RENAME_LOCAL + } step; + + struct ldb_module *module; + + struct ldb_dn *local_dn; + const struct ldb_parse_tree *local_tree; + const char * const *local_attrs; + const char * const *remote_attrs; + const char * const *all_attrs; + + struct ldb_request *orig_req; + struct ldb_request *local_req; + struct ldb_request *remote_req; + struct ldb_request *down_req; + struct ldb_request *search_req; + + /* for search, we may have a lot of contexts */ + int num_searches; + struct ldb_request **search_reqs; +}; + +/* Context data for mapped search requests */ +struct map_search_context { + struct map_context *ac; + struct ldb_reply *local_res; + struct ldb_reply *remote_res; +}; + + +/* Common operations + * ================= */ + +/* The following definitions come from lib/ldb/modules/ldb_map.c */ +const struct ldb_map_context *map_get_context(struct ldb_module *module); +struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares); +struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module); + +int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request); + +bool map_check_local_db(struct ldb_module *module); +bool map_attr_check_remote(const struct ldb_map_context *data, const char *attr); +bool ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn); + +const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name); +const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name); + +const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr); +const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr); +int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attrs, const char * const *more_attrs); + +struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val); +struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val); + +struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn); +struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn); +struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn); + +struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback); +struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn); +struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn); + +int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map); + +/* LDB Requests + * ============ */ + +/* The following definitions come from lib/ldb/modules/ldb_map_inbound.c */ +int map_add_do_remote(struct ldb_handle *handle); +int map_add_do_local(struct ldb_handle *handle); + +int map_modify_do_remote(struct ldb_handle *handle); +int map_modify_do_local(struct ldb_handle *handle); + +int map_delete_do_remote(struct ldb_handle *handle); +int map_delete_do_local(struct ldb_handle *handle); + +int map_rename_do_remote(struct ldb_handle *handle); +int map_rename_do_fixup(struct ldb_handle *handle); +int map_rename_do_local(struct ldb_handle *handle); diff --git a/ldb/ldb_sqlite3/README b/ldb/ldb_sqlite3/README new file mode 100644 index 000000000..6cda0a775 --- /dev/null +++ b/ldb/ldb_sqlite3/README @@ -0,0 +1,7 @@ +trees.ps contains an explanation of the Genealogical Representation of Trees +in Databases which is being used in ldb_sqlite3. Note that we use fgID +representation with 4 bytes per level, so we can represent 6.5E+08 subclasses +of any object class. This should be adequate for our purposes. :-) + +The following document is the primary basis for the schema currently being +used here: http://www.research.ibm.com/journal/sj/392/shi.html diff --git a/ldb/ldb_sqlite3/base160.c b/ldb/ldb_sqlite3/base160.c new file mode 100644 index 000000000..423e2b684 --- /dev/null +++ b/ldb/ldb_sqlite3/base160.c @@ -0,0 +1,154 @@ +/* + base160 code used by ldb_sqlite3 + + Copyright (C) 2004 Derrell Lipman + + 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 . +*/ + + +/* + * ldb_sqlite3_base160() + * + * Convert an integer value to a string containing the base 160 representation + * of the integer. We always convert to a string representation that is 4 + * bytes in length, and we always null terminate. + * + * Parameters: + * val -- + * The value to be converted + * + * result -- + * Buffer in which the result is to be placed + * + * Returns: + * nothing + */ +static unsigned char base160tab[161] = +{ + 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , /* 0-9 */ + 58 , 59 , 65 , 66 , 67 , 68 , 69 , 70 , 71 , 72 , /* : ; A-H */ + 73 , 74 , 75 , 76 , 77 , 78 , 79 , 80 , 81 , 82 , /* I-R */ + 83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 97 , 98 , /* S-Z , a-b */ + 99 , 100, 101, 102, 103, 104, 105, 106, 107, 108, /* c-l */ + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, /* m-v */ + 119, 120, 121, 122, 160, 161, 162, 163, 164, 165, /* w-z, latin1 */ + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, /* latin1 */ + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, /* latin1 */ + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, /* latin1 */ + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, /* latin1 */ + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, /* latin1 */ + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, /* latin1 */ + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, /* latin1 */ + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, /* latin1 */ + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, /* latin1 */ + '\0' +}; + + +/* + * lsqlite3_base160() + * + * Convert an unsigned long integer into a base160 representation of the + * number. + * + * Parameters: + * val -- + * value to be converted + * + * result -- + * character array, 5 bytes long, into which the base160 representation + * will be placed. The result will be a four-digit representation of the + * number (with leading zeros prepended as necessary), and null + * terminated. + * + * Returns: + * Nothing + */ +void +lsqlite3_base160(unsigned long val, + unsigned char result[5]) +{ + int i; + + for (i = 3; i >= 0; i--) { + + result[i] = base160tab[val % 160]; + val /= 160; + } + + result[4] = '\0'; +} + + +/* + * lsqlite3_base160Next() + * + * Retrieve the next-greater number in the base160 sequence for the terminal + * tree node (the last four digits). Only one tree level (four digits) are + * operated on. + * + * Parameters: + * base160 -- a character array containing either an empty string (in which + * case no operation is performed), or a string of base160 digits + * with a length of a multiple of four digits. + * + * Upon return, the trailing four digits (one tree level) will + * have been incremented by 1. + * + * Returns: + * base160 -- the modified array + */ +char * +lsqlite3_base160Next(char base160[]) +{ + int i; + int len; + unsigned char * pTab; + char * pBase160 = base160; + + /* + * We need a minimum of four digits, and we will always get a multiple of + * four digits. + */ + if (len = strlen(pBase160)) >= 4) + { + pBase160 += strlen(pBase160) - 1; + + /* We only carry through four digits: one level in the tree */ + for (i = 0; i < 4; i++) { + + /* What base160 value does this digit have? */ + pTab = strchr(base160tab, *pBase160); + + /* Is there a carry? */ + if (pTab < base160tab + sizeof(base160tab) - 1) { + + /* Nope. Just increment this value and we're done. */ + *pBase160 = *++pTab; + break; + } else { + + /* + * There's a carry. This value gets base160tab[0], we + * decrement the buffer pointer to get the next higher-order + * digit, and continue in the loop. + */ + *pBase160-- = base160tab[0]; + } + } + } + + return base160; +} diff --git a/ldb/ldb_sqlite3/ldb_sqlite3.c b/ldb/ldb_sqlite3/ldb_sqlite3.c new file mode 100644 index 000000000..a0e63c8da --- /dev/null +++ b/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -0,0 +1,1876 @@ +/* + ldb database library + + Copyright (C) Derrell Lipman 2005 + Copyright (C) Simo Sorce 2005-2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb sqlite3 backend + * + * Description: core files for SQLITE3 backend + * + * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend) + */ + +#include "ldb_includes.h" + +#include + +struct lsqlite3_private { + int trans_count; + char **options; + sqlite3 *sqlite; +}; + +struct lsql_context { + struct ldb_module *module; + + /* search stuff */ + long long current_eid; + const char * const * attrs; + struct ldb_reply *ares; + + /* async stuff */ + void *context; + int (*callback)(struct ldb_context *, void *, struct ldb_reply *); +}; + +static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, + struct ldb_module *module, + struct ldb_request *req) +{ + struct lsql_context *ac; + struct ldb_handle *h; + + h = talloc_zero(lsqlite3, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc(h, struct lsql_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->module = module; + ac->context = req->context; + ac->callback = req->callback; + + return h; +} + +/* + * Macros used throughout + */ + +#ifndef FALSE +# define FALSE (0) +# define TRUE (! FALSE) +#endif + +#define RESULT_ATTR_TABLE "temp_result_attrs" + +//#define TEMPTAB /* for testing, create non-temporary table */ +#define TEMPTAB "TEMPORARY" + +/* + * Static variables + */ +sqlite3_stmt * stmtGetEID = NULL; + +static char *lsqlite3_tprintf(TALLOC_CTX *mem_ctx, const char *fmt, ...) +{ + char *str, *ret; + va_list ap; + + va_start(ap, fmt); + str = sqlite3_vmprintf(fmt, ap); + va_end(ap); + + if (str == NULL) return NULL; + + ret = talloc_strdup(mem_ctx, str); + if (ret == NULL) { + sqlite3_free(str); + return NULL; + } + + sqlite3_free(str); + return ret; +} + +static char base160tab[161] = { + 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */ + 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */ + 73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 , /* I-R */ + 83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 ,97 ,98 , /* S-Z , a-b */ + 99 ,100,101,102,103,104,105,106,107,108, /* c-l */ + 109,110,111,112,113,114,115,116,117,118, /* m-v */ + 119,120,121,122,160,161,162,163,164,165, /* w-z, latin1 */ + 166,167,168,169,170,171,172,173,174,175, /* latin1 */ + 176,177,178,179,180,181,182,183,184,185, /* latin1 */ + 186,187,188,189,190,191,192,193,194,195, /* latin1 */ + 196,197,198,199,200,201,202,203,204,205, /* latin1 */ + 206,207,208,209,210,211,212,213,214,215, /* latin1 */ + 216,217,218,219,220,221,222,223,224,225, /* latin1 */ + 226,227,228,229,230,231,232,233,234,235, /* latin1 */ + 236,237,238,239,240,241,242,243,244,245, /* latin1 */ + 246,247,248,249,250,251,252,253,254,255, /* latin1 */ + '\0' +}; + + +/* + * base160() + * + * Convert an unsigned long integer into a base160 representation of the + * number. + * + * Parameters: + * val -- + * value to be converted + * + * result -- + * character array, 5 bytes long, into which the base160 representation + * will be placed. The result will be a four-digit representation of the + * number (with leading zeros prepended as necessary), and null + * terminated. + * + * Returns: + * Nothing + */ +static void +base160_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv) +{ + int i; + long long val; + char result[5]; + + val = sqlite3_value_int64(argv[0]); + + for (i = 3; i >= 0; i--) { + + result[i] = base160tab[val % 160]; + val /= 160; + } + + result[4] = '\0'; + + sqlite3_result_text(hContext, result, -1, SQLITE_TRANSIENT); +} + + +/* + * base160next_sql() + * + * This function enhances sqlite by adding a "base160_next()" function which is + * accessible via queries. + * + * Retrieve the next-greater number in the base160 sequence for the terminal + * tree node (the last four digits). Only one tree level (four digits) is + * operated on. + * + * Input: + * A character string: either an empty string (in which case no operation is + * performed), or a string of base160 digits with a length of a multiple of + * four digits. + * + * Output: + * Upon return, the trailing four digits (one tree level) will have been + * incremented by 1. + */ +static void +base160next_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv) +{ + int i; + int len; + char * pTab; + char * pBase160 = strdup((const char *)sqlite3_value_text(argv[0])); + char * pStart = pBase160; + + /* + * We need a minimum of four digits, and we will always get a multiple + * of four digits. + */ + if (pBase160 != NULL && + (len = strlen(pBase160)) >= 4 && + len % 4 == 0) { + + if (pBase160 == NULL) { + + sqlite3_result_null(hContext); + return; + } + + pBase160 += strlen(pBase160) - 1; + + /* We only carry through four digits: one level in the tree */ + for (i = 0; i < 4; i++) { + + /* What base160 value does this digit have? */ + pTab = strchr(base160tab, *pBase160); + + /* Is there a carry? */ + if (pTab < base160tab + sizeof(base160tab) - 1) { + + /* + * Nope. Just increment this value and we're + * done. + */ + *pBase160 = *++pTab; + break; + } else { + + /* + * There's a carry. This value gets + * base160tab[0], we decrement the buffer + * pointer to get the next higher-order digit, + * and continue in the loop. + */ + *pBase160-- = base160tab[0]; + } + } + + sqlite3_result_text(hContext, + pStart, + strlen(pStart), + free); + } else { + sqlite3_result_value(hContext, argv[0]); + if (pBase160 != NULL) { + free(pBase160); + } + } +} + +static char *parsetree_to_sql(struct ldb_module *module, + void *mem_ctx, + const struct ldb_parse_tree *t) +{ + const struct ldb_schema_attribute *a; + struct ldb_val value, subval; + char *wild_card_string; + char *child, *tmp; + char *ret = NULL; + char *attr; + int i; + + + switch(t->operation) { + case LDB_OP_AND: + + tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]); + if (tmp == NULL) return NULL; + + for (i = 1; i < t->u.list.num_elements; i++) { + + child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); + if (child == NULL) return NULL; + + tmp = talloc_asprintf_append(tmp, " INTERSECT %s ", child); + if (tmp == NULL) return NULL; + } + + ret = talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )\n", tmp); + + return ret; + + case LDB_OP_OR: + + tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]); + if (tmp == NULL) return NULL; + + for (i = 1; i < t->u.list.num_elements; i++) { + + child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); + if (child == NULL) return NULL; + + tmp = talloc_asprintf_append(tmp, " UNION %s ", child); + if (tmp == NULL) return NULL; + } + + return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s ) ", tmp); + + case LDB_OP_NOT: + + child = parsetree_to_sql(module, mem_ctx, t->u.isnot.child); + if (child == NULL) return NULL; + + return talloc_asprintf(mem_ctx, + "SELECT eid FROM ldb_entry " + "WHERE eid NOT IN ( %s ) ", child); + + case LDB_OP_EQUALITY: + /* + * For simple searches, we want to retrieve the list of EIDs that + * match the criteria. + */ + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + a = ldb_schema_attribute_by_name(module->ldb, attr); + + /* Get a canonicalised copy of the data */ + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + if (strcasecmp(t->u.equality.attr, "dn") == 0) { + /* DN query is a special ldb case */ + const char *cdn = ldb_dn_get_casefold( + ldb_dn_new(mem_ctx, module->ldb, + (const char *)value.data)); + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_entry " + "WHERE norm_dn = '%q'", cdn); + + } else { + /* A normal query. */ + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND norm_attr_value = '%q'", + attr, + value.data); + + } + + case LDB_OP_SUBSTRING: + + wild_card_string = talloc_strdup(mem_ctx, + (t->u.substring.start_with_wildcard)?"*":""); + if (wild_card_string == NULL) return NULL; + + for (i = 0; t->u.substring.chunks[i]; i++) { + wild_card_string = talloc_asprintf_append(wild_card_string, "%s*", + t->u.substring.chunks[i]->data); + if (wild_card_string == NULL) return NULL; + } + + if ( ! t->u.substring.end_with_wildcard ) { + /* remove last wildcard */ + wild_card_string[strlen(wild_card_string) - 1] = '\0'; + } + + attr = ldb_attr_casefold(mem_ctx, t->u.substring.attr); + if (attr == NULL) return NULL; + a = ldb_schema_attribute_by_name(module->ldb, attr); + + subval.data = (void *)wild_card_string; + subval.length = strlen(wild_card_string) + 1; + + /* Get a canonicalised copy of the data */ + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(subval), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND norm_attr_value GLOB '%q'", + attr, + value.data); + + case LDB_OP_GREATER: + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + a = ldb_schema_attribute_by_name(module->ldb, attr); + + /* Get a canonicalised copy of the data */ + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND ldap_compare(norm_attr_value, '>=', '%q', '%q') ", + attr, + value.data, + attr); + + case LDB_OP_LESS: + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + a = ldb_schema_attribute_by_name(module->ldb, attr); + + /* Get a canonicalised copy of the data */ + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND ldap_compare(norm_attr_value, '<=', '%q', '%q') ", + attr, + value.data, + attr); + + case LDB_OP_PRESENT: + if (strcasecmp(t->u.present.attr, "dn") == 0) { + return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); + } + + attr = ldb_attr_casefold(mem_ctx, t->u.present.attr); + if (attr == NULL) return NULL; + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' ", + attr); + + case LDB_OP_APPROX: + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + a = ldb_schema_attribute_by_name(module->ldb, attr); + + /* Get a canonicalised copy of the data */ + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND ldap_compare(norm_attr_value, '~%', 'q', '%q') ", + attr, + value.data, + attr); + + case LDB_OP_EXTENDED: +#warning "work out how to handle bitops" + return NULL; + + default: + break; + }; + + /* should never occur */ + abort(); + return NULL; +} + +/* + * query_int() + * + * This function is used for the common case of queries that return a single + * integer value. + * + * NOTE: If more than one value is returned by the query, all but the first + * one will be ignored. + */ +static int +query_int(const struct lsqlite3_private * lsqlite3, + long long * pRet, + const char * pSql, + ...) +{ + int ret; + int bLoop; + char * p; + sqlite3_stmt * pStmt; + va_list args; + + /* Begin access to variable argument list */ + va_start(args, pSql); + + /* Format the query */ + if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { + return SQLITE_NOMEM; + } + + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { + + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + p, + -1, + &pStmt, + NULL)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + continue; + } else if (ret != SQLITE_OK) { + break; + } + + /* One row expected */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_ROW) { + (void) sqlite3_finalize(pStmt); + break; + } + + /* Get the value to be returned */ + *pRet = sqlite3_column_int64(pStmt, 0); + + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + break; + } + + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + bLoop = FALSE; + } + + /* All done with variable argument list */ + va_end(args); + + + /* Free the memory we allocated for our query string */ + sqlite3_free(p); + + return ret; +} + +/* + * This is a bad hack to support ldap style comparisons whithin sqlite. + * val is the attribute in the row currently under test + * func is the desired test "<=" ">=" "~" ":" + * cmp is the value to compare against (eg: "test") + * attr is the attribute name the value of which we want to test + */ + +static void lsqlite3_compare(sqlite3_context *ctx, int argc, + sqlite3_value **argv) +{ + struct ldb_context *ldb = (struct ldb_context *)sqlite3_user_data(ctx); + const char *val = (const char *)sqlite3_value_text(argv[0]); + const char *func = (const char *)sqlite3_value_text(argv[1]); + const char *cmp = (const char *)sqlite3_value_text(argv[2]); + const char *attr = (const char *)sqlite3_value_text(argv[3]); + const struct ldb_schema_attribute *a; + struct ldb_val valX; + struct ldb_val valY; + int ret; + + switch (func[0]) { + /* greater */ + case '>': /* >= */ + a = ldb_schema_attribute_by_name(ldb, attr); + valX.data = (void *)cmp; + valX.length = strlen(cmp); + valY.data = (void *)val; + valY.length = strlen(val); + ret = a->syntax->comparison_fn(ldb, ldb, &valY, &valX); + if (ret >= 0) + sqlite3_result_int(ctx, 1); + else + sqlite3_result_int(ctx, 0); + return; + + /* lesser */ + case '<': /* <= */ + a = ldb_schema_attribute_by_name(ldb, attr); + valX.data = (void *)cmp; + valX.length = strlen(cmp); + valY.data = (void *)val; + valY.length = strlen(val); + ret = a->syntax->comparison_fn(ldb, ldb, &valY, &valX); + if (ret <= 0) + sqlite3_result_int(ctx, 1); + else + sqlite3_result_int(ctx, 0); + return; + + /* approx */ + case '~': + /* TODO */ + sqlite3_result_int(ctx, 0); + return; + + /* bitops */ + case ':': + /* TODO */ + sqlite3_result_int(ctx, 0); + return; + + default: + break; + } + + sqlite3_result_error(ctx, "Value must start with a special operation char (<>~:)!", -1); + return; +} + + +/* rename a record */ +static int lsqlite3_safe_rollback(sqlite3 *sqlite) +{ + char *errmsg; + int ret; + + /* execute */ + ret = sqlite3_exec(sqlite, "ROLLBACK;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_safe_rollback: Error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + + return 0; +} + +/* return an eid as result */ +static int lsqlite3_eid_callback(void *result, int col_num, char **cols, char **names) +{ + long long *eid = (long long *)result; + + if (col_num != 1) return SQLITE_ABORT; + if (strcasecmp(names[0], "eid") != 0) return SQLITE_ABORT; + + *eid = atoll(cols[0]); + return SQLITE_OK; +} + +/* + * add a single set of ldap message values to a ldb_message + */ +static int lsqlite3_search_callback(void *result, int col_num, char **cols, char **names) +{ + struct ldb_handle *handle = talloc_get_type(result, struct ldb_handle); + struct lsql_context *ac = talloc_get_type(handle->private_data, struct lsql_context); + struct ldb_message *msg; + long long eid; + int i; + + /* eid, dn, attr_name, attr_value */ + if (col_num != 4) + return SQLITE_ABORT; + + eid = atoll(cols[0]); + + if (eid != ac->current_eid) { /* here begin a new entry */ + + /* call the async callback for the last entry + * except the first time */ + if (ac->current_eid != 0) { + ac->ares->message = ldb_msg_canonicalize(ac->module->ldb, ac->ares->message); + if (ac->ares->message == NULL) + return SQLITE_ABORT; + + handle->status = ac->callback(ac->module->ldb, ac->context, ac->ares); + if (handle->status != LDB_SUCCESS) + return SQLITE_ABORT; + } + + /* start over */ + ac->ares = talloc_zero(ac, struct ldb_reply); + if (!ac->ares) + return SQLITE_ABORT; + + ac->ares->message = ldb_msg_new(ac->ares); + if (!ac->ares->message) + return SQLITE_ABORT; + + ac->ares->type = LDB_REPLY_ENTRY; + ac->current_eid = eid; + } + + msg = ac->ares->message; + + if (msg->dn == NULL) { + msg->dn = ldb_dn_new(msg, ac->module->ldb, cols[1]); + if (msg->dn == NULL) + return SQLITE_ABORT; + } + + if (ac->attrs) { + int found = 0; + for (i = 0; ac->attrs[i]; i++) { + if (strcasecmp(cols[2], ac->attrs[i]) == 0) { + found = 1; + break; + } + } + if (!found) return SQLITE_OK; + } + + if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0) { + return SQLITE_ABORT; + } + + return SQLITE_OK; +} + + +/* + * lsqlite3_get_eid() + * lsqlite3_get_eid_ndn() + * + * These functions are used for the very common case of retrieving an EID value + * given a (normalized) DN. + */ + +static long long lsqlite3_get_eid_ndn(sqlite3 *sqlite, void *mem_ctx, const char *norm_dn) +{ + char *errmsg; + char *query; + long long eid = -1; + long long ret; + + /* get object eid */ + query = lsqlite3_tprintf(mem_ctx, "SELECT eid " + "FROM ldb_entry " + "WHERE norm_dn = '%q';", norm_dn); + if (query == NULL) return -1; + + ret = sqlite3_exec(sqlite, query, lsqlite3_eid_callback, &eid, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_get_eid: Fatal Error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + + return eid; +} + +static long long lsqlite3_get_eid(struct ldb_module *module, struct ldb_dn *dn) +{ + TALLOC_CTX *local_ctx; + struct lsqlite3_private *lsqlite3 = module->private_data; + long long eid = -1; + char *cdn; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(dn)) { + return -1; + } + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_get_eid local context"); + if (local_ctx == NULL) { + return -1; + } + + cdn = ldb_dn_alloc_casefold(local_ctx, dn); + if (!cdn) goto done; + + eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn); + +done: + talloc_free(local_ctx); + return eid; +} + +/* + * Interface functions referenced by lsqlite3_ops + */ + +/* search for matching records, by tree */ +int lsql_search(struct ldb_module *module, struct ldb_request *req) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + char *norm_basedn; + char *sqlfilter; + char *errmsg; + char *query = NULL; + int ret; + + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + + if ((( ! ldb_dn_is_valid(req->op.search.base)) || ldb_dn_is_null(req->op.search.base)) && + (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) + return LDB_ERR_OPERATIONS_ERROR; + + if (req->op.search.base) { + norm_basedn = ldb_dn_alloc_casefold(lsql_ac, req->op.search.base); + if (norm_basedn == NULL) { + ret = LDB_ERR_INVALID_DN_SYNTAX; + goto failed; + } + } else norm_basedn = talloc_strdup(lsql_ac, ""); + + /* Convert filter into a series of SQL conditions (constraints) */ + sqlfilter = parsetree_to_sql(module, lsql_ac, req->op.search.tree); + + switch(req->op.search.scope) { + case LDB_SCOPE_DEFAULT: + case LDB_SCOPE_SUBTREE: + if (*norm_basedn != '\0') { + query = lsqlite3_tprintf(lsql_ac, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE (ldb_entry.norm_dn GLOB('*,%q')\n" + " OR ldb_entry.norm_dn = '%q')\n" + " AND ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + norm_basedn, + sqlfilter); + } else { + query = lsqlite3_tprintf(lsql_ac, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " ORDER BY entry.eid ASC;", + sqlfilter); + } + + break; + + case LDB_SCOPE_BASE: + query = lsqlite3_tprintf(lsql_ac, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE ldb_entry.norm_dn = '%q'\n" + " AND ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + sqlfilter); + break; + + case LDB_SCOPE_ONELEVEL: + query = lsqlite3_tprintf(lsql_ac, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE norm_dn GLOB('*,%q')\n" + " AND NOT norm_dn GLOB('*,*,%q')\n" + " AND ldb_entry.eid IN\n(%s)\n" + " )\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + norm_basedn, + sqlfilter); + break; + } + + if (query == NULL) { + goto failed; + } + + /* * / + printf ("%s\n", query); + / * */ + + lsql_ac->current_eid = 0; + lsql_ac->attrs = req->op.search.attrs; + lsql_ac->ares = NULL; + + req->handle->state = LDB_ASYNC_PENDING; + + ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, req->handle, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + goto failed; + } + + /* complete the last message if any */ + if (lsql_ac->ares) { + lsql_ac->ares->message = ldb_msg_canonicalize(module->ldb, lsql_ac->ares->message); + if (lsql_ac->ares->message == NULL) + goto failed; + + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); + if (req->handle->status != LDB_SUCCESS) + goto failed; + } + + req->handle->state = LDB_ASYNC_DONE; + + return LDB_SUCCESS; + +failed: + return LDB_ERR_OPERATIONS_ERROR; +} + +/* add a record */ +static int lsql_add(struct ldb_module *module, struct ldb_request *req) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + struct ldb_message *msg = req->op.add.message; + long long eid; + char *dn, *ndn; + char *errmsg; + char *query; + int i; + int ret = LDB_SUCCESS; + + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; + + /* See if this is an ltdb special */ + if (ldb_dn_is_special(msg->dn)) { +/* + struct ldb_dn *c; + c = ldb_dn_new(local_ctx, module->ldb, "@INDEXLIST"); + if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { +#warning "should we handle indexes somehow ?" + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; + } +*/ + /* Others return an error */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; + } + + /* create linearized and normalized dns */ + dn = ldb_dn_alloc_linearized(lsql_ac, msg->dn); + ndn = ldb_dn_alloc_casefold(lsql_ac, msg->dn); + if (dn == NULL || ndn == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + query = lsqlite3_tprintf(lsql_ac, + /* Add new entry */ + "INSERT OR ABORT INTO ldb_entry " + "('dn', 'norm_dn') " + "VALUES ('%q', '%q');", + dn, ndn); + if (query == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto done; + } + + eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, lsql_ac, ndn); + if (eid == -1) { + ret = LDB_ERR_OTHER; + goto done; + } + + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_message_element *el = &msg->elements[i]; + const struct ldb_schema_attribute *a; + char *attr; + int j; + + /* Get a case-folded copy of the attribute name */ + attr = ldb_attr_casefold(lsql_ac, el->name); + if (attr == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + a = ldb_schema_attribute_by_name(module->ldb, el->name); + + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + char *insert; + + /* Get a canonicalised copy of the data */ + a->syntax->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + if (value.data == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + insert = lsqlite3_tprintf(lsql_ac, + "INSERT OR ROLLBACK INTO ldb_attribute_values " + "('eid', 'attr_name', 'norm_attr_name'," + " 'attr_value', 'norm_attr_value') " + "VALUES ('%lld', '%q', '%q', '%q', '%q');", + eid, el->name, attr, + el->values[j].data, value.data); + if (insert == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto done; + } + } + } + + if (lsql_ac->callback) { + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } + +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* modify a record */ +static int lsql_modify(struct ldb_module *module, struct ldb_request *req) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + struct ldb_message *msg = req->op.mod.message; + long long eid; + char *errmsg; + int i; + int ret = LDB_SUCCESS; + + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; + + /* See if this is an ltdb special */ + if (ldb_dn_is_special(msg->dn)) { + /* Others return an error */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; + } + + eid = lsqlite3_get_eid(module, msg->dn); + if (eid == -1) { + ret = LDB_ERR_OTHER; + goto done; + } + + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_message_element *el = &msg->elements[i]; + const struct ldb_schema_attribute *a; + int flags = el->flags & LDB_FLAG_MOD_MASK; + char *attr; + char *mod; + int j; + + /* Get a case-folded copy of the attribute name */ + attr = ldb_attr_casefold(lsql_ac, el->name); + if (attr == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + a = ldb_schema_attribute_by_name(module->ldb, el->name); + + switch (flags) { + + case LDB_FLAG_MOD_REPLACE: + + /* remove all attributes before adding the replacements */ + mod = lsqlite3_tprintf(lsql_ac, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q';", + eid, attr); + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto done; + } + + /* MISSING break is INTENTIONAL */ + + case LDB_FLAG_MOD_ADD: +#warning "We should throw an error if no value is provided!" + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + + /* Get a canonicalised copy of the data */ + a->syntax->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + if (value.data == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + mod = lsqlite3_tprintf(lsql_ac, + "INSERT OR ROLLBACK INTO ldb_attribute_values " + "('eid', 'attr_name', 'norm_attr_name'," + " 'attr_value', 'norm_attr_value') " + "VALUES ('%lld', '%q', '%q', '%q', '%q');", + eid, el->name, attr, + el->values[j].data, value.data); + + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto done; + } + } + + break; + + case LDB_FLAG_MOD_DELETE: +#warning "We should throw an error if the attribute we are trying to delete does not exist!" + if (el->num_values == 0) { + mod = lsqlite3_tprintf(lsql_ac, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q';", + eid, attr); + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto done; + } + } + + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + + /* Get a canonicalised copy of the data */ + a->syntax->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + if (value.data == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + mod = lsqlite3_tprintf(lsql_ac, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q' " + "AND norm_attr_value = '%q';", + eid, attr, value.data); + + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto done; + } + } + + break; + } + } + + if (lsql_ac->callback) { + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } + +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* delete a record */ +static int lsql_delete(struct ldb_module *module, struct ldb_request *req) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + long long eid; + char *errmsg; + char *query; + int ret = LDB_SUCCESS; + + + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; + + eid = lsqlite3_get_eid(module, req->op.del.dn); + if (eid == -1) { + goto done; + } + + query = lsqlite3_tprintf(lsql_ac, + /* Delete entry */ + "DELETE FROM ldb_entry WHERE eid = %lld; " + /* Delete attributes */ + "DELETE FROM ldb_attribute_values WHERE eid = %lld; ", + eid, eid); + if (query == NULL) { + ret = LDB_ERR_OTHER; + goto done; + } + + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + req->handle->status = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + if (lsql_ac->callback) { + ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } + +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* rename a record */ +static int lsql_rename(struct ldb_module *module, struct ldb_request *req) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + char *new_dn, *new_cdn, *old_cdn; + char *errmsg; + char *query; + int ret = LDB_SUCCESS; + + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; + + /* create linearized and normalized dns */ + old_cdn = ldb_dn_alloc_casefold(lsql_ac, req->op.rename.olddn); + new_cdn = ldb_dn_alloc_casefold(lsql_ac, req->op.rename.newdn); + new_dn = ldb_dn_alloc_linearized(lsql_ac, req->op.rename.newdn); + if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) { + goto done; + } + + /* build the SQL query */ + query = lsqlite3_tprintf(lsql_ac, + "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' " + "WHERE norm_dn = '%q';", + new_dn, new_cdn, old_cdn); + if (query == NULL) { + goto done; + } + + /* execute */ + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + if (lsql_ac->callback) { + ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } + +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +static int lsql_start_trans(struct ldb_module * module) +{ + int ret; + char *errmsg; + struct lsqlite3_private * lsqlite3 = module->private_data; + + if (lsqlite3->trans_count == 0) { + ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN IMMEDIATE;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_start_trans: error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + }; + + lsqlite3->trans_count++; + + return 0; +} + +static int lsql_end_trans(struct ldb_module *module) +{ + int ret; + char *errmsg; + struct lsqlite3_private *lsqlite3 = module->private_data; + + if (lsqlite3->trans_count > 0) { + lsqlite3->trans_count--; + } else return -1; + + if (lsqlite3->trans_count == 0) { + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_end_trans: error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + } + + return 0; +} + +static int lsql_del_trans(struct ldb_module *module) +{ + struct lsqlite3_private *lsqlite3 = module->private_data; + + if (lsqlite3->trans_count > 0) { + lsqlite3->trans_count--; + } else return -1; + + if (lsqlite3->trans_count == 0) { + return lsqlite3_safe_rollback(lsqlite3->sqlite); + } + + return -1; +} + +static int destructor(struct lsqlite3_private *lsqlite3) +{ + if (lsqlite3->sqlite) { + sqlite3_close(lsqlite3->sqlite); + } + return 0; +} + +static int lsql_request(struct ldb_module *module, struct ldb_request *req) +{ + return LDB_ERR_OPERATIONS_ERROR; +} + +static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + return handle->status; +} + +/* + * Table of operations for the sqlite3 backend + */ +static const struct ldb_module_ops lsqlite3_ops = { + .name = "sqlite", + .search = lsql_search, + .add = lsql_add, + .modify = lsql_modify, + .del = lsql_delete, + .rename = lsql_rename, + .request = lsql_request, + .start_transaction = lsql_start_trans, + .end_transaction = lsql_end_trans, + .del_transaction = lsql_del_trans, + .wait = lsql_wait, +}; + +/* + * Static functions + */ + +static int initialize(struct lsqlite3_private *lsqlite3, + struct ldb_context *ldb, const char *url, int flags) +{ + TALLOC_CTX *local_ctx; + long long queryInt; + int rollback = 0; + char *errmsg; + char *schema; + int ret; + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context"); + if (local_ctx == NULL) { + return -1; + } + + schema = lsqlite3_tprintf(local_ctx, + + + "CREATE TABLE ldb_info AS " + " SELECT 'LDB' AS database_type," + " '1.0' AS version;" + + /* + * The entry table holds the information about an entry. + * This table is used to obtain the EID of the entry and to + * support scope=one and scope=base. The parent and child + * table is included in the entry table since all the other + * attributes are dependent on EID. + */ + "CREATE TABLE ldb_entry " + "(" + " eid INTEGER PRIMARY KEY AUTOINCREMENT," + " dn TEXT UNIQUE NOT NULL," + " norm_dn TEXT UNIQUE NOT NULL" + ");" + + + "CREATE TABLE ldb_object_classes" + "(" + " class_name TEXT PRIMARY KEY," + " parent_class_name TEXT," + " tree_key TEXT UNIQUE," + " max_child_num INTEGER DEFAULT 0" + ");" + + /* + * We keep a full listing of attribute/value pairs here + */ + "CREATE TABLE ldb_attribute_values" + "(" + " eid INTEGER REFERENCES ldb_entry," + " attr_name TEXT," + " norm_attr_name TEXT," + " attr_value TEXT," + " norm_attr_value TEXT " + ");" + + + /* + * Indexes + */ + "CREATE INDEX ldb_attribute_values_eid_idx " + " ON ldb_attribute_values (eid);" + + "CREATE INDEX ldb_attribute_values_name_value_idx " + " ON ldb_attribute_values (attr_name, norm_attr_value);" + + + + /* + * Triggers + */ + + "CREATE TRIGGER ldb_object_classes_insert_tr" + " AFTER INSERT" + " ON ldb_object_classes" + " FOR EACH ROW" + " BEGIN" + " UPDATE ldb_object_classes" + " SET tree_key = COALESCE(tree_key, " + " (" + " SELECT tree_key || " + " (SELECT base160(max_child_num + 1)" + " FROM ldb_object_classes" + " WHERE class_name = " + " new.parent_class_name)" + " FROM ldb_object_classes " + " WHERE class_name = new.parent_class_name " + " ));" + " UPDATE ldb_object_classes " + " SET max_child_num = max_child_num + 1" + " WHERE class_name = new.parent_class_name;" + " END;" + + /* + * Table initialization + */ + + "INSERT INTO ldb_object_classes " + " (class_name, tree_key) " + " VALUES " + " ('TOP', '0001');"); + + /* Skip protocol indicator of url */ + if (strncmp(url, "sqlite3://", 10) != 0) { + return SQLITE_MISUSE; + } + + /* Update pointer to just after the protocol indicator */ + url += 10; + + /* Try to open the (possibly empty/non-existent) database */ + if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { + return ret; + } + + /* In case this is a new database, enable auto_vacuum */ + ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA auto_vacuum = 1;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + + if (flags & LDB_FLG_NOSYNC) { + /* DANGEROUS */ + ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + } + + /* */ + + /* Establish a busy timeout of 30 seconds */ + if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite, + 30000)) != SQLITE_OK) { + return ret; + } + + /* Create a function, callable from sql, to increment a tree_key */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite,/* handle */ + "base160_next", /* function name */ + 1, /* number of args */ + SQLITE_ANY, /* preferred text type */ + NULL, /* user data */ + base160next_sql, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } + + /* Create a function, callable from sql, to convert int to base160 */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite,/* handle */ + "base160", /* function name */ + 1, /* number of args */ + SQLITE_ANY, /* preferred text type */ + NULL, /* user data */ + base160_sql, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } + + /* Create a function, callable from sql, to perform various comparisons */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite, /* handle */ + "ldap_compare", /* function name */ + 4, /* number of args */ + SQLITE_ANY, /* preferred text type */ + ldb , /* user data */ + lsqlite3_compare, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } + + /* Begin a transaction */ + ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN EXCLUSIVE;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3: initialization error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + rollback = 1; + + /* Determine if this is a new database. No tables means it is. */ + if (query_int(lsqlite3, + &queryInt, + "SELECT COUNT(*)\n" + " FROM sqlite_master\n" + " WHERE type = 'table';") != 0) { + goto failed; + } + + if (queryInt == 0) { + /* + * Create the database schema + */ + ret = sqlite3_exec(lsqlite3->sqlite, schema, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + } else { + /* + * Ensure that the database we opened is one of ours + */ + if (query_int(lsqlite3, + &queryInt, + "SELECT " + " (SELECT COUNT(*) = 2" + " FROM sqlite_master " + " WHERE type = 'table' " + " AND name IN " + " (" + " 'ldb_entry', " + " 'ldb_object_classes' " + " ) " + " ) " + " AND " + " (SELECT 1 " + " FROM ldb_info " + " WHERE database_type = 'LDB' " + " AND version = '1.0'" + " );") != 0 || + queryInt != 1) { + + /* It's not one that we created. See ya! */ + goto failed; + } + } + + /* Commit the transaction */ + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3: iniialization error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + + return SQLITE_OK; + +failed: + if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); + sqlite3_close(lsqlite3->sqlite); + return -1; +} + +/* + * connect to the database + */ +static int lsqlite3_connect(struct ldb_context *ldb, + const char *url, + unsigned int flags, + const char *options[], + struct ldb_module **module) +{ + int i; + int ret; + struct lsqlite3_private * lsqlite3 = NULL; + + lsqlite3 = talloc(ldb, struct lsqlite3_private); + if (!lsqlite3) { + goto failed; + } + + lsqlite3->sqlite = NULL; + lsqlite3->options = NULL; + lsqlite3->trans_count = 0; + + ret = initialize(lsqlite3, ldb, url, flags); + if (ret != SQLITE_OK) { + goto failed; + } + + talloc_set_destructor(lsqlite3, destructor); + + + + *module = talloc(ldb, struct ldb_module); + if (!module) { + ldb_oom(ldb); + goto failed; + } + talloc_set_name_const(*module, "ldb_sqlite3 backend"); + (*module)->ldb = ldb; + (*module)->prev = (*module)->next = NULL; + (*module)->private_data = lsqlite3; + (*module)->ops = &lsqlite3_ops; + + if (options) { + /* + * take a copy of the options array, so we don't have to rely + * on the caller keeping it around (it might be dynamic) + */ + for (i=0;options[i];i++) ; + + lsqlite3->options = talloc_array(lsqlite3, char *, i+1); + if (!lsqlite3->options) { + goto failed; + } + + for (i=0;options[i];i++) { + + lsqlite3->options[i+1] = NULL; + lsqlite3->options[i] = + talloc_strdup(lsqlite3->options, options[i]); + if (!lsqlite3->options[i]) { + goto failed; + } + } + } + + return 0; + +failed: + if (lsqlite3->sqlite != NULL) { + (void) sqlite3_close(lsqlite3->sqlite); + } + talloc_free(lsqlite3); + return -1; +} + +const struct ldb_backend_ops ldb_sqlite3_backend_ops = { + .name = "sqlite3", + .connect_fn = lsqlite3_connect +}; diff --git a/ldb/ldb_sqlite3/schema b/ldb/ldb_sqlite3/schema new file mode 100644 index 000000000..ab7c5cc40 --- /dev/null +++ b/ldb/ldb_sqlite3/schema @@ -0,0 +1,328 @@ + -- ------------------------------------------------------ + + PRAGMA auto_vacuum=1; + + -- ------------------------------------------------------ + + BEGIN EXCLUSIVE; + + -- ------------------------------------------------------ + + CREATE TABLE ldb_info AS + SELECT 'LDB' AS database_type, + '1.0' AS version; + + /* + * Get the next USN value with: + * BEGIN EXCLUSIVE; + * UPDATE usn SET value = value + 1; + * SELECT value FROM usn; + * COMMIT; + */ + CREATE TABLE usn + ( + value INTEGER + ); + + CREATE TABLE ldb_object + ( + /* tree_key is auto-generated by the insert trigger */ + tree_key TEXT PRIMARY KEY, + + parent_tree_key TEXT, + dn TEXT, + + attr_name TEXT REFERENCES ldb_attributes, + attr_value TEXT, + + /* + * object_type can take on these values (to date): + * 1: object is a node of a DN + * 2: object is an attribute/value pair of its parent DN + */ + object_type INTEGER, + + /* + * if object_type is 1, the node can have children. + * this tracks the maximum previously assigned child + * number so we can generate a new unique tree key for + * a new child object. note that this is always incremented, + * so if children are deleted, this will not represent + * the _number_ of children. + */ + max_child_num INTEGER, + + /* + * Automatically maintained meta-data (a gift for metze) + */ + object_guid TEXT UNIQUE, + timestamp INTEGER, -- originating_time + invoke_id TEXT, -- GUID: originating_invocation_id + usn INTEGER, -- hyper: originating_usn + + /* do not allow duplicate name/value pairs */ + UNIQUE (parent_tree_key, attr_name, attr_value, object_type) + ); + + CREATE TABLE ldb_attributes + ( + attr_name TEXT PRIMARY KEY, + parent_tree_key TEXT, + + objectclass_p BOOLEAN DEFAULT 0, + + case_insensitive_p BOOLEAN DEFAULT 0, + wildcard_p BOOLEAN DEFAULT 0, + hidden_p BOOLEAN DEFAULT 0, + integer_p BOOLEAN DEFAULT 0, + + /* tree_key is auto-generated by the insert trigger */ + tree_key TEXT, -- null if not a object/sub class + -- level 1 if an objectclass + -- level 1-n if a subclass + max_child_num INTEGER + ); + + -- ------------------------------------------------------ + + CREATE INDEX ldb_object_dn_idx + ON ldb_object (dn); + + CREATE INDEX ldb_attributes_tree_key_ids + ON ldb_attributes (tree_key); + + -- ------------------------------------------------------ + + /* Gifts for metze. Automatically updated meta-data */ + CREATE TRIGGER ldb_object_insert_tr + AFTER INSERT + ON ldb_object + FOR EACH ROW + BEGIN + UPDATE ldb_object + SET max_child_num = max_child_num + 1 + WHERE tree_key = new.parent_tree_key; + UPDATE usn SET value = value + 1; + UPDATE ldb_object + SET tree_key = + (SELECT + new.tree_key || + base160(SELECT max_child_num + FROM ldb_object + WHERE tree_key = + new.parent_tree_key)); + max_child_num = 0, + object_guid = random_guid(), + timestamp = strftime('%s', 'now'), + usn = (SELECT value FROM usn); + WHERE tree_key = new.tree_key; + END; + + CREATE TRIGGER ldb_object_update_tr + AFTER UPDATE + ON ldb_object + FOR EACH ROW + BEGIN + UPDATE usn SET value = value + 1; + UPDATE ldb_object + SET timestamp = strftime('%s', 'now'), + usn = (SELECT value FROM usn); + WHERE tree_key = new.tree_key; + END; + + CREATE TRIGGER ldb_attributes_insert_tr + AFTER INSERT + ON ldb_attributes + FOR EACH ROW + BEGIN + UPDATE ldb_attributes + SET max_child_num = max_child_num + 1 + WHERE tree_key = new.parent_tree_key; + UPDATE ldb_attributes + SET tree_key = + (SELECT + new.tree_key || + base160(SELECT max_child_num + FROM ldb_attributes + WHERE tree_key = + new.parent_tree_key)); + max_child_num = 0 + WHERE tree_key = new.tree_key; + END; + + + -- ------------------------------------------------------ + + /* Initialize usn */ + INSERT INTO usn (value) VALUES (0); + + /* Create root object */ + INSERT INTO ldb_object + (tree_key, parent_tree_key, + dn, + object_type, max_child_num) + VALUES ('', NULL, + '', + 1, 0); + + /* We need an implicit "top" level object class */ + INSERT INTO ldb_attributes (attr_name, + parent_tree_key) + SELECT 'top', ''; + + -- ------------------------------------------------------ + + COMMIT; + + -- ------------------------------------------------------ + +/* + * dn: o=University of Michigan,c=US + * objectclass: organization + * objectclass: domainRelatedObject + */ +-- newDN +BEGIN; + +INSERT OR IGNORE INTO ldb_object + (parent_tree_key + dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('', + 'c=US', + 'c', 'US', 1, 0); + +INSERT INTO ldb_object + (parent_tree_key, + dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('0001', + 'o=University of Michigan,c=US', + 'o', 'University of Michigan', 1, 0); + +-- newObjectClass +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('objectclass', '', 1); + +INSERT INTO ldb_object + (parent_tree_key, + dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', + NULL, + 'objectclass', 'organization', 2, 0); + +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('objectclass', '', 1); + +INSERT INTO ldb_object + (parent_tree_key, + dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', + NULL, + 'objectclass', 'domainRelatedObject', 2, 0); + +COMMIT; + + +/* + * dn: o=University of Michigan,c=US + * l: Ann Arbor, Michigan + * st: Michigan + * o: University of Michigan + * o: UMICH + * seeAlso: + * telephonenumber: +1 313 764-1817 + */ +-- addAttrValuePair +BEGIN; + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'l', 'Ann Arbor, Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'st', 'Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'o', 'University of Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'o', 'UMICH', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'seeAlso', '', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'telephonenumber', '+1 313 764-1817', 2, 0); + +COMMIT; + +-- ---------------------------------------------------------------------- + +/* + * dn: @ATTRIBUTES + * uid: CASE_INSENSITIVE WILDCARD + * cn: CASE_INSENSITIVE + * ou: CASE_INSENSITIVE + * dn: CASE_INSENSITIVE + */ +-- newAttribute + +BEGIN; + +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('uid', '', 0); + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 1, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'uid' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'cn' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'ou' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'dn' + diff --git a/ldb/ldb_sqlite3/trees.ps b/ldb/ldb_sqlite3/trees.ps new file mode 100644 index 000000000..433a06481 --- /dev/null +++ b/ldb/ldb_sqlite3/trees.ps @@ -0,0 +1,1760 @@ +%!PS-Adobe-2.0 +%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software +%%Title: trees.dvi +%%Pages: 7 +%%PageOrder: Ascend +%%BoundingBox: 0 0 596 842 +%%EndComments +%DVIPSWebPage: (www.radicaleye.com) +%DVIPSCommandLine: dvips -f trees.dvi +%DVIPSParameters: dpi=600, compressed +%DVIPSSource: TeX output 2000.05.06:2055 +%%BeginProcSet: texc.pro +%! +/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S +N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 +mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 +0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ +landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize +mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ +matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round +exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ +statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] +N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin +/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array +/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 +array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N +df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A +definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get +}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} +B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr +1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3 +1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx +0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx +sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{ +rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp +gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B +/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{ +/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{ +A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy +get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse} +ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp +fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17 +{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add +chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{ +1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop} +forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn +/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put +}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ +bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A +mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ +SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ +userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X +1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 +index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N +/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ +/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) +(LaserWriter 16/600)]{A length product length le{A length product exch 0 +exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse +end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask +grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} +imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round +exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto +fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p +delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} +B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ +p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S +rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end + +%%EndProcSet +TeXDict begin 39158280 55380996 1000 600 600 (trees.dvi) +@start +%DVIPSBitmapFont: Fa cmr10 10 6 +/Fa 6 55 df<146014E0EB01C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B +120F90C7FCA25A121EA2123EA35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A2 +6C7EA26C7E1378A27F7F130E7FEB0380EB01C0EB00E01460135278BD20>40 +D<12C07E12707E7E7E120F6C7E6C7EA26C7E6C7EA21378A2137C133C133E131EA2131F7F +A21480A3EB07C0A6EB03E0B2EB07C0A6EB0F80A31400A25B131EA2133E133C137C1378A2 +5BA2485A485AA2485A48C7FC120E5A5A5A5A5A13527CBD20>I<15301578B3A6007FB812 +F8B912FCA26C17F8C80078C8FCB3A6153036367BAF41>43 D48 DI54 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fb cmr7 7 3 +/Fb 3 55 df48 D<13381378EA01F8121F12FE12E01200B3AB487EB512F8A2 +15267BA521>I54 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fc cmmi10 10 1 +/Fc 1 69 df<0103B7FC4916E018F8903B0007F80007FE4BEB00FFF03F80020FED1FC018 +0F4B15E0F007F0021F1503A24B15F81801143F19FC5DA2147FA292C8FCA25C18035CA213 +0119F84A1507A2130319F04A150FA2010717E0181F4A16C0A2010FEE3F80A24AED7F0018 +7E011F16FE4D5A4A5D4D5A013F4B5A4D5A4A4A5A057FC7FC017F15FEEE03FC91C7EA0FF0 +49EC7FC0B8C8FC16FC16C03E397DB845>68 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fd ectt1000 10 73 +/Fd 73 126 df37 +D39 +D<143814FC13011303EB07F8EB0FF0EB1FC0EB3F80EB7F0013FE485A485A5B12075B120F +5B485AA2123F90C7FCA25A127EA312FE5AAC7E127EA3127F7EA27F121FA26C7E7F12077F +12037F6C7E6C7E137FEB3F80EB1FC0EB0FF0EB07F8EB03FC130113001438164272B92C> +I<127012FC7E7E6C7E6C7EEA0FE06C7E6C7E6C7E6C7E137F7F1480131F14C0130FEB07E0 +A214F01303A214F81301A314FC1300AC130114F8A3130314F0A2130714E0A2EB0FC0131F +1480133F14005B13FE485A485A485A485AEA3FC0485A48C7FC5A5A1270164279B92C>I< +EB0380497EA60020140800F8143E00FE14FE00FF13C1EBC7C7EBE7CF003FB512F8000F14 +E0000314806C140038007FFCA248B5FC481480000F14E0003F14F839FFE7CFFEEBC7C7EB +07C100FE13C000F8143E0020140800001400A66D5A1F247AAA2C>I<147014F8AF003FB6 +12E0B712F8A4C700F8C7FCB0147025267DAB2C>II<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80EA1F000B0B708A2C>46 +D<1507ED0F80A2151F16005D153E157E157CA215FC5D14015D14035D14075D140F5D141F +92C7FC5C143EA2147E147C14FC5C13015C13035C13075C130F5C131F91C8FC5B133EA213 +7E137C13FC5B12015B12035B12075B120F5B121F90C9FCA25A123E127E127C12FC5AA212 +7021417BB92C>II<1307497EA2131F +A2133F137F13FF5A1207127FB5FC13DF139FEA7C1F1200B3AE007FB512E0B612F0A36C14 +E01C3477B32C>II<000FB512FE4880A35D0180C8FCADEB83FE90389FFF8090B512E015F881 +9038FE03FE9038F000FF01C07F49EB3F8090C7121F6C15C0C8120FA2ED07E0A4123C127E +B4FC150F16C0A248141F007EEC3F80007FEC7F006C6C5B6D485A391FF80FFC6CB55A6C5C +000114C06C6C90C7FCEB0FF823347CB22C>53 DI<1278B712C016E0A316C000FCC7EA3F80ED7F0015FE00785CC712014A +5A4A5A5D140F5D4A5A143F92C7FC5C147E14FE5C13015CA2495AA213075CA3495AA4495A +A5133F91C8FCAA131E23357CB32C>I59 D<1502ED0F80151F157F15 +FF913803FE00EC0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390 +C8FCEA07FCEA1FF8EA3FE0EAFF8090C9FCA27FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE0 +6D7EEB07FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157F151F150FED +0200212A7BAD2C>I<007FB612F0B712F8A36C15F0CAFCA8007FB612F0B712F8A36C15F0 +25127DA12C>I<122012F87EB4FC7FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07 +FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157FA215FF913803FE00EC +0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA1F +F8EA3FE0EAFF8090C9FC12FC5A1220212A7BAD2C>I<14FE497EA4497FA214EFA2130781 +A214C7A2010F7FA314C390381F83F0A590383F01F8A490387E00FCA549137E90B512FEA3 +4880A29038F8003FA34848EB1F80A4000715C049130FD87FFEEBFFFC6D5AB514FE6C15FC +497E27347EB32C>65 D<007FB512E015F8B612FE6C8016C03903F0003FED0FE0ED07F015 +03A2ED01F8A6ED03F0A21507ED0FE0ED1FC0EDFF8090B612005D5D15FF16C09039F0001F +E0ED07F0ED03F81501ED00FCA216FE167EA616FE16FC1501ED03F8150FED3FF0007FB612 +E016C0B712806CECFE0015F027337FB22C>I<02FF13700107EBE0F84913F9013F13FD49 +13FFEBFF813901FE007F4848131FD807F0130F1507485A491303485A150148C7FCA25A00 +7EEC00F01600A212FE5AAB7E127EA3007F15F06CEC01F8A26C7EA26C6C13036D14F06C6C +130716E0D803FC131F6C6CEB3FC03A00FF81FF806DB512006D5B010F5B6D13F001001380 +25357DB32C>I<007FB5FCB612C015F0816C803907E003FEEC00FFED7F80153FED1FC0ED +0FE0A2150716F0150316F81501A4ED00FCACED01F8A3150316F0A2150716E0150FED1FC0 +153FED7F80EDFF00EC03FE007FB55AB65A5D15C06C91C7FC26337EB22C>I<007FB612F0 +B712F8A37E3903F00001A7ED00F01600A4EC01E04A7EA490B5FCA5EBF003A46E5A91C8FC +A5163C167EA8007FB612FEB7FCA36C15FC27337EB22C>I<007FB612F8B712FCA37ED803 +F0C7FCA716781600A515F04A7EA490B5FCA5EBF001A46E5A92C7FCAD387FFFE0B5FC805C +7E26337EB22C>I<903901FC038090390FFF87C04913EF017F13FF90B6FC4813073803FC +01497E4848137F4848133F49131F121F5B003F140F90C7FCA2127EED078092C7FCA212FE +5AA8913803FFF84A13FCA27E007E6D13F89138000FC0A36C141FA27F121F6D133F120F6D +137F6C7E6C6C13FF6D5A3801FF076C90B5FC6D13EF011F13CF6DEB0780D901FCC7FC2635 +7DB32C>II<007FB512F8B612FCA36C14 +F839000FC000B3B3A5007FB512F8B612FCA36C14F81E3379B22C>I75 D<387FFFE0B57EA36C5BD803F0C8FCB3AE16F0 +ED01F8A8007FB6FCB7FCA36C15F025337DB22C>IIII<007FB512C0B612 +F88115FF6C15802603F00013C0153FED0FE0ED07F0A2150316F81501A6150316F01507A2 +ED0FE0ED3FC015FF90B61280160015FC5D15C001F0C8FCB0387FFF80B57EA36C5B25337E +B22C>II<387FFFFCB67E15E015F86C803907E007FE1401EC007F6F7E151FA2 +6F7EA64B5AA2153F4BC7FCEC01FE140790B55A5D15E081819038E007FCEC01FE1400157F +81A8160FEE1F80A5D87FFEEB1FBFB5ECFF00815E6C486D5AC8EA01F029347EB22C>I<90 +381FF80790B5EA0F804814CF000714FF5A381FF01F383FC003497E48C7FC007E147F00FE +143F5A151FA46CEC0F00007E91C7FC127F7FEA3FE0EA1FFCEBFFC06C13FC0003EBFFC06C +14F06C6C7F01077F9038007FFEEC07FF02001380153FED1FC0A2ED0FE0A20078140712FC +A56CEC0FC0A26CEC1F806D133F01E0EB7F009038FE01FF90B55A5D00F914F0D8F83F13C0 +D8700790C7FC23357CB32C>I<007FB612FCB712FEA43AFC007E007EA70078153CC71400 +B3AF90383FFFFCA2497F6D5BA227337EB22C>I<3B7FFF803FFFC0B56C4813E0A36C496C +13C03B03F00001F800B3AF6D130300015DA26D130700005D6D130F017F495A6D6C485AEC +E0FF6DB5C7FC6D5B010313F86D5B9038003F802B3480B22C>III<3A3FFF03FFE0484913F0148714076C6D13E03A01 +F800FE007F0000495A13FE017E5BEB7F03013F5B1487011F5B14CF010F5B14FF6D5BA26D +90C7FCA26D5AA26D5AA2497EA2497EA2497F81EB0FCF81EB1FC7EC87F0EB3F83EC03F8EB +7F01017E7FEBFE00497F0001147E49137F000380491480151FD87FFEEBFFFC6D5AB514FE +6C15FC497E27337EB22C>II<387FFFFCB512FEA314FC00FCC7FCB3B3B3B512FC14FEA36C13FC +17416FB92C>91 D<127012F8A27E127C127E123E123F7EA27F120F7F12077F12037F1201 +7F12007F137C137E133EA2133F7F80130F80130780130380130180130080147C147E143E +A2143F8081140F81140781140381140181140081157CA2157E153E153F811680150FA2ED +070021417BB92C>I<387FFFFCB512FEA37EC7127EB3B3B3387FFFFEB5FCA36C13FC1741 +7DB92C>II<007FB6FCB71280A46C150021067B7D +2C>I<1338137CEA01FC1203EA07F813F0EA0FC0EA1F80A2EA3F00123E127E127CA212FC +5AA3EAFFC013E013F013F8A2127FA2123F13F0EA1FE0EA07C00E1D72B82C>I<3801FFF0 +000713FE001F6D7E15E048809038C01FF81407EC01FC381F80000006C77EC8127EA3ECFF +FE131F90B5FC1203120F48EB807E383FF800EA7FC090C7FC12FE5AA47E007F14FEEB8003 +383FE01F6CB612FC6C15FE6C14BF0001EBFE1F3A003FF007FC27247CA32C>II<90 +3803FFE0011F13F8017F13FE48B5FC48804848C6FCEA0FF0485A49137E4848131890C9FC +5A127EA25AA8127EA2127F6C140F6DEB1F806C7E6D133F6C6CEB7F003907FE03FF6CB55A +6C5C6C6C5B011F13E0010390C7FC21247AA32C>III103 +DI< +1307EB1FC0A2497EA36D5AA20107C7FC90C8FCA7387FFFC080B5FC7EA2EA0007B3A8007F +B512FCB612FEA36C14FC1F3479B32C>I107 D<387FFFE0B57EA37EEA0003B3B3A5007F +B61280B712C0A36C158022337BB22C>I<3A7F83F007E09039CFFC1FF83AFFDFFE3FFCD8 +7FFF13FF91B57E3A07FE1FFC3E01FCEBF83F496C487E01F013E001E013C0A301C01380B3 +3B7FFC3FF87FF0027F13FFD8FFFE6D13F8D87FFC4913F0023F137F2D2481A32C>I<397F +F01FE039FFF87FFC9038F9FFFE01FB7F6CB6FC00019038F03F80ECC01F02807FEC000F5B +5BA25BB3267FFFE0B5FCB500F11480A36C01E0140029247FA32C>II<397FF01FE0 +39FFF8FFF801FB13FE90B6FC6C158000019038F07FC09138801FE091380007F049EB03F8 +5BED01FC491300A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F9138801FE0 +9138E07FC091B51280160001FB5B01F813F8EC3FC091C8FCAD387FFFE0B57EA36C5B2736 +7FA32C>I<903903FC078090391FFF0FC0017F13CF48B512EF4814FF3807FE07380FF001 +48487E49137F4848133F90C7FC48141F127E150F5AA87E007E141FA26C143F7F6C6C137F +6D13FF380FF0033807FC0F6CB6FC6C14EF6C6C138F6D130FEB07F890C7FCAD0203B5FC4A +1480A36E140029367DA32C>II<90387FF8700003B512F8120F5A5A387FC00F387E00034813015AA36CEB +00F0007F140013F0383FFFC06C13FE6CEBFF80000314E0C66C13F8010113FCEB0007EC00 +FE0078147F00FC143F151F7EA26C143F6D133E6D13FE9038F007FC90B5FC15F815E000F8 +148039701FFC0020247AA32C>I<131E133FA9007FB6FCB71280A36C1500D8003FC8FCB1 +ED03C0ED07E0A5EC800F011FEB1FC0ECE07F6DB51280160001035B6D13F89038003FE023 +2E7EAD2C>I<3A7FF003FF80486C487FA3007F7F0001EB000FB3A3151FA2153F6D137F39 +00FE03FF90B7FC6D15807F6D13CF902603FE07130029247FA32C>I<3A3FFF03FFF04801 +8713F8A36C010313F03A00FC007E005D90387E01F8013F5BEB1F83EC87E090380FCFC090 +3807EF80EB03FF6D90C7FC5C6D5A147C14FE130180903803EF80903807CFC0EB0FC7EC83 +E090381F01F0013F7FEB7E00017C137C49137E0001803A7FFF01FFFC1483B514FE6C15FC +140127247EA32C>120 D<3A7FFF01FFFCB5008113FE148314816C010113FC3A03E0000F +806C7E151F6D140012005D6D133E137C017E137E013E137CA2013F13FC6D5BA2EB0F815D +A2EB07C1ECC3E0A2EB03E3ECE7C0130114F75DEB00FFA292C7FC80A2143EA2147E147CA2 +14FC5CA2EA0C01003F5BEA7F83EB87E0EA7E0F495A387FFF806C90C8FC6C5A6C5AEA07E0 +27367EA32C>I<15FF02071380141F147F91B512004913C04AC7FCEB03F85CB31307EB1F +E013FF007F5BB55A49C8FC6D7E6C7FC67F131FEB07F01303B380EB01FEECFFC06D13FF6E +1380141F14070200130021417BB92C>123 D<127812FCB3B3B3A9127806416DB92C>II E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fe ecti1000 10 33 +/Fe 33 122 df28 D<150C151C153815F0EC01E0EC03C0EC0780EC0F00141E5C147C5C5C495A1303 +495A5C130F49C7FCA2133EA25BA25BA2485AA212035B12075BA2120F5BA2121FA290C8FC +A25AA2123EA2127EA2127CA412FC5AAD1278A57EA3121C121EA2120E7EA26C7E6C7EA212 +001E5274BD22>40 D<140C140E80EC0380A2EC01C015E0A2140015F0A21578A4157C153C +AB157CA715FCA215F8A21401A215F0A21403A215E0A21407A215C0140F1580A2141F1500 +A2143EA25CA25CA2495AA2495A5C1307495A91C7FC5B133E133C5B5B485A12035B48C8FC +120E5A12785A12C01E527FBD22>I<4B7EA3150393C8FCA35D1506A3150E150CA3151C15 +18A315381530A31570B912E0A2C80060C8FC15E05DA314015DA3140392C9FCA35C1406A3 +140E140CA3141C1418A2333275AD40>43 DI<120E +EA3F80127F12FFA31300127E123C0909778819>46 D<0103B612FEEFFFC018F0903B0007 +F8000FF84BEB03FCEF00FE020F157FF03F804B141F19C0021F150F19E05D1807143F19F0 +5DA2147FA292C8FCA25C180F5CA2130119E04A151FA2130319C04A153FA201071780187F +4A1600A2010F16FEA24A4A5A60011F15034D5A4A5D4D5A013F4B5A173F4A4AC7FC17FC01 +7FEC03F84C5A91C7EA1FC04949B45A007F90B548C8FCB712F016803C397CB83F>68 +D<0103B512F8A390390007F8005DA2140FA25DA2141FA25DA2143FA25DA2147FA292C7FC +A25CA25CA21301A25CA21303A25CA21307A25CA2130FA25CA2131FA25CA2133FA25CA213 +7FA291C8FC497EB6FCA25C25397CB820>73 D<0107B512FCA25E9026000FF8C7FC5D5D14 +1FA25DA2143FA25DA2147FA292C8FCA25CA25CA21301A25CA21303A25CA21307A25CA213 +0F170C4A141CA2011F153C17384A1478A2013F157017F04A14E01601017F140317C091C7 +1207160F49EC1F80163F4914FF000102071300B8FCA25E2E397BB834>76 +D79 +D81 D<92383FC00E913901FFF01C020713FC91 +391FC07E3C91393F001F7C027CEB0FF84A130749481303495A4948EB01F0A2495AA2011F +15E091C7FCA34915C0A36E90C7FCA2806D7E14FCECFF806D13F015FE6D6D7E6D14E00100 +80023F7F14079138007FFC150F15031501A21500A2167C120EA3001E15FC5EA3003E4A5A +A24B5AA2007F4A5A4B5A6D49C7FC6D133ED8F9F013FC39F8FC03F839F07FFFE0D8E01F13 +8026C003FCC8FC2F3D7ABA2F>83 D<0007B812E0A25AD9F800EB001F01C049EB07C0485A +D900011403121E001C5C003C17801403123800785C00701607140700F01700485CA2140F +C792C7FC5DA2141FA25DA2143FA25DA2147FA292C9FCA25CA25CA21301A25CA21303A25C +A21307A25CA2130FA25CEB3FF0007FB512F8B6FCA2333971B83B>I<14F8EB07FE90381F +871C90383E03FE137CEBF801120148486C5A485A120FEBC001001F5CA2EA3F801403007F +5C1300A21407485C5AA2140F5D48ECC1C0A2141F15831680143F1587007C017F1300ECFF +076C485B9038038F8E391F0F079E3907FE03FC3901F000F0222677A42A>97 +D<133FEA1FFFA3C67E137EA313FE5BA312015BA312035BA31207EBE0F8EBE7FE9038EF0F +80390FFC07C013F89038F003E013E0D81FC013F0A21380A2123F1300A214075A127EA214 +0F12FE4814E0A2141F15C05AEC3F80A215005C147E5C387801F8007C5B383C03E0383E07 +C0381E1F80D80FFEC7FCEA01F01C3B77B926>I<147F903803FFC090380FC1E090381F00 +70017E13784913383901F801F83803F003120713E0120FD81FC013F091C7FC485AA2127F +90C8FCA35A5AA45AA3153015381578007C14F0007EEB01E0003EEB03C0EC0F806CEB3E00 +380F81F83803FFE0C690C7FC1D2677A426>II<147F903803FFC090380FC1E09038 +3F00F0017E13785B485A485A485A120F4913F8001F14F0383F8001EC07E0EC1F80397F81 +FF00EBFFF8148090C8FC5A5AA55AA21530007C14381578007E14F0003EEB01E0EC03C06C +EB0F806CEB3E00380781F83803FFE0C690C7FC1D2677A426>IIIII108 +DII<147F903803FFC090380FC1F090381F00F8 +017E137C5B4848137E4848133E0007143F5B120F485AA2485A157F127F90C7FCA215FF5A +4814FEA2140115FC5AEC03F8A2EC07F015E0140F007C14C0007EEB1F80003EEB3F00147E +6C13F8380F83F03803FFC0C648C7FC202677A42A>I<9039078007C090391FE03FF09039 +3CF0787C903938F8E03E9038787FC00170497EECFF00D9F0FE148013E05CEA01E113C15C +A2D80003143FA25CA20107147FA24A1400A2010F5C5E5C4B5A131F5EEC80035E013F495A +6E485A5E6E48C7FC017F133EEC70FC90387E3FF0EC0F8001FEC9FCA25BA21201A25BA212 +03A25B1207B512C0A3293580A42A>I<3903C003F0390FF01FFC391E783C0F381C7C703A +3C3EE03F8038383FC0EB7F800078150000701300151CD8F07E90C7FCEAE0FE5BA2120012 +015BA312035BA312075BA3120F5BA3121F5BA3123F90C9FC120E212679A423>114 +D<14FE903807FF8090380F83C090383E00E04913F00178137001F813F00001130313F0A2 +15E00003EB01C06DC7FC7FEBFFC06C13F814FE6C7F6D13807F010F13C01300143F141F14 +0F123E127E00FE1480A348EB1F0012E06C133E00705B6C5B381E03E06CB45AD801FEC7FC +1C267AA422>II<01F013 +0ED803FC133FD8071EEB7F80EA0E1F121C123C0038143F49131F0070140FA25BD8F07E14 +0000E08013FEC6485B150E12015B151E0003141C5BA2153C000714385B5DA35DA24A5A14 +0300035C6D48C7FC0001130E3800F83CEB7FF8EB0FC0212679A426>118 +D<903907E007C090391FF81FF89039787C383C9038F03E703A01E01EE0FE3803C01F0180 +13C0D8070014FC481480000E1570023F1300001E91C7FC121CA2C75AA2147EA214FEA25C +A21301A24A1370A2010314F016E0001C5B007E1401010714C000FEEC0380010F1307010E +EB0F0039781CF81E9038387C3C393FF03FF03907C00FC027267CA427>120 +D<13F0D803FCEB01C0D8071EEB03E0D80E1F1307121C123C0038140F4914C01270A24913 +1FD8F07E148012E013FEC648133F160012015B5D0003147E5BA215FE00075C5BA214015D +A314035D14070003130FEBF01F3901F87FE038007FF7EB1FC7EB000F5DA2141F003F5C48 +133F92C7FC147E147C007E13FC387001F8EB03E06C485A383C1F80D80FFEC8FCEA03F023 +3679A428>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Ff cmsy10 10 1 +/Ff 1 16 df15 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fg ecbx1000 10 36 +/Fg 36 119 df<913803FFC0027F13F00103B512FC010FEB00FED93FF8133FD97FE0EBFF +8049485A5A1480484A13C04A6C1380A36F1300167E93C7FCA592383FFFC0B8FCA4000390 +C7FCB3ABB5D8FC3F13FFA4303A7EB935>28 D45 +DI<141E143E +14FE1307137FB5FCA3138FEA000FB3B3A5007FB61280A4213679B530>49 +DI54 D58 D66 DII73 +D76 DII< +EDFFF8020FEBFF80027F14F0903A01FFC01FFC010790380007FFD91FFC010113C0D93FF0 +6D6C7E49486E7E49486E7E48496E7E48834890C86C7EA248486F1380A248486F13C0A200 +3F18E0A348486F13F0A400FF18F8AC007F18F06D5DA3003F18E0A26D5D001F18C0A26C6C +4B13806C18006E5C6C6D4A5A6C5F6C6D4A5A6D6C4A5AD93FFC49485A6DB401075B0107D9 +C01F90C7FC010190B512FC6D6C14F0020F1480020001F8C8FC3D3B7BB948>III83 D85 DII<13 +FFB5FCA412077EAF4AB47E020F13F0023F13FC9138FE03FFDAF00013804AEB7FC00280EB +3FE091C713F0EE1FF8A217FC160FA217FEAA17FCA3EE1FF8A217F06E133F6EEB7FE06E14 +C0903AFDF001FF80903AF8FC07FE009039F03FFFF8D9E00F13E0D9C00390C7FC2F3A7EB9 +35>98 D100 +D<903803FF80011F13F0017F13FC3901FF83FE3A03FE007F804848133F484814C0001FEC +1FE05B003FEC0FF0A2485A16F8150712FFA290B6FCA301E0C8FCA4127FA36C7E1678121F +6C6C14F86D14F000071403D801FFEB0FE06C9038C07FC06DB51200010F13FC010113E025 +257DA42C>II<161FD907FEEBFFC090387FFFE348B6EAEFE02607FE07138F260FF801131F48486C13 +8F003F15CF4990387FC7C0EEC000007F81A6003F5DA26D13FF001F5D6C6C4890C7FC3907 +FE07FE48B512F86D13E0261E07FEC8FC90CAFCA2123E123F7F6C7E90B512F8EDFF8016E0 +6C15F86C816C815A001F81393FC0000F48C8138048157F5A163FA36C157F6C16006D5C6C +6C495AD81FF0EB07FCD807FEEB3FF00001B612C06C6C91C7FC010713F02B377DA530>I< +EA01F0EA07FC487EA2487EA56C5AA26C5AEA01F0C8FCA913FF127FA412077EB3A9B512F8 +A4153B7DBA1B>105 D<13FFB5FCA412077EAF92380FFFE0A4923803FC0016F0ED0FE0ED +1F804BC7FC157E5DEC03F8EC07E04A5A141FEC7FE04A7E8181A2ECCFFEEC0FFF496C7F80 +6E7F6E7F82157F6F7E6F7E82150F82B5D8F83F13F8A42D3A7EB932>107 +D<13FFB5FCA412077EB3B3ACB512FCA4163A7DB91B>I<01FED97FE0EB0FFC00FF902601 +FFFC90383FFF80020701FF90B512E0DA1F81903983F03FF0DA3C00903887801F000749DA +CF007F00034914DE6D48D97FFC6D7E4A5CA24A5CA291C75BB3A3B5D8FC1FB50083B512F0 +A44C257DA451>I<01FEEB7FC000FF903803FFF8020F13FE91381F03FFDA3C0113800007 +13780003497E6D4814C05CA25CA291C7FCB3A3B5D8FC3F13FFA430257DA435>I<903801 +FFC0010F13F8017F13FFD9FF807F3A03FE003FE048486D7E48486D7E48486D7EA2003F81 +491303007F81A300FF1680A9007F1600A3003F5D6D1307001F5DA26C6C495A6C6C495A6C +6C495A6C6C6CB45A6C6CB5C7FC011F13FC010113C029257DA430>I<9038FE03F000FFEB +0FFEEC3FFF91387C7F809138F8FFC000075B6C6C5A5CA29138807F80ED3F00150C92C7FC +91C8FCB3A2B512FEA422257EA427>114 D<90383FF0383903FFFEF8000F13FF381FC00F +383F0003007E1301007C130012FC15787E7E6D130013FCEBFFE06C13FCECFF806C14C06C +14F06C14F81203C614FC131F9038007FFE140700F0130114007E157E7E157C6C14FC6C14 +F8EB80019038F007F090B512C000F8140038E01FF81F257DA426>I<130FA55BA45BA25B +5BA25A1207001FEBFFE0B6FCA3000390C7FCB21578A815F86CEB80F014816CEBC3E09038 +3FFFC06D1380903803FE001D357EB425>I118 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fh ecrm1000 10 89 +/Fh 89 126 df<486C1360000314E039070001C0000EEB038048EB070000181306003813 +0E0030130C0070131C00601318A200E01338481330A400CEEB338039FF803FE001C013F0 +A3007F131FA2393F800FE0390E0003801C1981B91C>16 D<001C1307007FEB1FC039FF80 +3FE0A201C013F0A3007F131F001CEB073000001300A400011470491360A2000314E090C7 +12C048130100061480000E130348EB070048130E485B006013181C1980B91C>I21 D27 +DI30 D36 D<141FEC7FC0903801F0 +E0903803C0600107137090380F803090381F00381518A25BA2133E133F15381530A21570 +5D5D140190381F838092CAFC1487148E02DC49B51280EB0FF85C4A9039003FF8000107ED +0FC06E5D71C7FC6E140E010F150CD91DFC141C01391518D970FE143801E015302601C07F +1470D803805D00076D6C5BD80F00EBC00148011F5C4890380FE003003E6E48C8FC007E90 +3807F8060203130E00FE6E5A6E6C5A1400ED7F706C4B13036F5A6F7E6C6C6D6C5B701306 +6C6C496C130E6DD979FE5B281FF001F07F133C3C07F80FE03FC0F86CB539800FFFF0C690 +26FE000313C0D91FF0D9007FC7FC393E7DBB41>38 D<121C127FEAFF80A213C0A3127F12 +1C1200A412011380A2120313005A1206120E5A5A5A12600A1979B917>I<146014E0EB01 +C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B120F90C7FCA25A121EA2123E +A35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A26C7EA26C7E1378A27F7F130E +7FEB0380EB01C0EB00E01460135278BD20>I<12C07E12707E7E7E120F6C7E6C7EA26C7E +6C7EA21378A2137C133C133E131EA2131F7FA21480A3EB07C0A6EB03E0B2EB07C0A6EB0F +80A31400A25B131EA2133E133C137C1378A25BA2485A485AA2485A48C7FC120E5A5A5A5A +5A13527CBD20>I<1530B3A8B912FCA2C80030C8FCB3A836367BAF41>43 +D<121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A1206120E5A5A5A +12600A19798817>II<121C127FEAFF80A5EA7F00121C09097988 +17>I<1506A2150E150CA2151C151815381530A215701560A215E015C0A214011580A214 +0315005C1406A2140E140CA2141C1418A214381430A21470146014E05CA213015CA21303 +91C7FCA25B1306A2130E130C131C1318A213381330A213701360A213E05BA212015B1203 +90C8FCA25A1206A2120E120CA2121C1218A21238123012701260A212E05AA21F537BBD2A +>II +III<1538A2157815F8A214011403 +1407A2140F141F141B14331473146314C313011483EB030313071306130C131C13181330 +1370136013C01201EA038013005A120E120C5A123812305A12E0B712F8A3C73803F800AA +4A7E0103B512F8A325387EB72A>I<0006140CD80780133C9038F003F890B5FC5D5D1580 +92C7FC14FC38067FE090C9FCAAEB07F8EB1FFE9038780F809038E007E03907C003F0496C +7E130000066D7E81C8FC8181A21680A4121C127F5A7FA390C713005D12FC00605C12704A +5A6C5C6C1303001E495A6C6C485A3907E03F800001B5C7FC38007FFCEB1FE021397CB62A +>II<12301238123E003FB612E0A316C05A168016 +000070C712060060140E5D5D00E014304814705D5DC712014A5A4AC7FC1406140E5CA25C +1478147014F05C1301A213035C1307A2130FA3131F5CA2133FA5137FA96DC8FC131E233A +7BB72A>III<121C127FEAFF80A5 +EA7F00121CC7FCB2121C127FEAFF80A5EA7F00121C092479A317>I<121C127FEAFF80A5 +EA7F00121CC7FCB2121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A +1206120E5A5A5A12600A3479A317>II<007FB812F8B912FCCCFCB0B912FC6C17F836147B9E41>I<12E01278121EEA07C0 +EA01F0EA003C130FEB03C0EB00F0143C140FEC03E0EC00F8151EED0780ED01E0ED007816 +1EEE07C0EE01F0EE003C170FEF03C0A2EF0F00173CEE01F0EE07C0041EC7FC1678ED01E0 +ED0780031EC8FC15F8EC03E0020FC9FC143C14F0EB03C0010FCAFC133CEA01F0EA07C000 +1ECBFC127812E0322E79AB41>II<1538A3157CA315FEA34A7EA34A6C7EA202077FEC063FA202 +0E7FEC0C1FA2021C7FEC180FA202387FEC3007A202707FEC6003A202C07F1501A2D90180 +7F81A249C77F167FA20106810107B6FCA24981010CC7121FA2496E7EA3496E7EA3496E7E +A213E0707E1201486C81D80FFC02071380B56C90B512FEA3373C7DBB3E>65 +DI<913A01FF800180020FEBE003027F13F8903A01FF807E07903A03 +FC000F0FD90FF0EB039F4948EB01DFD93F80EB00FF49C8127F01FE153F12014848151F48 +48150FA248481507A2485A1703123F5B007F1601A35B00FF93C7FCAD127F6DED0180A312 +3F7F001F160318006C7E5F6C7E17066C6C150E6C6C5D00001618017F15386D6C5CD91FE0 +5C6D6CEB03C0D903FCEB0F80902701FF803FC7FC9039007FFFFC020F13F002011380313D +7BBA3C>IIIIIII<013FB512 +E0A39039001FFC00EC07F8B3B3A3123FEA7F80EAFFC0A44A5A1380D87F005B0070131F6C +5C6C495A6C49C7FC380781FC3801FFF038007F80233B7DB82B>IIIIIIIII< +D90FF813C090383FFE0190B512813903F807E33907E000F74848137F4848133F48C7121F +003E140F007E1407A2007C140312FC1501A36C1400A37E6D14006C7E7F13F86CB47E6C13 +F8ECFF806C14E06C14F86C14FEC680013F1480010714C0EB007F020713E0EC007FED3FF0 +151F150FED07F8A200C01403A21501A37EA216F07E15036C15E06C14076C15C06C140F6D +EB1F80D8FBF0EB3F00D8F0FE13FE39E03FFFF8010F13E0D8C00190C7FC253D7CBA2E>I< +003FB812E0A3D9C003EB001F273E0001FE130348EE01F00078160000701770A300601730 +A400E01738481718A4C71600B3B0913807FF80011FB612E0A335397DB83C>IIII89 D<003FB7FCA39039FC0001FE +01C0130349495A003EC7FC003C4A5A5E0038141F00784A5A12704B5A5E006014FF4A90C7 +FCA24A5A5DC712074A5AA24A5A5D143F4A5AA24A5A92C8FC5B495AA2495A5C130F4948EB +0180A2495A5C137F495A16034890C7FC5B1203485AEE0700485A495C001F5D48485C5E48 +48495A49130FB8FCA329397BB833>II93 D<007FB81280B912C0A26C17 +803204797041>95 D97 DIIII<147E903803FF8090 +380FC1E0EB1F8790383F0FF0137EA213FCA23901F803C091C7FCADB512FCA3D801F8C7FC +B3AB487E387FFFF8A31C3B7FBA19>IIIIIII<2703F00FF0EB1FE000FFD93FFCEB +7FF8913AF03F01E07E903BF1C01F83803F3D0FF3800FC7001F802603F70013CE01FE14DC +49D907F8EB0FC0A2495CA3495CB3A3486C496CEB1FE0B500C1B50083B5FCA340257EA445 +>I<3903F00FF000FFEB3FFCECF03F9039F1C01F803A0FF3800FC03803F70013FE496D7E +A25BA35BB3A3486C497EB500C1B51280A329257EA42E>II<3903F01F +E000FFEB7FF89038F1E07E9039F3801F803A07F7000FC0D803FEEB07E049EB03F04914F8 +49130116FC150016FEA3167FAA16FEA3ED01FCA26DEB03F816F06D13076DEB0FE001F614 +C09039F7803F009038F1E07E9038F0FFF8EC1FC091C8FCAB487EB512C0A328357EA42E> +II<3807E01F00FFEB7FC09038E1E3E09038E387F0380FE707EA03E613EE9038EC03E0 +9038FC0080491300A45BB3A2487EB512F0A31C257EA421>II<1318A51338A31378A313F812011203 +1207001FB5FCB6FCA2D801F8C7FCB215C0A93800FC011580EB7C03017E13006D5AEB0FFE +EB01F81A347FB220>IIIIII<003FB512FCA2EB8003D83E0013F8003CEB07F00038 +EB0FE012300070EB1FC0EC3F800060137F150014FE495AA2C6485A495AA2495A495A495A +A290387F000613FEA2485A485A0007140E5B4848130C4848131CA24848133C48C7127C48 +EB03FC90B5FCA21F247EA325>II<126012F0B3B3B3 +B3A91260045377BD17>I<12FCEAFFC0EA07F0EA01FCEA007E7F80131F80130FB3A78013 +07806D7E6D7EEB007EEC1FF0EC07F8EC1FF0EC7E00495A495A495A5C130F5CB3A7131F5C +133F91C7FC137E485AEA07F0EAFFC000FCC8FC1D537ABD2A>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fi ecbx1440 14.4 34 +/Fi 34 118 df28 D45 D<151E153E15FE1403140F147FEB07FF00 +03B5FCB6FCA3EBF87FEAFC00C7FCB3B3B3A6007FB712FCA52E4E76CD42>49 +DI<913807FFC0027F13FC0103B67E010F15E090 +261FF80313F890267FC0007F01FEC7EA3FFE48488148486E138013FE486C6C6D13C08048 +17E080A66C5B18C06C5B6C90C75AD80038168090C8FC4C1300A24C5A5F4C5A4B5B4B13C0 +030F5BDB7FFEC7FC91387FFFF816C016FCEEFF80DA000313E09238007FF8EE3FFE707E70 +138018C07013E018F07013F8A218FC82A218FEA3EA03C0EA0FF0EA3FFC487EA2B5FCA218 +FCA25E18F8A26C4816F0495C4916E0D83FE04A13C06C485CD80FF04A1380D807FE91387F +FE003B03FFE003FFFC6C90B65A6C6C15E0010F92C7FC010114FCD9001F1380374F7BCD42 +>I<17FC1601A216031607160FA2161F163F167FA216FF5D5DA25D5D5D167F153E157E15 +FC15F8EC01F01403EC07E015C0EC0F80141FEC3F00143E5C14FC495A5C495A1307495A5C +49C7FC5B137E137C5B1201485A5B485A120F485A90C8FC123E127E5ABA1280A5C901FCC7 +FCAF021FB71280A5394F7CCE42>I<486C150601F0153E01FEEC01FED9FFF0133F91B65A +5F5F5F5F5F94C7FC16FC5E16E093C8FC15FC01F0138091CAFCAC913807FF80023F13F891 +B512FE01F36E7E9026FFFC0113E09139E0007FF891C76C7E496E7E01F86E7E5B70138049 +16C0C9FC18E08218F0A418F8A31203EA0FE0EA3FF8487EA212FF7FA218F0A25B5E6C4816 +E05B01C016C06CC85A18806C6C4A13007FD80FF04A5A6C6CECFFFCD803FE4913F02701FF +E00F5B6C6CB612806D92C7FC010F14F8010114C09026003FFCC8FC354F7ACD42>I58 +D<932603FFF01407047F01FF5C0307B600E05B033F03F85B92B700FE5B02039126C003FF +5B020F01F8C7EA3FC1023F01C0EC0FE391B5C80003B5FC4901FC814949814901E082011F +498249498292CA7E4948834948835A4A83485B4885A2484984A2485B87A2485B87A25AA2 +98C8FC91CFFCA2B5FCAE7E067FB7128080A37E95C76C90C7FC807EA36C7FA26C7FA26C7F +7E806C7F137F6D7E816D6D93B5FC01077F6D01F85D6D7F6D01FF5D023F01E0EC0FEF020F +01FCEC3FE30203903AFFE001FF81020091B6C6FC033F03FC133F030703F0130FDB007F02 +801303040301F8CAFC595479D267>71 D73 D76 +D78 D80 D<93381FFF800303B512FC033FECFFC0 +92B712F00207D9F80113FE021F903AC0003FFF804A48C700077FDAFFF8020113F049496E +7F49496F7E49496F7E49496F7E4990C96C7F4948707F4948707F01FF854849707F4A8248 +86A24849717E48864A83A2481B80A248497113C0A4481BE0A291CB7EA3B51AF0AF6C1BE0 +A36E5FA26C1BC0A36C1B806E5FA26C1B006E5F6C62A26C6DD903FC4A5A6CDB0FFF5D6E49 +EBC0016C4B01E05C6D6C90277E07F0035B6E9039F801F807902A3FFF01F000780F5B6D04 +7C5C6DD981E06D4890C7FC6D01E191381F7FFE010101F1EDFFF86DD9F9F06D5BDA3FFF16 +C06E6D013F5B02079027FE01FFFEC8FC020190B612F8DA003F4B141003071838DB001FEB +83F893C7EA03FC1C7885726C14F8F2C003F2F01F97B512F084A31CE085A27314C01C8085 +1C00735B735B735B735B9638003FC0556A79D263>III<003FBB12FCA59126C0007FEB000301FCC7ED003FD87FF0F00FFE491807 +49180349180190C81600A2007E1A7EA3007C1A3EA500FC1A3F481A1FA6C91700B3B3AC49 +B912C0A550517BD05B>I97 D<913803FFE0023F13FE91B67E010315E0010F9038003FF8D93FFCEB +07FC4948497E4948131F4849497E485B485BA24890C7FC5A5B003F6F5A705A705A007F92 +C8FC5BA312FFAD127F7FA3123F7F6CEE0F80A26C6D141F18006C6D5C6C6D143E6C6D147E +6C6D5C6D6C495A6DB4EB07F0010F9038C01FE06D90B5128001014AC7FCD9003F13F80203 +138031387CB63A>99 D<943803FF80040FB5FCA5EE003F170FB3A4913803FF80023F13F8 +49B512FE0107ECFF8F011F9038C03FEF90273FFE0007B5FCD97FF8130149487F48498048 +4980484980488291C8FC5A5B123FA2127F5BA312FFAD127FA37F123FA3121F7F6C5E6C6D +5C5F6C6D91B5FC6C6D5B6C6D4914E0D97FFCD90FEFEBFF80D91FFFEB7F8F010790B5120F +010114FC6D6C13E00207010049C7FC41547CD249>I<913807FF80027F13F849B512FE01 +076E7E011F010313E0903A3FFC007FF0D97FF06D7E49486D7E4849130F48496D7E488248 +90C77E1880485A82003F17C0A3485A18E082A212FFA290B8FCA401FCCAFCA6127FA37F12 +3FA2EF03E06C7E17076C17C06C6D140F18806C6D141F6C6DEC3F006C6D147ED97FFC495A +D91FFFEB07F86D9038E03FF0010390B512C001005D023F01FCC7FC020113E033387CB63C +>IIII<133FEBFFC0 +487F487FA2487FA66C5BA26C5B6C5B013FC7FC90C8FCAEEB1FF8B5FCA512017EB3B3A6B6 +12F0A51C547CD324>I108 +DII<913801FFC0023F13FE91B67E010315E001 +0F018013F8903A3FFC001FFED97FF0EB07FF49486D7F48496D7F48496D7F91C8127F4883 +488349153F001F83A2003F8349151FA2007F83A400FF1880AC007F1800A3003F5F6D153F +A2001F5FA26C6C4B5AA26C6D4A5A6C5F6C6D495B6C6D495B6D6C4990C7FCD93FFCEB1FFE +6DB46CB45A010790B512F0010115C0D9003F49C8FC020313E039387CB642>II<90393FF001FCB590 +380FFF804B13E0037F13F09238FE1FF89138F1F83F00019138F07FFC6CEBF3E015C0ECF7 +80A2ECFF00EE3FF84AEB1FF0EE0FE093C7FC5CA45CB3ABB612FEA52E367DB535>114 +D<903903FFC00E011FEBFC1E90B6127E000315FE3907FE003FD80FF0130F484813034848 +1301491300127F90C8127EA248153EA27FA27F01F091C7FC13FCEBFF806C13FEECFFF06C +14FE6F7E6C15E06C816C15FC6C81C681133F010F15801301D9000F14C0EC003F030713E0 +150100F880167F6C153FA2161F7EA217C07E6D143F17807F6DEC7F0001F85C6DEB03FE90 +39FF801FFC486CB512F0D8F81F14C0D8F00791C7FC39E0007FF02B387CB634>I<147CA6 +14FCA41301A31303A21307A2130F131F133F137F13FF1203000F90B512FEB7FCA426007F +FCC8FCB3A9EE0F80ABEE1F006D7EA2011F143E806D6D5A6DEBC1F86DEBFFF001005C023F +1380DA03FEC7FC294D7ECB33>II E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fj ecrm0900 9 5 +/Fj 5 109 df<123C127E12FFA4127E123C08087A8715>46 D97 DI104 +D108 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fk ecbx0900 9 7 +/Fk 7 117 df65 D97 DI<903807FF80013F13F090B512FC3903FE01FE4848487EEA0FF8EA1FF0EA3FE0 +A2007F6D5A496C5A153000FF91C7FCA9127F7FA2003FEC07807F6C6C130F000FEC1F00D8 +07FE133E3903FF80FCC6EBFFF8013F13E0010790C7FC21217DA027>I<3901F81F8000FF +EB7FF0ECFFF89038F9E3FC9038FBC7FE380FFF876C1307A213FEEC03FCEC01F8EC006049 +1300B1B512F0A41F217EA024>114 D<9038FFE1C0000713FF5A383F803F387E000F1407 +5A14037EA26C6CC7FC13FCEBFFE06C13FC806CEBFF80000F14C06C14E0C6FC010F13F0EB +007F140F00F0130714037EA26C14E06C13076CEB0FC09038C01F8090B5120000F913FC38 +E03FE01C217DA023>I<133CA5137CA313FCA21201A212031207001FB51280B6FCA3D807 +FCC7FCB0EC03C0A79038FE078012033901FF0F006C13FEEB3FFCEB0FF01A2F7EAE22>I +E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fl ecrm1200 12 25 +/Fl 25 122 df<121EEA7F8012FF13C0A213E0A3127FEA1E601200A413E013C0A3120113 +80120313005A1206120E5A5A5A12600B1D78891B>44 D<14FF010713E090381F81F89038 +3E007C01FC133F4848EB1F8049130F4848EB07C04848EB03E0A2000F15F0491301001F15 +F8A2003F15FCA390C8FC4815FEA54815FFB3A46C15FEA56D1301003F15FCA3001F15F8A2 +6C6CEB03F0A36C6CEB07E0000315C06D130F6C6CEB1F806C6CEB3F00013E137C90381F81 +F8903807FFE0010090C7FC28447CC131>48 D50 D54 D<16C04B7EA34B7EA34B7EA34B7EA3ED +19FEA3ED30FFA203707FED607FA203E07FEDC03FA2020180ED801FA2DA03007F160FA202 +06801607A24A6D7EA34A6D7EA34A6D7EA20270810260147FA202E08191B7FCA249820280 +C7121FA249C87F170FA20106821707A2496F7EA3496F7EA3496F7EA201788313F8486C83 +D80FFF03037FB500E0027FEBFFC0A342477DC649>65 DI68 D77 +D<003FB912F8A3903BF0001FF8001F01806D481303003EC7150048187C0078183CA20070 +181CA30060180CA5481806A5C81600B3B3A54B7EED7FFE49B77EA33F447DC346>84 +D +I97 +D99 D<167FED3FFFA315018182B3EC7F80903803 +FFF090380FC07C90383F000E017E1307496D5AD803F87F48487F5B000F81485AA2485AA2 +127FA290C8FC5AAB7E7FA2123FA26C7EA2000F5D7F6C6C5B00035C6C6C9038077F806C6C +010E13C0013F011C13FE90380FC0F8903803FFE09026007F0013002F467DC436>II103 D105 D108 D<3901FC01FE00FF903807FFC091381E +07F091383801F8000701707F0003EBE0002601FDC07F5C01FF147F91C7FCA25BA35BB3A8 +486CECFF80B5D8F83F13FEA32F2C7DAB36>110 DI<3903F803F000FFEB1FFCEC3C3EEC707F0007EBE0FF3803F9C000015B13FBEC00 +7E153C01FF13005BA45BB3A748B4FCB512FEA3202C7DAB26>114 +D<90383FE0183901FFFC383907E01F78390F0003F8001E1301481300007C1478127800F8 +1438A21518A27EA27E6C6C13006C7E13FC383FFFE06C13FC6C13FF6C14C06C14E0C614F0 +011F13F81300EC0FFC140300C0EB01FE1400157E7E153EA27EA36C143C6C147C15786C14 +F86CEB01F039F38003E039F1F00F8039E07FFE0038C00FF01F2E7DAC26>I<1306A5130E +A4131EA3133E137EA213FE12011207001FB512F0B6FCA2C648C7FCB3A4150CAA017E131C +017F1318A26D133890381F8030ECC070903807E0E0903801FFC09038007F001E3E7EBC26 +>III< +B539F001FFFCA3000790C7EA7FE06C48EC1F8000011600160E0000150C6D141C6D1418A2 +6E1338013F1430A26D6C5BA26E13E0010F5CA26D6C485AA2ECF803010391C7FCA2903801 +FC06A2ECFE0E0100130CA2EC7F18A215B8EC3FB0A2EC1FE0A36E5AA26E5AA36EC8FCA214 +06A35CA25CA2123C007E5BB4FC5CA25CEAFE01387C0380D87007C9FCEA3C1EEA0FFCEA03 +F02E3F7EAA33>121 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fm ecbx1200 12 47 +/Fm 47 123 df<0118140C017C143E01FC147E48485C4848495A495C4848495A4848495A +001F140F90C75B003E4AC7FCA2003C141E007C143E0078143CA200F8147CA2481478D8F1 +F014F8D8F7FCEB7BFEB46CEB7FFF6D1580028014C0A36C80A36C806C496C13806C486D13 +006C486D5AD801F0EB00F82A2283C427>16 DI28 D46 D48 DIII<163FA25E5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715 +C7EC0F87EC1F07143E147E147C14F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B +485A485A485A120F5B48C7FC123E5A12FCB91280A5C8000F90C7FCAC027FB61280A53141 +7DC038>I<0007150301E0143F01FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8 +FC01C0C9FCAAEC3FF001C1B5FC01C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E +01F06D13804915C0497F6C4815E0C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317 +F05B5D6C4815E05B007EC74813C0123E003F4A1380D81FC0491300D80FF0495AD807FEEB +FFFC6CB612F0C65D013F1480010F01FCC7FC010113C02D427BC038>I<4AB47E021F13F0 +027F13FC49B6FC01079038807F8090390FFC001FD93FF014C04948137F4948EBFFE04849 +5A5A1400485A120FA248486D13C0EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381F +FF8000FF017F13E091B512F89039F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C0 +5B6F13E0A24915F0A317F85BA4127FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D +4913806C018014006C6D485A6C9038E01FFC6DB55A011F5C010714C0010191C7FC903800 +3FF02D427BC038>I<121E121F13FC90B712FEA45A17FC17F817F017E017C0A248168000 +7EC8EA3F00007C157E5E00785D15014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A +5A14035D14074A5AA2141F5D143FA2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A +6D5A2F447AC238>I58 D<1A60F101F01907191FF17FC0953801FF00F007FCF01FF0F07FC04D48C7FCEF07 +FCEF3FF0EFFFC0040390C8FCEE0FFCEE3FE0EEFF80DB03FEC9FCED0FF8ED3FE0EDFF80DA +07FECAFCEC1FF8EC7FE0903801FF80D907FCCBFCEB1FF0EB7FC04848CCFCEA07FCEA1FF0 +EA7FC048CDFCA2EA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FC903801FF809038 +007FE0EC1FF8EC07FE913800FF80ED3FE0ED0FF8ED03FE923800FF80EE3FE0EE0FFCEE03 +FF040013C0EF3FF0EF07FCEF01FF9438007FC0F01FF0F007FCF001FF9538007FC0F11FF0 +19071901F10060444277B957>60 D<126012F812FE6C7EEA3FE0EA0FF8EA03FEC66C7EEB +3FE0EB0FF8EB03FE903800FFC0EC3FF0EC0FFCEC03FF9138007FC0ED1FF0ED07FCED01FF +9238007FC0EE1FF0EE07FE933801FF809338007FE0EF1FF8EF03FE943800FF80F03FE0F0 +0FF8F003FE953800FF80F13FE0F10FF0A2F13FE0F1FF80953803FE00F00FF8F03FE0F0FF +80DD03FEC7FCEF1FF8EF7FE0933801FF80DC07FEC8FCEE1FF0EE7FC04B48C9FCED07FCED +1FF0ED7FC0DA03FFCAFCEC0FFCEC3FF0ECFFC0D903FECBFCEB0FF8EB3FE0EBFF80D803FE +CCFCEA0FF8EA3FE0EAFF8048CDFC12F81260444277B957>62 D<923803FFF0037FEBFF80 +0203B612F0020F15FC913A3FFC000FFFDAFFC0010013C0D903FEC8EA1FF0D907F0ED03F8 +D91FC0ED00FE4948167F017ECAEA1F8049717E4848717E49DAFF8013034848010F01F06D +7E4848013F01FC6D7E92B6FC4848489026C07F80137C49489026001FC0133C484948D907 +E0133E001E49486D6C131E003E49480101141F023F913800FFE0003C4A82007C017F1880 +007819074A5AA300F81AC04848491603AB6C6C7F12781B801A076E7E127C003C133F003E +6E1700021F4A5C001E6D6C5B001F6D6C49EBF01E6C6D6C011F143E6D6CD9C07F6D5A6C6C +6C90B5383FFFF8033FD9FC0F5B6C6C010FD9F0035B6C6C0100903980007F806D91CBFC6C +7E137E6D7E6D6CEF7FC0D907F0EE03FFD903FE043F1300902600FFC0913803FFF8DA3FFC +49B512C0020FB748C7FC020316E0DA007F02FCC8FC030349C9FC4A477AC557>64 +DIIII73 D77 D<923807FFC092B512FE0207ECFFC0021F15F0 +91267FFE0013FC902601FFF0EB1FFF01070180010313C04990C76C7FD91FFC6E6C7E4948 +6F7E49486F7E01FF8348496F7E48496F1380A248496F13C0A24890C96C13E0A24819F049 +82003F19F8A3007F19FC49177FA400FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C19 +F0A26E5D6C19E0A26C6D4B13C06C19806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A6D +6C4A5B6D01C001075B6D01F0011F5B010101FE90B5C7FC6D90B65A023F15F8020715C002 +004AC8FC030713C047467AC454>79 D83 D<007FBA12E0BB12F0A46C19E04406776757>95 D<903801FFE0011F13FE017F6D +7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F7F6C5A6C5AEA00F0 +90C7FCA40203B5FC91B6FC1307013F13F19038FFFC01000313E0481380381FFE00485A5B +127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1FFF80FC7F0007EBFFF8 +6CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97 DIIIIIII<137C48B4FC4813804813C0A24813E0A56C13 +C0A26C13806C1300EA007C90C7FCAAEB7FC0EA7FFFA512037EB3AFB6FCA518467CC520> +I108 D<90277F8007FEEC0FFC +B590263FFFC090387FFF8092B5D8F001B512E002816E4880913D87F01FFC0FE03FF8913D +8FC00FFE1F801FFC0003D99F009026FF3E007F6C019E6D013C130F02BC5D02F86D496D7E +A24A5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7CAC5E>I<90397F8007FEB59038 +3FFF8092B512E0028114F8913987F03FFC91388F801F000390399F000FFE6C139E14BC02 +F86D7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>II<90397FC00FF8B590B57E02C314E002CF14F89139DFC03F +FC9139FF001FFE000301FCEB07FF6C496D13804A15C04A6D13E05C7013F0A2EF7FF8A4EF +3FFCACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913806E4913006E495A9139DFC07F +FC02CFB512F002C314C002C091C7FCED1FF092C9FCADB67EA536407DAC3E>II<90387F807FB53881FFE002 +8313F0028F13F8ED8FFC91389F1FFE000313BE6C13BC14F8A214F0ED0FFC9138E007F8ED +01E092C7FCA35CB3A5B612E0A5272D7DAC2E>I<90391FFC038090B51287000314FF120F +381FF003383FC00049133F48C7121F127E00FE140FA215077EA27F01E090C7FC13FE387F +FFF014FF6C14C015F06C14FC6C800003806C15806C7E010F14C0EB003F020313E0140000 +F0143FA26C141F150FA27EA26C15C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A +00FC5CD8F03F13E026E007FEC7FC232F7CAD2C>II< +D97FC049B4FCB50103B5FCA50003EC000F6C81B3A85EA25EA25E7E6E491380017FD901F7 +13FE9138F807E76DB512C7010F1407010313FE9026007FF0EBFC00372E7CAC3E>I +I120 +D<001FB71280A49026FC001F130001E0495A5B49495A90C7485A48495B123E4A5B4A5B00 +3C495BA24A90C7FC4A5A4A5AC7FC4A5A495B495BA2495B499038800780491300A2495A49 +48130F49481400A2485B48495B485BA248495B4890C75A48485C15034848EB1FFEB7FCA4 +292C7DAB32>122 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fn ecrm1728 17.28 8 +/Fn 8 117 df68 D70 D97 D102 D<1378EA01FE487E487FA66C +90C7FC6C5AEA007890C8FCB3A2EB0780EA0FFFB5FCA41203C6FCA2137FB3B3AC497E487F +B61280A4195F7BDE25>105 D<010FEB07F8D80FFFEB1FFEB590387FFF809238F81FC091 +3801E03F913903C07FE00003EB0780C6EB0F00140E6D5A0218EB3FC00238EB1F800230EB +0600027090C7FCA2146014E0A25CA55CB3B0497E4813F0B612F8A42B3F7BBE34>114 +D<9138FFC003010FEBF807017FEBFE0F3A01FF003F9FD803F0EB07DF48486DB4FCD80F80 +1300001F8148C8FC003E81007E81127C00FC81A4827EA27E7F6C7E6D91C7FC13F8EA3FFE +381FFFE06C13FF15F0000314FE6C6E7E6C6C14E0011F14F801078001008002077FDA003F +13801507030113C0ED007F00E0ED3FE0161F17F06C150F1607A36C1503A37EA26C16E016 +077E17C06D140F6D15806D141FD8FDF0EC3F00D8F8F8147E017C495A3AF01F801FF06DB5 +12C0D8E00391C7FC39C0007FF02C417CBF35>I<1470A714F0A51301A31303A21307A213 +0FA2131F133F137F13FF1203000F90B6FCB8FCA326000FF0C8FCB3AEEE01C0AE6D6CEB03 +80A316076D6C14005E6D6C130E6D6C131E6E6C5A91383FE0F86EB45A020713C0020090C7 +FC2A597ED734>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fo ecbx1728 17.28 18 +/Fo 18 117 df68 D<942603FFF8151C94B66C +143C040F03F0147C047F03FC14FC0303B81301030FDAC00113C0033F01F8C7381FF00392 +B500C0913807F807020349C83801FE0F020F01F89238007F1F4A01E0EE3FBF4A49EE0FFF +91B5CA7E494983494983494983495B4949187F4B183F491A1F495B90B5CC120FA2484919 +075A4A19035A4A19015AA24A19005AA348491A7CA35A9AC8FCA35CA2B5FCB07EA26E043F +B81280A47E96C7000701FCC7FCA26C7FA37E80A27E807E807E6C7FA26D7F6D7F7F816D7F +6D6D5F6D7F6D6D5F6D6D7E023F6D5E6E01F05E6E6DEEFE7F020301FF923801FC3F020002 +C0913807F80F033F01FC91381FF007030F903BFFE001FFC001030391B6EA8000DB007F4B +C7123C040F03F8140C040003C091C8FC050301F8CBFC696677E37A>71 +D82 D<001FBD12F0A59126F8000191C7123F4801C0 +060713F849C71700491A7F01F01A1F491A0F491A07A2491A03A290C81801A2007EF300FC +A4007C1C7CA7481C3EA5C91900B3B3B3A5023FB912F8A55F617AE06C>84 +D<913803FFF0027F13FF0103B612E0010F15F890263FFC0013FED97FC090381FFF8049C7 +6C7F4801C06D7F486D6D7F6E6D7F48836E7F84177F84A36C496E7FA26C5B6C5B013FC8FC +90C9FCA75F0307B6FC4AB7FC141F91B5EAF03F0103EBFE00010F13F0013F1380D9FFFEC7 +FC485B485B485B485B485B485BA24890C8FC1A7CA2485AA35FA394B5FC7F6C5D6EEB03DF +6CDB07CFEBC0F86C6DEB0F8F6C6DD91F07EBF3F06C01F8017E14FF6C9027FE01FC0314E0 +C690B5D8F00114C0013F9126C0007F1380010791C7383FFE009026003FF8EC07F846437B +C14D>97 D<903807FF80B6FCA5C6FC7F7FB3A9933801FFE0041F13FE047FEBFFC00381B6 +12F0922687FC0113FC923A9FE0003FFEDBBF8090380FFF8003FEC76C7F4B6E7F4B6E7F4B +6E7F4B824B157F4B82737EA21B80851BC0A31BE085A41BF0AE1BE0A44F13C0A31B80A24F +1300A262197F6F5E6F4B5A4E5B6F4A5BDAFCF84A5BDAF87E4A5B4A6C4A90C7FC9126E01F +C0EB7FFC913BC00FF803FFF8DA8003B612E091C71580013E023F01FCC8FC90C800031380 +4C657CE356>II101 DII105 D<903807FF80B6FCA5C6FC7F7FB3B3B3B3AFB7 +12E0A523647CE32A>108 D110 D<92381FFF804AB512F8020F +14FF023F15C09126FFFC0313F001039039E0007FFC490180EB1FFED91FFEC73807FF8049 +486E7F49486E7F49486E7F48496F7EA248496F7E4884A248496F7EA2481980A24819C091 +C97EA24819E0A5B518F0AD6C19E0A46C6D4B13C0A36C1980A26C6D4B1300A26C606E157F +6C606C6D4B5A6C606D6C4A5B6D6C4A5B6D6C4A5B6D6C6C011F90C7FC010301E0EB7FFC6D +9039FC03FFF86D6CB612E0020F92C8FC020114F8DA001F138044437CC14D>I<903B07FF +8001FFE0B6011F13FE047FEBFFC00381B612F0922687FC0313FC923A9FE0007FFEC6DABF +806D6C7E6D01FEC7000F7F6D496E7F4B824B6E7F4B6E7F4B804B82737EA21B80851BC0A2 +851BE0A4851BF0AE4F13E0A41BC061A21B80A24F1300A24F5AA26F4A5B6F4A5B626F4A5B +6F4A5B03FE4A5B03BF027F90C7FCDB9FC0EBFFFC92268FF8075B0383B612E00380158004 +3F01FCC8FC0403138093CBFCB3A4B712E0A54C5D7CC056>I114 DII E +%EndDVIPSBitmapFont +end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 600dpi +TeXDict begin +%%PaperSize: A4 + +%%EndSetup +%%Page: 1 1 +1 0 bop 290 639 a Fo(Genealogical)56 b(Represen)l(tation)e(of)f(T)-13 +b(rees)52 b(in)g(Databases)1686 822 y Fn(First)46 b(Draft)1247 +1063 y Fm(Miguel)36 b(Sofer)i()1359 1179 +y Fl(Univ)m(ersidad)33 b(T)-8 b(orcuato)33 b(Di)f(T)-8 +b(ella)1728 1295 y(Buenos)33 b(Aires)1797 1411 y(Argen)m(tina)1746 +1606 y(Ma)m(y)h(6,)e(2000)1839 1905 y Fk(Abstract)441 +2035 y Fj(blah)25 b(blah)h(.)13 b(.)g(.)118 2310 y Fi(1)131 +b(In)l(tro)t(duction)118 2491 y Fh(T)-7 b(rees)28 b(are)h(a)g(v)n(ery)f +(frequen)n(t)h(data)f(structure.)41 b(They)30 b(are)e(the)h(natural)g +(represen)n(tation)e(for)i(instance)g(for)f(organiza-)118 +2591 y(tional)f(c)n(harts,)g(threaded)g(discussion)g(groups,)f(some)h +(bills)g(of)h(materials,)e(.)14 b(.)g(.)243 2691 y(A)n(t)28 +b(least)f(t)n(w)n(o)f(alternativ)n(e)h(represen)n(tations)e(for)i +(trees)g(in)h(RDBMs)g(are)e(kno)n(wn)h(and)h(used:)220 +2857 y(1.)41 b Fg(P)m(oin)m(ters:)k Fh(a)31 b(\034eld)h(in)h(the)f(c)n +(hild)g(record)e(references)h(the)h(paren)n(t)f(no)r(de.)50 +b(This)32 b(seems)g(to)f(b)r(e)i(the)f(canonical)326 +2956 y(represen)n(tation.)38 b(Some)29 b(DB)g(engines)f(pro)n(vide)g +(sp)r(ecial)g(SQL)g(extensions)g(to)h(simplify)g(tree)g(searc)n(hes;)e +(Oracle)326 3056 y(tree)d(extensions)g(are)g(an)h(example)f(\(see)h +(for)f(instance)g([1]\);)i(DB2's)f(WITH)g(can)f(b)r(e)i(used)e(for)h +(this)g(purp)r(ose)f(to)r(o)326 3156 y(\(see)j([3],)g(pp)h(139-162\).) +220 3322 y(2.)41 b Fg(Nested)35 b(Sets:)43 b Fh(t)n(w)n(o)30 +b(n)n(umeric)h(\034elds)g(in)g(ev)n(ery)f(no)r(de)h(record)f(co)r(de)h +(the)g(tree)g(structure.)47 b(I)31 b(can't)g(pro)n(vide)f(a)326 +3421 y(b)r(etter)e(or)e(briefer)h(description)g(of)h(this)g(metho)r(d)g +(than)f(the)h(four)f(articles)g([2].)118 3587 y(These)g(t)n(w)n(o)g +(metho)r(ds)h(o\033er)f(di\033eren)n(t)h(adv)-5 b(an)n(tages)25 +b(and)j(disadv)-5 b(an)n(tages:)243 3753 y Ff(\017)41 +b Fh(P)n(oin)n(ters)30 b(are)g(extremely)g(e\036cien)n(t)h(for)f(no)r +(de)h(insertion)f(and/or)g(deletion,)h(but)h(require)e(recursiv)n(e)f +(table)i(ac-)326 3853 y(cesses)e(to)h(searc)n(h)f(the)h(tree)g(\(I)h +(do)f(not)g(kno)n(w)f(the)i(implemen)n(tation)f(details)g(of)g(the)h +(Oracle)e(tree)g(extensions,)326 3953 y(whic)n(h)e(as)g(far)g(as)g(I)g +(kno)n(w)g(ma)n(y)g(solv)n(e)f(this)i(problem)f(in)n(ternally;)g(they)g +(de\034nitely)h(solv)n(e)f(it)g(for)g(the)h(end)g(user\).)243 +4119 y Ff(\017)41 b Fh(Nested)30 b(sets)g(are)f(v)n(ery)f(e\036cien)n +(t)i(for)g(tree)f(searc)n(hes,)g(but)i(are)e(rather)f(exp)r(ensiv)n(e)i +(for)f(no)r(de)h(insertion)f(and/or)326 4218 y(deletion:)37 +b(they)27 b(require)g(up)r(dating)g(p)r(oten)n(tially)h(man)n(y)f(no)r +(des.)243 4384 y(W)-7 b(e)30 b(prop)r(ose)f(here)h(a)g(di\033eren)n(t)h +(represen)n(tation,)e(based)g(on)i(no)r(de)f(iden)n(ti\034ers)g(whic)n +(h)g(are)f(\020genealogical)f(iden)n(ti-)118 4484 y(\034ers\021:)44 +b(they)32 b(con)n(tain)f(the)h(complete)f(genealogy)f(of)h(the)h(no)r +(de,)h(i.e.,)g(the)f(list)g(of)g(ancestors)d(up)j(to)g(the)g(ro)r(ot)f +(of)g(the)118 4584 y(tree.)243 4683 y(This)j(allo)n(ws)f(to)i(replace)e +(man)n(y)h(searc)n(hes)f(in)h(database)g(tables)g(with)h(string)f(op)r +(erations)f(on)h(the)h(index.)58 b(The)118 4783 y(result,)24 +b(as)f(explained)h(in)g(Section)g(3)f(is)h(that)g(tree)f(searc)n(hes)f +(pro)r(ceed)h(at)h(\020nested)f(sets\021)30 b(sp)r(eed,)25 +b(while)f(no)r(de)g(insertions)118 4882 y(and)k(deletions)f(are)f(as)h +(fast)h(as)f(with)h(p)r(oin)n(ters.)243 4982 y(The)i(ob)n(vious)f(do)n +(wnside)h(of)h(the)g(metho)r(d)g(is)f(that)h(the)g(primary)f(k)n(ey)f +(in)i(the)g(tree)f(needs)h(to)f(b)r(e)h(a)g(v)-5 b(ariable)29 +b(size)118 5082 y(text)j(\034eld,)h(and)f(that)g(the)g(iden)n +(ti\034ers)f(ma)n(y)g(b)r(e)i(extremelly)e(long)g(for)g(deep)h(trees.) +49 b(W)-7 b(e)32 b(will)g(pro)n(vide)e(estimates)i(of)118 +5181 y(the)c(size)f(required)g(as)g(a)g(function)h(of)g(the)f +(magnitude)h(of)f(the)h(tree.)1987 5653 y(1)p eop +%%Page: 2 2 +2 1 bop 118 291 a Fi(2)131 b(Genealogical)45 b(iden)l(ti\034ers)g(for)f +(trees)118 489 y Fm(2.1)112 b(De\034nition)118 642 y +Fh(W)-7 b(e)28 b(de\034ne)g Fe(gene)l(alo)l(gic)l(al)k(identi\034ers)j +Fh(recursiv)n(ely)25 b(as)i(follo)n(ws:)326 808 y Fg(De\034nition:)59 +b Fe(The)42 b(gene)l(alo)l(gic)l(al)h(identi\034er)f(\(gID\))e(of)i(a)f +(no)l(de)h(is)f(obtaine)l(d)h(by)g(app)l(ending)g(a)f(child)326 +908 y(identi\034er)30 b(to)g(the)g(gene)l(alo)l(gic)l(al)h +(identi\034er)g(of)f(the)g(p)l(ar)l(ent)f(no)l(de.)243 +1074 y Fh(Remark)40 b(that)h(genealogical)e(iden)n(ti\034ers)i(are)f +(rather)g(w)n(ell)h(kno)n(wn)f(and)h(used;)48 b(common)41 +b(examples)f(are)g(the)118 1174 y(\020path+\034le-name\021)33 +b(in)28 b(a)f(computer)g(\034le)h(system)f(and)h(the)f(URLs)h(within)g +(a)f(WWW.)243 1273 y(The)d(name)g(\020genealogical)e(iden)n +(ti\034er\021)30 b(is)24 b(suggested)g(b)n(y)g(the)g(fact)h(that)f(the) +h(v)-5 b(alue)24 b(of)g(the)h(iden)n(ti\034er)f(con)n(tains)f(the)118 +1373 y(complete)30 b(genealogy)d(of)j(the)g(no)r(de:)41 +b(it)30 b(con)n(tains)e(as)h(a)h(substring)f(the)h(gID)f(of)h(its)g +(father,)g(whic)n(h)f(in)h(turn)g(con)n(tains)118 1472 +y(as)d(a)g(substring)g(the)h(gID)g(of)f(the)h(grandfather,)e(.)14 +b(.)g(.)243 1572 y(The)27 b(ro)r(ot)g(no)r(de)h(of)f(the)h(tree)f(has)g +(a)h(gID)f(with)h(v)-5 b(alue)28 b(\021)34 b(\(the)28 +b(empt)n(y)g(string\),)f(as)g(it)h(has)f(no)g(paren)n(t.)118 +1804 y Fm(2.2)112 b(Child)36 b(iden)m(ti\034ers)118 1958 +y Fh(The)26 b(ob)n(vious)e(c)n(hild)i(iden)n(ti\034er)g(is)f(a)h +(zero-based)d(coun)n(ter:)35 b(iden)n(tify)26 b(the)h(c)n(hild)e(b)n(y) +h(the)g(n)n(um)n(b)r(er)f(of)h(older)f(brethren)g(it)118 +2057 y(has.)243 2157 y(W)-7 b(e)25 b(could)f(represen)n(t)g(the)h(coun) +n(ter)f(in)h(base)f(10;)h(this)g(ho)n(w)n(ev)n(er)e(is)i(extremely)f(w) +n(asteful)g(of)h(resources.)34 b(It)25 b(is)g(m)n(uc)n(h)118 +2257 y(b)r(etter)33 b(to)f(represen)n(t)f(the)h(coun)n(ter)g(in)g(as)g +(large)e(a)i(base)g(as)f(p)r(ossible:)46 b(in)n(terpret)32 +b(as)f(n)n(um)n(b)r(ers)h(a)g(set)g(of)g(c)n(haracters)118 +2356 y(larger)26 b(than)h({0,1,.)14 b(.)g(.)g(9}.)243 +2456 y(As)26 b(tree)f(op)r(erations)f(will)i(in)n(v)n(olv)n(e)f(string) +g(op)r(erations)f(on)i(the)g(indices,)g(in)g(order)f(to)g(a)n(v)n(oid)g +(a)g(\020quoting)g(hell\021)33 b(it)26 b(is)118 2555 +y(desirable)d(to)h(a)n(v)n(oid)e(using)h(an)n(y)g(c)n(haracter)f(with)i +(a)g(sp)r(ecial)f(meaning)h(in)g(LIKE)g(expressions)e(or)g(regular)g +(expressions;)118 2655 y(i.e.,)28 b(w)n(e)f(will)h(not)f(use)h(an)n(y)f +(of)g(the)h(sym)n(b)r(ols)70 b Fd(.)44 b(*)f(^)g(\\)g([)g(])g({)h(})f +(\()g(\))g(<)g(>)71 b Fh(?)37 b(|)28 b(&)f($)243 2755 +y(W)-7 b(e)28 b(prop)r(ose)e(to)h(reserv)n(e)f(also)g(/)i(as)f(a)g +(separator)e(\(see)i(\020V)-7 b(ariable)27 b(Sized)g(gID\021)34 +b(b)r(elo)n(w\).)243 2854 y(If)g(w)n(e)f(limit)i(ourselv)n(es)d(to)i +(ascii)f(c)n(haracters,)g(and)h(a)n(v)n(oid)e(to)i(b)r(e)g(safe)f(a)h +(lot)g(of)g(other)f(c)n(haracters,)g(w)n(e)g(can)h(use)118 +2954 y(n)n(um)n(b)r(ers)27 b(in)h(base)f(64)g(b)n(y)g(represen)n(ting) +243 3120 y Ff(\017)41 b Fh(0-9)26 b(with)i('0'-'9')f(\(dec)g(ascii)g +(co)r(de)h(48-57\))243 3286 y Ff(\017)41 b Fh(10)26 b(with)i(':')37 +b(\(dec)28 b(ascii)f(co)r(de)h(58\))243 3452 y Ff(\017)41 +b Fh(11)26 b(with)i(';')g(\(dec)g(ascii)f(co)r(de)g(59\))243 +3618 y Ff(\017)41 b Fh(12-37)25 b(with)j('A'-'Z')g(\(dec)f(ascii)g(co)r +(de)h(65-90\))243 3784 y Ff(\017)41 b Fh(38-63)25 b(with)j('a'-'z')f +(\(dec)h(ascii)f(co)r(de)g(97-122\))118 3950 y(By)g(using)g(base)f(64,) +h(up)g(to)h(4096)d(c)n(hildren)i(can)f(b)r(e)i(represen)n(ted)e(using)h +(t)n(w)n(o)f(suc)n(h)h(digits,)g(up)h(to)f(262144)d(with)k(three)118 +4050 y(digits,)g(and)f(up)h(to)f(16777216)d(with)k(four)f(digits.)243 +4149 y(If)37 b(the)g(RDBMs)g(supp)r(orts)f(in)n(ternational)g(c)n +(haracters,)h(it)g(is)g(p)r(ossible)f(to)h(further)f(increase)g(the)h +(base;)k(as)36 b(an)118 4249 y(example,)30 b(b)n(y)f(using)g(the)h(95)f +(additional)g(c)n(haracters)e(of)i(the)h(latin-1)f(c)n(haracter)e(set,) +k(w)n(e)e(could)g(co)r(de)g(n)n(um)n(b)r(ers)g(in)h(a)118 +4349 y(base)f(up)g(to)g(160)f(\025)g(remark)g(that)h(ev)n(ery)f(single) +h(digit)g(is)g(still)h(one)e(b)n(yte)h(in)h(this)f(represen)n(tation.) +40 b(This)29 b(means)f(that)118 4448 y(w)n(e)f(expand)h(the)f(sym)n(b)r +(ols)g(ab)r(o)n(v)n(e)f(b)n(y)i(represen)n(ting)243 4614 +y Ff(\017)41 b Fh(64-159)25 b(with)j(dec)f(latin1)g(co)r(de)h(160-255) +243 4780 y(In)23 b(base)g(160,)g(up)g(to)h(25600)d(c)n(hildren)i(can)f +(b)r(e)i(represen)n(ted)e(using)h(t)n(w)n(o)g(digits,)h(up)g(to)f +(4096000)d(with)k(three)f(digits,)118 4880 y(and)28 b(up)f(to)h +(6.5E+08)e(with)i(four)f(digits.)243 4980 y(Remark)g(that)h(base)f(con) +n(v)n(ersions)f(only)h(need)i(to)e(b)r(e)i(p)r(erformed)e(at)h +(insertion)g(time,)g(when)h(the)f(index)g(of)g(a)g(new)118 +5079 y(no)r(de)g(is)f(computed.)37 b(They)28 b(will)f(therefore)g(only) +g(ha)n(v)n(e)f(an)i(impact)f(on)h(insertion)f(timings.)1987 +5653 y(2)p eop +%%Page: 3 3 +3 2 bop 118 291 a Fm(2.3)112 b(Coun)m(ters:)50 b(\020delimited\021)44 +b(vs.)51 b(\020\034xed)38 b(size\021)118 444 y Fh(The)33 +b(standard)g(represen)n(tation)e(of)i(gID)h(uses)e(a)h(v)-5 +b(ariable)32 b(size)h(c)n(hild)h(iden)n(ti\034er,)g(and)f(delimiters)g +(to)h(separate)d(the)118 543 y(gID)f(of)g(the)h(c)n(hild)f(no)r(de)g +(from)f(the)i(gID)f(of)g(its)g(paren)n(t.)43 b(F)-7 b(or)30 +b(example,)g(w)n(e)g(can)f(represen)n(t)g(the)i(\034fth)g(c)n(hild)f +(of)g(no)r(de)118 643 y('/23/27/1')24 b(as)j('/23/27/1/4'.)32 +b(Let)c(us)f(call)g(this)h(a)f Fg(vgID)h Fh(represen)n(tation)e(\(V)-7 +b(ariable)27 b(Size)h(Genealogical)d(ID\).)243 743 y(This)30 +b(represen)n(tation)f(allo)n(ws)f(for)i(an)n(y)g(n)n(um)n(b)r(er)g(of)g +(c)n(hildren)g(of)h(a)f(no)r(de,)h(sub)5 b(ject)30 b(only)g(to)g(the)h +(limitations)f(the)118 842 y(RDBMS)e(ma)n(y)f(ha)n(v)n(e)f(as)h(to)h +(the)g(length)f(of)h(a)f(v)-5 b(ariable)27 b(sized)g(string.)243 +942 y(Alternativ)n(ely)-7 b(,)24 b(w)n(e)f(could)h(c)n(ho)r(ose)f(to)h +(limit)g(from)g(the)g(outset)g(the)g(quan)n(tit)n(y)g(of)f(c)n(hildren) +h(that)g(a)g(no)r(de)g(ma)n(y)f(ha)n(v)n(e;)118 1042 +y(this)28 b(limit)g(w)n(ould)f(dep)r(end)i(of)e(course)f(on)i(the)g +(application.)36 b(Let)27 b(us)h(call)f(this)h(a)f Fg(fgID)h +Fh(represen)n(tation.)243 1141 y(F)-7 b(or)25 b(example,)h(if)g(no)g +(no)r(de)f(is)h(allo)n(w)n(ed)f(to)g(ha)n(v)n(e)g(more)g(than)h(25600)d +(c)n(hildren,)j(w)n(e)g(could)f(represen)n(t)g(the)h(coun)n(ters)118 +1241 y(alw)n(a)n(ys)36 b(with)i(2)f(digits.)67 b(The)38 +b(no)r(de)f(whic)n(h)h(w)n(as)f(previously)f('/23/27/1/4')d(is)k(no)n +(w)g('23270104'.)64 b(If)38 b(w)n(e)f(require)118 1340 +y(a)g(three)g(digit)h(represen)n(tation)d(of)i(no)r(des)g(\(up)h(to)f +(ab)r(out)h(4)f(million)g(c)n(hildren\),)j(then)d(it)h(will)g(b)r(e)f +(represen)n(ted)f(as)118 1440 y('023027001004'.)118 1672 +y Fm(2.4)112 b(Ordering)37 b(of)h(no)s(des)118 1825 y +Fh(F)-7 b(or)35 b(some)g(applications)g(it)h(is)f(necessary)f(to)i +(obtain)f(subtrees)g(ordered)f(according)g(to)i(some)f(sp)r(ecial)g +(rules.)60 b(F)-7 b(or)118 1925 y(instance:)220 2090 +y(1.)41 b(the)34 b(complete)g(subtree)f(starting)g(at)h(a)f(no)r(de)h +(is)g(listed)g(immediately)g(after)f(the)i(no)r(de)f(in)g(question)f +(\(\020depth)326 2189 y(\034rst\021\))220 2354 y(2.)41 +b(no)r(des)27 b(with)h(a)f(common)g(paren)n(t)g(are)g(listed)g(c)n +(hronologically)243 2519 y(F)-7 b(or)39 b(instance,)k(the)d(displa)n(y) +f(of)h(an)f(organization)f(c)n(hart)h(is)g(usually)h(required)e(to)i +(satisfy)g(at)f(least)h(the)g(\034rst)118 2619 y(condition.)h(In)29 +b(a)g(threaded)f(discussion)h(group)e(one)i(wishes)g(to)f(satisfy)h(b)r +(oth)h(conditions)e(to)h(displa)n(y)f(the)h(messages)118 +2718 y(in)20 b(a)g(thread)g(\025)f(the)i(threads)e(themselv)n(es)h +(\(i.e.,)i(c)n(hildren)e(of)g(the)g(ro)r(ot)f(no)r(de\))i(are)e +(usually)g(listed)i(in)f(in)n(v)n(erse)f(c)n(hronolical)118 +2818 y(order.)243 2917 y(T)-7 b(o)35 b(mak)n(e)f(a)h(particular)f +(ordering)g(e\036cien)n(t,)j(it)f(w)n(ould)f(b)r(e)h(a)f(nice)g +(feature)g(if)h(it)g(could)f(b)r(e)h(made)f(to)g(coincide)118 +3017 y(with)28 b(a)f(lexicographic)f(ordering)f(of)j(the)g(indices)f +(\025i.e.,)g(as)g(pro)r(duced)g(b)n(y)h(an)f(\020ORDER)h(BY)f(id)h +(ASC\021)35 b(in)27 b(SQL.)h(The)118 3117 y(lexicographic)d(ordering)h +(of)h(fgID)h(satis\034es)e(b)r(oth)i(conditions.)36 b(The)27 +b(lexicographic)f(ordering)f(of)i(vgID)g(as)g(describ)r(ed)118 +3216 y(ab)r(o)n(v)n(e)34 b(satis\034es)g(the)h(\034rst)g(requisite)f +(if)i(the)f(separator)d(has)j(the)g(minimal)g(binary)g(represen)n +(tation)e(of)i(all)f(allo)n(w)n(ed)118 3316 y(sym)n(b)r(ols)c(in)h(an)f +(index)h(\025)f(this)h(is)g(wh)n(y)f(w)n(e)g(reserv)n(ed)f(/)h(for)g +(the)i(separator.)43 b(But)31 b(the)g(second)f(prop)r(ert)n(y)g(is)g +(missing:)118 3416 y(for)d(instance,)g(the)h(index)g('/1/10')d(is)j +(lexicographically)d(b)r(efore)i('/1/2'.)243 3515 y(If)c(the)h(second)e +(prop)r(ert)n(y)g(is)i(also)e(required)g(for)h(vgID,)g(w)n(e)f(can)h +(sp)r(ecify)h(the)f(c)n(hild)h(iden)n(ti\034ers)e(with)i(coun)n(ters)e +(built)118 3615 y(in)28 b(the)g(follo)n(wing)e(w)n(a)n(y:)36 +b(represen)n(t)26 b(a)h(n)n(um)n(b)r(er)h(b)n(y)f(a)g(string)g(of)g +(digits,)h(where)243 3779 y Ff(\017)41 b Fh(the)25 b(\034rst)g(digit)h +Fc(D)896 3791 y Fb(0)958 3779 y Fh(represen)n(ts)e(the)i(length)f(in)h +(digits)f(of)g(the)h(decimal)f(expansion)f(of)i(the)f(n)n(um)n(b)r(er,) +h(min)n(us)f(one)243 3945 y Ff(\017)41 b Fh(the)28 b(follo)n(wing)e +Fa(\()p Fc(D)920 3957 y Fb(0)976 3945 y Fa(+)18 b(1\))27 +b Fh(digits)h(are)e(the)i(decimal)g(expansion)e(of)i(the)g(n)n(um)n(b)r +(er)118 4109 y(Let)g(us)f(call)h(these)f(iden)n(ti\034ers)g +Fg(m-vgID)p Fh(,)g(\020m\021)34 b(for)27 b(mo)r(di\034ed.)243 +4209 y(As)e(an)f(example,)h(the)g(no)r(de)g(whic)n(h)g(w)n(as)f +(previously)f(represen)n(ted)h(b)n(y)g(/15/3/182)d(will,)k(after)g +(this)g(mo)r(di\034cation,)118 4309 y(ha)n(v)n(e)h(the)i(index)g +(/115/03/2182.)243 4408 y(The)37 b(lexicographic)f(ordering)g(of)i +(m-vgID)f(is)h(the)g(desired)f(ordering)f(of)h(the)h(tree)g(no)r(des.) +67 b(The)38 b(cost)f(of)g(this)118 4508 y(prop)r(ert)n(y)31 +b(is)i(that)f(\(a\))h(the)g(ID)f(are)g(no)n(w)g(longer,)g(\(b\))h(no)f +(no)r(de)g(can)g(ha)n(v)n(e)g(more)f(than)i Fa(160)3106 +4478 y Fb(160)3240 4508 y Fh(c)n(hildren)f(\(actually)-7 +b(,)118 4607 y(this)32 b(is)g(a)f(non-issue\),)h(and)f(\(c\))h(the)g +(index)g(structure)f(is)h(redundan)n(t,)g(some)f(formally)f(correct)h +(indices)g(are)g(in)n(v)-5 b(alid)118 4707 y(\025e.g.,)24 +b(/316/013/11.)30 b(The)24 b(third)g(issue)g(can)g(b)r(e)g(addressed)f +(b)n(y)g(k)n(eeping)g(a)h(strict)g(con)n(trol)e(on)i(the)g(generation)f +(of)h(new)118 4807 y(indices)k(to)f(insure)g(that)h(all)f(indices)h +(are)e(formally)h(correct.)243 4906 y(The)32 b(issue)f(of)h(the)g(rev)n +(erse)e(c)n(hronological)f(indexing)j(of)f(threads)h(in)g(threaded)f +(discussion)g(groups)g(can)g(b)r(e)h(ad-)118 5006 y(dressed)d(easily)f +(enough)h(in)h(fgID:)f(coun)n(t)g(\020do)n(wn\021)36 +b(instead)29 b(of)g(\020up\021)36 b(the)30 b(c)n(hildren)f(of)g(the)h +(ro)r(ot)e(no)r(de)i(\025)f(this)h(implies)118 5106 y(only)e(an)g +(inconsequen)n(tial)f(mo)r(di\034cation)h(of)g(the)g(no)r(de)h +(insertion)e(routine,)h(as)g(sho)n(wn)f(b)r(elo)n(w.)38 +b(The)29 b(problem)e(is)h(less)118 5205 y(trivial)i(with)g(vgID;)h(in)f +(this)h(case,)f(ma)n(yb)r(e)f(a)h(thread)g(iden)n(ti\034er)g(should)g +(b)r(e)h(k)n(ept)f(in)g(a)g(di\033eren)n(t)g(\034eld)h(-)f(i.e.,)h +(repre-)118 5305 y(sen)n(ting)h(the)h(structure)f(as)g(a)h(forest)f +(rather)f(than)i(a)f(tree,)i(where)e(the)h(thread_id)f(\034eld)h +(selects)f(the)h(\020tree\021)38 b(in)33 b(the)118 5404 +y(forest.)1987 5653 y(3)p eop +%%Page: 4 4 +4 3 bop 118 291 a Fi(3)131 b(T)-11 b(ree)45 b(op)t(erations)e(using)h +(genealogical)g(indices)118 472 y Fh(In)32 b(this)f(section)g(w)n(e)g +(sho)n(w)g(ho)n(w)g(to)g(implemen)n(t)h(v)-5 b(arious)30 +b(tree)h(op)r(erations)f(using)h(gID)g(as)g(the)h(primary)e(k)n(ey)h +(in)g(the)118 572 y(no)r(de)d(table.)243 672 y(Some)h(implemen)n +(tation)h(issues)g(are)f(relev)-5 b(an)n(t)29 b(here,)h(esp)r(ecially)f +(concerning)g(the)h(utilisation)g(of)g(indices)g(b)n(y)f(the)118 +771 y(DB)f(engine.)243 871 y(W)-7 b(e)28 b(discuss)f(a)g(tree)g +(represen)n(ted)f(in)i(a)f(table)h(of)f(the)h(form)326 +1034 y Fd(CREATE)41 b(TABLE)g(tree)h(\()456 1134 y(gid)304 +b(text)42 b(PRIMARY)f(KEY,)456 1234 y(nchildren)f(integer)h(DEFAULT)f +(0,)456 1333 y(\\ldots)h(the)i(actual)e(node)h(data)326 +1433 y(\);)118 1597 y Fh(The)26 b(\034eld)g(\020nc)n(hildren\021)32 +b(is)26 b(a)f(coun)n(ter)g(for)g(the)i(n)n(um)n(b)r(er)e(of)h(c)n +(hildren)f(that)h(the)h(no)r(de)f(has)f Fe(ever)35 b +Fh(had;)27 b(w)n(e)e(assume)g(here)118 1696 y(it)j(is)g(not)f(up)r +(dated)h(when)g(no)r(des)f(or)g(subtrees)g(are)f(deleted.)243 +1796 y(Section)h(4)g(pro)n(vides)f(a)i(complete)f(implemen)n(tation)h +(of)f(these)h(op)r(erations)e(for)h(fgID)h(in)g(P)n(ostgreSQL.)118 +2028 y Fm(3.1)112 b(Computing)37 b(the)g(lev)m(el)f(of)h(a)h(no)s(de) +118 2181 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations)g(\(no)g(table)g +(ac)l(c)l(ess\))243 2280 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r +(eration,)f(no)i(table)f(access)g(is)g(required.)243 +2460 y Ff(\017)41 b Fg(vgID:)27 b Fh(coun)n(t)h(the)g(n)n(um)n(b)r(er)f +(of)g(separators)e(\('/'\))j(in)g(the)g(PK)243 2625 y +Ff(\017)41 b Fg(fgID:)27 b Fh(coun)n(t)g(the)h(n)n(um)n(b)r(er)g(of)f +(c)n(haracters)e(in)j(the)g(PK,)g(divide)g(b)n(y)f(the)h(\034xed)f +(size)h(of)f(the)h(coun)n(ters.)118 2857 y Fm(3.2)112 +b(Selecting)36 b(or)h(deleting)f(a)i(subtree)118 3010 +y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +3173 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g +(/26/5/7)e(is)i(selected)g(b)n(y)508 3338 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('/26/5/7\045')d(AND)j(id)h(<)g('/26/5/70')243 +3503 y Ff(\017)e Fg(m-vgID:)26 b Fh(The)h(subtree)h(ro)r(oted)e(at)i +(/126/05/07)22 b(is)28 b(selected)f(b)n(y)508 3668 y +Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07\045')243 +3833 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g +(260507)e(is)i(selected)h(b)n(y)508 3997 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('260507\045')118 4229 y Fm(3.3)112 +b(Selecting)36 b(the)h(direct)f(c)m(hildren)g(of)i(a)g(no)s(de)118 +4382 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +4562 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h +(/26/5/7)c(are)j(selected)g(b)n(y)508 4727 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('/26/5/7/\045')d(AND)j(id)h(NOT)f(LIKE)g +('26/5/7/\045/\045')243 4892 y Ff(\017)f Fg(m-vgID:)26 +b Fh(The)h(direct)h(c)n(hildren)f(of)g(/26/5/7)e(are)h(selected)i(b)n +(y)508 5056 y Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07/\045')37 +b(AND)43 b(id)f(NOT)h(LIKE)f('/126/05/07/\045/\045)o(')243 +5221 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h +(260507)c(are)j(selected)g(b)n(y)508 5386 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('260507\045')d(AND)k(char_length\(id\))37 +b(=)43 b(\(char_length\('26)o(05)o(07')o(\)+)o(2\))1987 +5653 y Fh(4)p eop +%%Page: 5 5 +5 4 bop 118 291 a Fm(3.4)112 b(Inserting)37 b(a)h(no)s(de)g(or)f(a)h +(subtree)118 444 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l +(e)l(e)f(+)h(string)f(and)h(math)g(op)l(er)l(ations)243 +543 y Fh(Insertion)f(is)g(a)h(pro)r(cedural)e(op)r(eration.)42 +b(As)30 b(eac)n(h)f(RDBMS)h(has)f(a)h(di\033eren)n(t)f(w)n(a)n(y)g(of)g +(de\034ning)h(pro)r(cedures,)f(w)n(e)118 643 y(will)f(just)g(describ)r +(e)f(here)g(the)h(necessary)e(steps.)37 b(Examples)27 +b(for)g(P)n(ostgreSQL)f(are)h(pro)n(vided)f(in)i(4.)243 +743 y(In)22 b(order)f(to)h(insert)g(a)g(new)g(c)n(hild)h(of)f +(\020daddy\021)28 b(\(either)23 b(one)f(of)g(/26/5/7,)e(/126/05/07)d +(or)22 b(260507)d(in)k(the)f(examples)118 842 y(ab)r(o)n(v)n(e\))27 +b(y)n(ou)f(ha)n(v)n(e)h(to)220 1008 y(1.)41 b(add)27 +b(one)g(to)h(the)g(n)n(um)n(b)r(er)f(of)g(c)n(hildren)h(of)f +(\020daddy\021)508 1174 y Fd(UPDATE)41 b(tree)h(SET)h(nchildren)c(=)k +(\(nchildren)d(+)j(1\))g(WHERE)e(ID)i(=)g(``daddy'';)220 +1340 y Fh(2.)e(enco)r(de)27 b(the)h(n)n(um)n(b)r(er)f(of)g(c)n(hildren) +g(of)h(\020daddy\021)33 b(in)28 b(base)f(160,)f(bring)h(it)h(to)f(the)h +(correct)e(format)h(dep)r(ending)h(on)326 1440 y(the)c(v)-5 +b(arian)n(t)23 b(of)h(gID)g(\(pad)g(with)h(0)e(or)g(not,)i(prep)r(end)f +(a)g(digit)g(coun)n(ter)f(or)g(not,)i(prep)r(end)f(/)g(or)f(not,)i +(coun)n(t)e(do)n(wn)326 1540 y(or)j(up,)i(.)14 b(.)g(.)g(\))37 +b(and)28 b(app)r(end)f(it)h(to)g(daddy's)f(gID)g(to)h(obtain)f(the)h +(new)g(no)r(de's)f(gID.)220 1706 y(3.)41 b(insert)27 +b(the)h(new)f(no)r(de)243 1872 y(When)35 b(inserting)g(a)f(subtree,)j +(the)e(index)g(of)g(the)h(ro)r(ot)e(of)h(the)g(subtree)g(has)f(to)h(b)r +(e)h(computed)f(as)f(ab)r(o)n(v)n(e,)i(and)118 1971 y(prep)r(ended)28 +b(to)f(the)h(index)g(of)f(eac)n(h)g(no)r(de)h(of)f(the)h(subtree)f(b)r +(efore)h(insertion.)243 2071 y(Remark)e(that)i(only)f(the)h(paren)n(t)f +(no)r(de)h(has)f(to)g(b)r(e)h(up)r(dated)g(on)f(insertion.)118 +2303 y Fm(3.5)112 b(Selecting)36 b(the)h(ancestors)h(of)g(a)g(no)s(de) +118 2457 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +2556 y Fh(Y)-7 b(ou)27 b(can)g(sp)r(ecify)h(all)g(ancestors)d(of)j(a)f +(no)r(de)h(in)f(a)h(single)f(SQL)g(statemen)n(t;)g(for)g(instance)h +(for)f(vgID)326 2722 y Fd(...)42 b(WHERE)f('/25/6/7')f(LIKE)i(\(id)g +(||)h('/\045'\))f(AND)g(id)h(<)g('/25/6/7')118 2888 y +Fh(The)31 b(second)e(part)h(of)h(the)g(clause,)f(while)h(logically)e +(redundan)n(t,)h(is)h(a)f(\020hin)n(t\021)37 b(to)30 +b(the)h(optimizer.)45 b(A)n(t)31 b(least)f(in)g(P)n(ost-)118 +2988 y(greSQL,)c(without)i(it)g(the)g(optimizer)f(will)h(c)n(ho)r(ose)e +(a)i(sequen)n(tial)e(scan)h(of)h(the)g(table)f(and)h(disregard)d(the)j +(index.)118 3220 y Fm(3.6)112 b(Selecting)36 b(all)g(lea)m(v)m(es)118 +3374 y Fg(Cost:)h Fe(sc)l(an)30 b(of)g(the)g(tr)l(e)l(e)243 +3473 y Fh(A)e(leaf)f(is)g(a)h(no)r(de)f(without)h(descendan)n(ts:)36 +b(it)28 b(has)f(0)g(c)n(hildren.)37 b(Hence)326 3639 +y Fd(...)42 b(WHERE)f(nchildren)f(=)j(0)118 3805 y Fh(If)28 +b(this)g(t)n(yp)r(e)g(of)f(query)g(is)h(often)f(necessary)-7 +b(,)26 b(y)n(ou)h(ma)n(y)g(b)r(e)h(w)n(ell)f(advised)g(to)g(k)n(eep)g +(an)h(index)f(on)h(tree\(nc)n(hildren\).)118 4038 y Fm(3.7)112 +b(Determining)35 b(if)i(A)g(is)g(a)h(descendan)m(t)g(of)g(B)118 +4191 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations,)h(no)f(table)g(ac)l +(c)l(ess)243 4291 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r(eration)f +(on)i(the)g(indices,)f(no)g(table)h(access)e(is)i(necessary)-7 +b(.)118 4565 y Fi(4)131 b(Putting)45 b(it)f(all)h(together:)57 +b(a)44 b(P)l(ostgreSQL)f(implemen)l(tation)118 4747 y +Fh(h)n(ttp://www.p)r(ostgresql.org/mhonarc/pgsq)o(l-sql/)o(20)o(00)o +(-0)o(4/)o(msg0)o(02)o(67)o(.h)n(tml)243 4847 y(W)-7 +b(e)30 b(describ)r(e)g(here)g(a)g(small)f(pac)n(k)-5 +b(age)29 b(that)i(can)e(b)r(e)i(used)f(for)g(implemen)n(ting)g(gID)g +(on)g(P)n(ostgreSQL.)f(It)i(can)e(b)r(e)118 4946 y(found)f(at)f()243 5046 y(The)21 b(pac)n(k)-5 b(age)21 b(uses)g(the)h(pro) +r(cedural)e(language)h(PL/PGsql.)35 b(A)22 b(b)r(etter)g(implemen)n +(tation)g(w)n(ould)f(probably)g(de\034ne)118 5145 y(the)28 +b(gID)g(as)f(new)g(P)n(ostgres)f(t)n(yp)r(es,)i(and)f(co)r(de)g(all)h +(this)g(in)f(C.)243 5245 y(The)g(\034les)h(should)f(b)r(e)h(loaded)f +(in)h(alphab)r(etical)f(order.)1987 5653 y(5)p eop +%%Page: 6 6 +6 5 bop 118 291 a Fm(4.1)112 b(tree0_enco)s(ding.sql)118 +444 y Fh(This)28 b(\034le)f(de\034nes)h(and)f(p)r(opulates)h(the)f +(table)h(_b160_digits)d(of)j(\020digits\021)33 b(in)28 +b(base)f(160,)326 604 y Fd(CREATE)41 b(TABLE)g(\\_b160\\_digits)d +(\(deci)j(integer,)f(code)i(char\);)118 764 y Fh(and)28 +b(the)f(t)n(w)n(o)g(functions)326 924 y Fd(CREATE)41 +b(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er\))d(RETURNS)j(string) +413 1024 y(AS)j('....')e(LANGUAGE)f('plpgsql';)326 1124 +y(CREATE)h(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er,)o(in)o(te)o +(ger)o(\))d(RETURNS)k(string)413 1223 y(AS)i('....')e(LANGUAGE)f +('plpgsql';)118 1384 y Fh(The)22 b(\034rst)h(function)f(returns)g(a)g +(v)-5 b(ariable)21 b(size)h(enco)r(ding;)i(the)f(second)e(a)h(\034xed)h +(size)f(enco)r(ding)g(\(the)h(second)e(parameter)118 +1483 y(is)g(the)h(size\),)g(and)f(raises)e(an)i(exception)g(if)h(the)f +(n)n(um)n(b)r(er)g(is)g(to)r(o)g(large)e(to)i(b)r(e)h(represen)n(ted)e +(with)h(the)h(requested)e(n)n(um)n(b)r(er)118 1583 y(of)28 +b(digits.)118 1814 y Fm(4.2)112 b(tree1_de\034ne.sql)118 +1967 y Fh(This)28 b(\034le)f(pro)n(vides)f(a)i(function)326 +2127 y Fd(CREATE)41 b(FUNCTION)f(_tree_create\(tex)o(t,)o(in)o(teg)o +(er)o(,t)o(ext)o(,t)o(ex)o(t\))d(RETURNS)k(bpchar)413 +2227 y(AS)i('....')e(LANGUAGE)f('plpgsql';)118 2387 y +Fh(that)e(creates)f(a)h(tree)f(infrastructure)g(of)h(either)g(fgID)g +(or)f(vgID.)h(Assuming)f(y)n(ou)g(ha)n(v)n(e)g(a)h(table)f(\020m)n +(ytable\021)44 b(with)118 2487 y(primary)26 b(k)n(ey)h(\020m)n +(yid\021,)g(then)h(calling)326 2647 y Fd(SELECT)41 b(_tree_create\('m)o +(yt)o(ree)o(',)o(2,')o(my)o(ta)o(ble)o(',)o('m)o(yid)o('\))o(;)118 +2807 y Fh(will)28 b(cause:)220 2967 y(1.)41 b(the)28 +b(creation)e(of)i(a)f(table)508 3131 y Fd(CREATE)41 b(TABLE)h +(mytree_bkg\()683 3230 y(gid)g(text)g(PRIMARY)e(KEY,)683 +3330 y(nchildren)f(int,)683 3429 y(sid)j(integer)f(REFERENCES)e +(mytable\(myid\))508 3529 y(\);)508 3629 y(CREATE)i(UNIQUE)g(INDEX)h +(mytree_bkg_sid)37 b(ON)43 b(mytree_bkg\(sid\);)326 3792 +y Fh(for)27 b(the)h(tree)f(structure.)220 3955 y(2.)41 +b(the)28 b(creation)e(of)i(a)f(view)508 4118 y Fd(CREATE)41 +b(VIEW)h(mytree)f(AS)639 4218 y(SELECT)g(t.gid,n.*)900 +4317 y(FROM)h(mytable)f(n,)i(mytree_bkg)c(t)900 4417 +y(WHERE)j(t.sid=n.myid;)326 4580 y Fh(with:)35 b(a)23 +b(trigger)e(on)i(UPD)n(A)-7 b(TE)25 b(that)e(blo)r(c)n(ks)g(up)r +(dating)g(the)h(gid)f(and)g(allo)n(ws)f(up)r(dating)h(the)g(no)r(de)h +(data,)f(a)g(rule)326 4680 y(on)k(DELETE)i(that)f(deletes)f(the)h +(corresp)r(onding)e(en)n(try)h(b)r(oth)h(in)g(m)n(ytree_bkg)d(and)j(m)n +(ytable,)f(and)g(a)g(trigger)326 4779 y(ON)h(INSER)-7 +b(T)30 b(that)f(raises)e(an)h(exception)g(and)g(informs)h(the)f(user)g +(to)h(use)f(the)h(insertion)f(function)h(describ)r(ed)326 +4879 y(b)r(elo)n(w.)220 5042 y(3.)41 b(t)n(w)n(o)26 b(insertion)h +(functions)h(that)g(compute)g(automatically)e(the)i(gID)g(of)f(the)h +(new)g(no)r(de:)425 5205 y Ff(\017)41 b Fh(a)27 b(function)i(m)n +(ytree_insert\(text,text,in)n(teger,text\))d(for)h(insertion)g(sim)n +(ultaneosly)f(in)i(b)r(oth)g(tables:)508 5305 y(m)n +(ytree_insert\('2201','hello',0,'not)15 b(m)n(uc)n(h'\))j(inserts)g(a)g +(new)g(c)n(hild)h(of)f(2201)f(with)h(data1='hello',)h(data2=0)508 +5404 y(and)28 b(data3='not)e(m)n(uc)n(h')1987 5653 y(6)p +eop +%%Page: 7 7 +7 6 bop 425 291 a Ff(\017)41 b Fh(a)27 b(function)i(m)n +(ytree_insert_no)r(de\(text,in)n(teger\))c(for)i(insertion)g(in)h(m)n +(ytree_bkg)508 390 y(m)n(ytree_insert\('2201',25\))c(inserts)j(in)h(m)n +(ytree_bkg)e(a)h(new)h(c)n(hild)f(of)h(2201)d(with)j(sid=25)220 +556 y(4.)41 b(a)27 b(function)h(m)n(ytree_mo)n(v)n(e\(text,text\))e +(that)i(mo)n(v)n(es)e(subtrees:)326 656 y(m)n(ytree_mo)n(v)n +(e\('2201','23'\))d(mo)n(v)n(es)j(the)i(subtree)f(ro)r(oted)g(at)g +(2201)f(to)h(a)h(place)f(b)r(elo)n(w)g(23)f(\(ma)n(yb)r(e)i(2307\))220 +822 y(5.)41 b(a)c(function)g(m)n(ytree_len\(\))g(that)h(returns)e(the)i +(length)f(of)g(the)h(enco)r(dings)f(used)g(in)h(the)f(gID)g(\(2)h +(here;)j(0)c(if)326 922 y(v)-5 b(ariable)26 b(size\).)118 +1196 y Fi(5)131 b(Non-tree)44 b(hierarc)l(hies)118 1378 +y Fh(sequence)22 b(as)f(id,)j(table)e(with)h(\(id,g-index\))f(with)g(p) +r(ossibly)g(man)n(y)g(g-indices)f(for)h(eac)n(h)f(id)h(\(if)h(TOO)f +(man)n(y)-7 b(,)23 b(bad)f(mo)r(del:)118 1478 y(list)28 +b(all)f(genealogies,)f(i.e.,)h(paths)h(from)f(the)h(ro)r(ot\))118 +1752 y Fi(References)160 1934 y Fh([1])41 b(Philip)28 +b(Greenspun,)g Fe(T)-6 b(r)l(e)l(es)29 b(in)h(Or)l(acle)g(SQL)p +Fh(,)d(in)h Fg(SQL)k(for)g(W)-8 b(eb)31 b(Nerds)289 2033 +y Fh()160 2200 +y([2])41 b(Jo)r(e)27 b(Celk)n(o,)f Fe(SQL)j(for)i(Smarties)p +Fh(,)d(in)g Fg(DBMS)j(Online)p Fh(,)26 b(Marc)n(h)h(to)g(June)h(1996) +289 2299 y()289 +2399 y()289 +2498 y()289 +2598 y()160 +2764 y([3])41 b(Graeme)26 b(Birc)n(hall,)h Fg(DB2)32 +b(UDB)g(V6.1)f(SQL)h(Co)s(okb)s(o)s(ok)p Fh(,)289 2864 +y()1987 5653 +y(7)p eop +%%Trailer +end +userdict /end-hook known{end-hook}if +%%EOF diff --git a/ldb/ldb_tdb/ldb_cache.c b/ldb/ldb_tdb/ldb_cache.c new file mode 100644 index 000000000..2576e2c7b --- /dev/null +++ b/ldb/ldb_tdb/ldb_cache.c @@ -0,0 +1,458 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb tdb cache functions + * + * Description: cache special records in a ldb/tdb + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" + +#include "ldb_tdb.h" + +#define LTDB_FLAG_CASE_INSENSITIVE (1<<0) +#define LTDB_FLAG_INTEGER (1<<1) +#define LTDB_FLAG_HIDDEN (1<<2) + +/* valid attribute flags */ +static const struct { + const char *name; + int value; +} ltdb_valid_attr_flags[] = { + { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE }, + { "INTEGER", LTDB_FLAG_INTEGER }, + { "HIDDEN", LTDB_FLAG_HIDDEN }, + { "NONE", 0 }, + { NULL, 0 } +}; + + +/* + de-register any special handlers for @ATTRIBUTES +*/ +static void ltdb_attributes_unload(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + struct ldb_message *msg; + int i; + + if (ltdb->cache->attributes == NULL) { + /* no previously loaded attributes */ + return; + } + + msg = ltdb->cache->attributes; + for (i=0;inum_elements;i++) { + ldb_schema_attribute_remove(module->ldb, msg->elements[i].name); + } + + talloc_free(ltdb->cache->attributes); + ltdb->cache->attributes = NULL; +} + +/* + add up the attrib flags for a @ATTRIBUTES element +*/ +static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v) +{ + int i; + unsigned value = 0; + for (i=0;inum_values;i++) { + int j; + for (j=0;ltdb_valid_attr_flags[j].name;j++) { + if (strcmp(ltdb_valid_attr_flags[j].name, + (char *)el->values[i].data) == 0) { + value |= ltdb_valid_attr_flags[j].value; + break; + } + } + if (ltdb_valid_attr_flags[j].name == NULL) { + return -1; + } + } + *v = value; + return 0; +} + +/* + register any special handlers from @ATTRIBUTES +*/ +static int ltdb_attributes_load(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + struct ldb_message *msg = ltdb->cache->attributes; + struct ldb_dn *dn; + int i, r; + + dn = ldb_dn_new(module, module->ldb, LTDB_ATTRIBUTES); + if (dn == NULL) goto failed; + + r = ltdb_search_dn1(module, dn, msg); + talloc_free(dn); + if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { + goto failed; + } + if (r == LDB_ERR_NO_SUCH_OBJECT) { + return 0; + } + /* mapping these flags onto ldap 'syntaxes' isn't strictly correct, + but its close enough for now */ + for (i=0;inum_elements;i++) { + unsigned flags; + const char *syntax; + const struct ldb_schema_syntax *s; + + if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'\n", msg->elements[i].name); + goto failed; + } + switch (flags & ~LTDB_FLAG_HIDDEN) { + case 0: + syntax = LDB_SYNTAX_OCTET_STRING; + break; + case LTDB_FLAG_CASE_INSENSITIVE: + syntax = LDB_SYNTAX_DIRECTORY_STRING; + break; + case LTDB_FLAG_INTEGER: + syntax = LDB_SYNTAX_INTEGER; + break; + default: + ldb_debug(module->ldb, LDB_DEBUG_ERROR, + "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES\n", + flags, msg->elements[i].name); + goto failed; + } + + s = ldb_standard_syntax_by_name(module->ldb, syntax); + if (s == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, + "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES\n", + syntax, msg->elements[i].name); + goto failed; + } + + flags |= LDB_ATTR_FLAG_ALLOCATED; + if (ldb_schema_attribute_add_with_syntax(module->ldb, msg->elements[i].name, flags, s) != 0) { + goto failed; + } + } + + return 0; +failed: + return -1; +} + + +/* + initialise the baseinfo record +*/ +static int ltdb_baseinfo_init(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + struct ldb_message *msg; + struct ldb_message_element el; + struct ldb_val val; + int ret; + /* the initial sequence number must be different from the one + set in ltdb_cache_free(). Thanks to Jon for pointing this + out. */ + const char *initial_sequence_number = "1"; + + ltdb->sequence_number = atof(initial_sequence_number); + + msg = talloc(ltdb, struct ldb_message); + if (msg == NULL) { + goto failed; + } + + msg->num_elements = 1; + msg->elements = ⪙ + msg->dn = ldb_dn_new(msg, module->ldb, LTDB_BASEINFO); + if (!msg->dn) { + goto failed; + } + el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER); + if (!el.name) { + goto failed; + } + el.values = &val; + el.num_values = 1; + el.flags = 0; + val.data = (uint8_t *)talloc_strdup(msg, initial_sequence_number); + if (!val.data) { + goto failed; + } + val.length = 1; + + ret = ltdb_store(module, msg, TDB_INSERT); + + talloc_free(msg); + + return ret; + +failed: + talloc_free(msg); + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; +} + +/* + free any cache records + */ +static void ltdb_cache_free(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + + ltdb->sequence_number = 0; + talloc_free(ltdb->cache); + ltdb->cache = NULL; +} + +/* + force a cache reload +*/ +int ltdb_cache_reload(struct ldb_module *module) +{ + ltdb_attributes_unload(module); + ltdb_cache_free(module); + return ltdb_cache_load(module); +} + +/* + load the cache records +*/ +int ltdb_cache_load(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + struct ldb_dn *baseinfo_dn = NULL, *options_dn = NULL; + struct ldb_dn *indexlist_dn = NULL; + uint64_t seq; + struct ldb_message *baseinfo = NULL, *options = NULL; + int r; + + /* a very fast check to avoid extra database reads */ + if (ltdb->cache != NULL && + tdb_get_seqnum(ltdb->tdb) == ltdb->tdb_seqnum) { + return 0; + } + + if (ltdb->cache == NULL) { + ltdb->cache = talloc_zero(ltdb, struct ltdb_cache); + if (ltdb->cache == NULL) goto failed; + ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message); + ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message); + if (ltdb->cache->indexlist == NULL || + ltdb->cache->attributes == NULL) { + goto failed; + } + } + + baseinfo = talloc(ltdb->cache, struct ldb_message); + if (baseinfo == NULL) goto failed; + + baseinfo_dn = ldb_dn_new(module, module->ldb, LTDB_BASEINFO); + if (baseinfo_dn == NULL) goto failed; + + r= ltdb_search_dn1(module, baseinfo_dn, baseinfo); + if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { + goto failed; + } + + /* possibly initialise the baseinfo */ + if (r == LDB_ERR_NO_SUCH_OBJECT) { + if (ltdb_baseinfo_init(module) != LDB_SUCCESS) { + goto failed; + } + if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) != LDB_SUCCESS) { + goto failed; + } + } + + ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb); + + /* if the current internal sequence number is the same as the one + in the database then assume the rest of the cache is OK */ + seq = ldb_msg_find_attr_as_uint64(baseinfo, LTDB_SEQUENCE_NUMBER, 0); + if (seq == ltdb->sequence_number) { + goto done; + } + ltdb->sequence_number = seq; + + /* Read an interpret database options */ + options = talloc(ltdb->cache, struct ldb_message); + if (options == NULL) goto failed; + + options_dn = ldb_dn_new(options, module->ldb, LTDB_OPTIONS); + if (options_dn == NULL) goto failed; + + r= ltdb_search_dn1(module, options_dn, options); + if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { + goto failed; + } + + /* set flag for checking base DN on searches */ + if (r == LDB_SUCCESS) { + ltdb->check_base = ldb_msg_find_attr_as_bool(options, LTDB_CHECK_BASE, false); + } else { + ltdb->check_base = false; + } + + talloc_free(ltdb->cache->last_attribute.name); + memset(<db->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute)); + + ltdb_attributes_unload(module); + + talloc_free(ltdb->cache->indexlist); + + ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message); + ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message); + if (ltdb->cache->indexlist == NULL || + ltdb->cache->attributes == NULL) { + goto failed; + } + + indexlist_dn = ldb_dn_new(module, module->ldb, LTDB_INDEXLIST); + if (indexlist_dn == NULL) goto failed; + + r = ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist); + if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { + goto failed; + } + + if (ltdb_attributes_load(module) == -1) { + goto failed; + } + +done: + talloc_free(options); + talloc_free(baseinfo); + talloc_free(baseinfo_dn); + talloc_free(indexlist_dn); + return 0; + +failed: + talloc_free(options); + talloc_free(baseinfo); + talloc_free(baseinfo_dn); + talloc_free(indexlist_dn); + return -1; +} + + +/* + increase the sequence number to indicate a database change +*/ +int ltdb_increase_sequence_number(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + struct ldb_message *msg; + struct ldb_message_element el[2]; + struct ldb_val val; + struct ldb_val val_time; + time_t t = time(NULL); + char *s = NULL; + int ret; + + msg = talloc(ltdb, struct ldb_message); + if (msg == NULL) { + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + + s = talloc_asprintf(msg, "%llu", ltdb->sequence_number+1); + if (!s) { + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->num_elements = ARRAY_SIZE(el); + msg->elements = el; + msg->dn = ldb_dn_new(msg, module->ldb, LTDB_BASEINFO); + if (msg->dn == NULL) { + talloc_free(msg); + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + el[0].name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER); + if (el[0].name == NULL) { + talloc_free(msg); + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + el[0].values = &val; + el[0].num_values = 1; + el[0].flags = LDB_FLAG_MOD_REPLACE; + val.data = (uint8_t *)s; + val.length = strlen(s); + + el[1].name = talloc_strdup(msg, LTDB_MOD_TIMESTAMP); + if (el[1].name == NULL) { + talloc_free(msg); + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + el[1].values = &val_time; + el[1].num_values = 1; + el[1].flags = LDB_FLAG_MOD_REPLACE; + + s = ldb_timestring(msg, t); + if (s == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + val_time.data = (uint8_t *)s; + val_time.length = strlen(s); + + ret = ltdb_modify_internal(module, msg); + + talloc_free(msg); + + if (ret == LDB_SUCCESS) { + ltdb->sequence_number += 1; + } + + /* updating the tdb_seqnum here avoids us reloading the cache + records due to our own modification */ + ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb); + + return ret; +} + +int ltdb_check_at_attributes_values(const struct ldb_val *value) +{ + int i; + + for (i = 0; ltdb_valid_attr_flags[i].name != NULL; i++) { + if ((strcmp(ltdb_valid_attr_flags[i].name, (char *)value->data) == 0)) { + return 0; + } + } + + return -1; +} + diff --git a/ldb/ldb_tdb/ldb_index.c b/ldb/ldb_tdb/ldb_index.c new file mode 100644 index 000000000..269305a46 --- /dev/null +++ b/ldb/ldb_tdb/ldb_index.c @@ -0,0 +1,1273 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb tdb backend - indexing + * + * Description: indexing routines for ldb tdb backend + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" + +#include "ldb_tdb.h" + +/* + find an element in a list, using the given comparison function and + assuming that the list is already sorted using comp_fn + + return -1 if not found, or the index of the first occurance of needle if found +*/ +static int ldb_list_find(const void *needle, + const void *base, size_t nmemb, size_t size, + comparison_fn_t comp_fn) +{ + const char *base_p = (const char *)base; + size_t min_i, max_i, test_i; + + if (nmemb == 0) { + return -1; + } + + min_i = 0; + max_i = nmemb-1; + + while (min_i < max_i) { + int r; + + test_i = (min_i + max_i) / 2; + /* the following cast looks strange, but is + correct. The key to understanding it is that base_p + is a pointer to an array of pointers, so we have to + dereference it after casting to void **. The strange + const in the middle gives us the right type of pointer + after the dereference (tridge) */ + r = comp_fn(needle, *(void * const *)(base_p + (size * test_i))); + if (r == 0) { + /* scan back for first element */ + while (test_i > 0 && + comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) { + test_i--; + } + return test_i; + } + if (r < 0) { + if (test_i == 0) { + return -1; + } + max_i = test_i - 1; + } + if (r > 0) { + min_i = test_i + 1; + } + } + + if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) { + return min_i; + } + + return -1; +} + +struct dn_list { + unsigned int count; + char **dn; +}; + +/* + return the dn key to be used for an index + caller frees +*/ +static struct ldb_dn *ltdb_index_key(struct ldb_context *ldb, + const char *attr, const struct ldb_val *value) +{ + struct ldb_dn *ret; + struct ldb_val v; + const struct ldb_schema_attribute *a; + char *attr_folded; + int r; + + attr_folded = ldb_attr_casefold(ldb, attr); + if (!attr_folded) { + return NULL; + } + + a = ldb_schema_attribute_by_name(ldb, attr); + r = a->syntax->canonicalise_fn(ldb, ldb, value, &v); + if (r != LDB_SUCCESS) { + const char *errstr = ldb_errstring(ldb); + /* canonicalisation can be refused. For example, + a attribute that takes wildcards will refuse to canonicalise + if the value contains a wildcard */ + ldb_asprintf_errstring(ldb, "Failed to create index key for attribute '%s':%s%s%s", + attr, ldb_strerror(r), (errstr?":":""), (errstr?errstr:"")); + talloc_free(attr_folded); + return NULL; + } + if (ldb_should_b64_encode(&v)) { + char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length); + if (!vstr) return NULL; + ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr); + talloc_free(vstr); + } else { + ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s:%.*s", LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data); + } + + if (v.data != value->data) { + talloc_free(v.data); + } + talloc_free(attr_folded); + + return ret; +} + +/* + see if a attribute value is in the list of indexed attributes +*/ +static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr, + unsigned int *v_idx, const char *key) +{ + unsigned int i, j; + for (i=0;inum_elements;i++) { + if (ldb_attr_cmp(msg->elements[i].name, key) == 0) { + const struct ldb_message_element *el = &msg->elements[i]; + + if (attr == NULL) { + /* in this case we are just looking to see if key is present, + we are not spearching for a specific index */ + return 0; + } + + for (j=0;jnum_values;j++) { + if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) { + if (v_idx) { + *v_idx = j; + } + return i; + } + } + } + } + return -1; +} + +/* used in sorting dn lists */ +static int list_cmp(const char **s1, const char **s2) +{ + return strcmp(*s1, *s2); +} + +/* + return a list of dn's that might match a simple indexed search or + */ +static int ltdb_index_dn_simple(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + struct ldb_context *ldb = module->ldb; + struct ldb_dn *dn; + int ret; + unsigned int i, j; + struct ldb_message *msg; + + list->count = 0; + list->dn = NULL; + + /* if the attribute isn't in the list of indexed attributes then + this node needs a full search */ + if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* the attribute is indexed. Pull the list of DNs that match the + search criterion */ + dn = ltdb_index_key(ldb, tree->u.equality.attr, &tree->u.equality.value); + if (!dn) return LDB_ERR_OPERATIONS_ERROR; + + msg = talloc(list, struct ldb_message); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_search_dn1(module, dn, msg); + talloc_free(dn); + if (ret != LDB_SUCCESS) { + return ret; + } + + for (i=0;inum_elements;i++) { + struct ldb_message_element *el; + + if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) { + continue; + } + + el = &msg->elements[i]; + + list->dn = talloc_array(list, char *, el->num_values); + if (!list->dn) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (j=0;jnum_values;j++) { + list->dn[list->count] = + talloc_strdup(list->dn, (char *)el->values[j].data); + if (!list->dn[list->count]) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + list->count++; + } + } + + talloc_free(msg); + + if (list->count > 1) { + qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp); + } + + return LDB_SUCCESS; +} + + +static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *); + +/* + return a list of dn's that might match a leaf indexed search + */ +static int ltdb_index_dn_leaf(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + if (ldb_attr_dn(tree->u.equality.attr) == 0) { + list->dn = talloc_array(list, char *, 1); + if (list->dn == NULL) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + list->dn[0] = talloc_strdup(list->dn, (char *)tree->u.equality.value.data); + if (list->dn[0] == NULL) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + list->count = 1; + return LDB_SUCCESS; + } + return ltdb_index_dn_simple(module, tree, index_list, list); +} + + +/* + list intersection + list = list & list2 + relies on the lists being sorted +*/ +static int list_intersect(struct ldb_context *ldb, + struct dn_list *list, const struct dn_list *list2) +{ + struct dn_list *list3; + unsigned int i; + + if (list->count == 0 || list2->count == 0) { + /* 0 & X == 0 */ + return LDB_ERR_NO_SUCH_OBJECT; + } + + list3 = talloc(ldb, struct dn_list); + if (list3 == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + list3->dn = talloc_array(list3, char *, list->count); + if (!list3->dn) { + talloc_free(list3); + return LDB_ERR_OPERATIONS_ERROR; + } + list3->count = 0; + + for (i=0;icount;i++) { + if (ldb_list_find(list->dn[i], list2->dn, list2->count, + sizeof(char *), (comparison_fn_t)strcmp) != -1) { + list3->dn[list3->count] = talloc_move(list3->dn, &list->dn[i]); + list3->count++; + } else { + talloc_free(list->dn[i]); + } + } + + talloc_free(list->dn); + list->dn = talloc_move(list, &list3->dn); + list->count = list3->count; + talloc_free(list3); + + return LDB_ERR_NO_SUCH_OBJECT; +} + + +/* + list union + list = list | list2 + relies on the lists being sorted +*/ +static int list_union(struct ldb_context *ldb, + struct dn_list *list, const struct dn_list *list2) +{ + unsigned int i; + char **d; + unsigned int count = list->count; + + if (list->count == 0 && list2->count == 0) { + /* 0 | 0 == 0 */ + return LDB_ERR_NO_SUCH_OBJECT; + } + + d = talloc_realloc(list, list->dn, char *, list->count + list2->count); + if (!d) { + return LDB_ERR_OPERATIONS_ERROR; + } + list->dn = d; + + for (i=0;icount;i++) { + if (ldb_list_find(list2->dn[i], list->dn, count, + sizeof(char *), (comparison_fn_t)strcmp) == -1) { + list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]); + if (!list->dn[list->count]) { + return LDB_ERR_OPERATIONS_ERROR; + } + list->count++; + } + } + + if (list->count != count) { + qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp); + } + + return LDB_ERR_NO_SUCH_OBJECT; +} + +static int ltdb_index_dn(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list); + + +/* + OR two index results + */ +static int ltdb_index_dn_or(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i; + int ret; + + ret = LDB_ERR_OPERATIONS_ERROR; + list->dn = NULL; + list->count = 0; + + for (i=0;iu.list.num_elements;i++) { + struct dn_list *list2; + int v; + + list2 = talloc(module, struct dn_list); + if (list2 == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2); + + if (v == LDB_ERR_NO_SUCH_OBJECT) { + /* 0 || X == X */ + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { + ret = v; + } + talloc_free(list2); + continue; + } + + if (v != LDB_SUCCESS && v != LDB_ERR_NO_SUCH_OBJECT) { + /* 1 || X == 1 */ + talloc_free(list->dn); + talloc_free(list2); + return v; + } + + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { + ret = LDB_SUCCESS; + list->dn = talloc_move(list, &list2->dn); + list->count = list2->count; + } else { + if (list_union(ldb, list, list2) == -1) { + talloc_free(list2); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = LDB_SUCCESS; + } + talloc_free(list2); + } + + if (list->count == 0) { + return LDB_ERR_NO_SUCH_OBJECT; + } + + return ret; +} + + +/* + NOT an index results + */ +static int ltdb_index_dn_not(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + /* the only way to do an indexed not would be if we could + negate the not via another not or if we knew the total + number of database elements so we could know that the + existing expression covered the whole database. + + instead, we just give up, and rely on a full index scan + (unless an outer & manages to reduce the list) + */ + return LDB_ERR_OPERATIONS_ERROR; +} + +/* + AND two index results + */ +static int ltdb_index_dn_and(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i; + int ret; + + ret = LDB_ERR_OPERATIONS_ERROR; + list->dn = NULL; + list->count = 0; + + for (i=0;iu.list.num_elements;i++) { + struct dn_list *list2; + int v; + + list2 = talloc(module, struct dn_list); + if (list2 == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2); + + if (v == LDB_ERR_NO_SUCH_OBJECT) { + /* 0 && X == 0 */ + talloc_free(list->dn); + talloc_free(list2); + return LDB_ERR_NO_SUCH_OBJECT; + } + + if (v != LDB_SUCCESS && v != LDB_ERR_NO_SUCH_OBJECT) { + talloc_free(list2); + continue; + } + + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { + ret = LDB_SUCCESS; + talloc_free(list->dn); + list->dn = talloc_move(list, &list2->dn); + list->count = list2->count; + } else { + if (list_intersect(ldb, list, list2) == -1) { + talloc_free(list2); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + talloc_free(list2); + + if (list->count == 0) { + talloc_free(list->dn); + return LDB_ERR_NO_SUCH_OBJECT; + } + } + + return ret; +} + +/* + AND index results and ONE level special index + */ +static int ltdb_index_dn_one(struct ldb_module *module, + struct ldb_dn *parent_dn, + struct dn_list *list) +{ + struct ldb_context *ldb = module->ldb; + struct dn_list *list2; + struct ldb_message *msg; + struct ldb_dn *key; + struct ldb_val val; + unsigned int i, j; + int ret; + + list2 = talloc_zero(module, struct dn_list); + if (list2 == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* the attribute is indexed. Pull the list of DNs that match the + search criterion */ + val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(parent_dn)); + val.length = strlen((char *)val.data); + key = ltdb_index_key(ldb, LTDB_IDXONE, &val); + if (!key) { + talloc_free(list2); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg = talloc(list2, struct ldb_message); + if (msg == NULL) { + talloc_free(list2); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_search_dn1(module, key, msg); + talloc_free(key); + if (ret != LDB_SUCCESS) { + return ret; + } + + for (i = 0; i < msg->num_elements; i++) { + struct ldb_message_element *el; + + if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) { + continue; + } + + el = &msg->elements[i]; + + list2->dn = talloc_array(list2, char *, el->num_values); + if (!list2->dn) { + talloc_free(list2); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (j = 0; j < el->num_values; j++) { + list2->dn[list2->count] = talloc_strdup(list2->dn, (char *)el->values[j].data); + if (!list2->dn[list2->count]) { + talloc_free(list2); + return LDB_ERR_OPERATIONS_ERROR; + } + list2->count++; + } + } + + if (list2->count == 0) { + talloc_free(list2); + return LDB_ERR_NO_SUCH_OBJECT; + } + + if (list2->count > 1) { + qsort(list2->dn, list2->count, sizeof(char *), (comparison_fn_t) list_cmp); + } + + if (list->count > 0) { + if (list_intersect(ldb, list, list2) == -1) { + talloc_free(list2); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (list->count == 0) { + talloc_free(list->dn); + talloc_free(list2); + return LDB_ERR_NO_SUCH_OBJECT; + } + } else { + list->dn = talloc_move(list, &list2->dn); + list->count = list2->count; + } + + talloc_free(list2); + + return LDB_SUCCESS; +} + +/* + return a list of dn's that might match a indexed search or + an error. return LDB_ERR_NO_SUCH_OBJECT for no matches, or LDB_SUCCESS for matches + */ +static int ltdb_index_dn(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + int ret = LDB_ERR_OPERATIONS_ERROR; + + switch (tree->operation) { + case LDB_OP_AND: + ret = ltdb_index_dn_and(module, tree, index_list, list); + break; + + case LDB_OP_OR: + ret = ltdb_index_dn_or(module, tree, index_list, list); + break; + + case LDB_OP_NOT: + ret = ltdb_index_dn_not(module, tree, index_list, list); + break; + + case LDB_OP_EQUALITY: + ret = ltdb_index_dn_leaf(module, tree, index_list, list); + break; + + case LDB_OP_SUBSTRING: + case LDB_OP_GREATER: + case LDB_OP_LESS: + case LDB_OP_PRESENT: + case LDB_OP_APPROX: + case LDB_OP_EXTENDED: + /* we can't index with fancy bitops yet */ + ret = LDB_ERR_OPERATIONS_ERROR; + break; + } + + return ret; +} + +/* + filter a candidate dn_list from an indexed search into a set of results + extracting just the given attributes +*/ +static int ltdb_index_filter(const struct dn_list *dn_list, + struct ldb_handle *handle) +{ + struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); + struct ldb_reply *ares = NULL; + unsigned int i; + + for (i = 0; i < dn_list->count; i++) { + struct ldb_dn *dn; + int ret; + + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + return LDB_ERR_OPERATIONS_ERROR; + } + + ares->message = ldb_msg_new(ares); + if (!ares->message) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + + dn = ldb_dn_new(ares->message, ac->module->ldb, dn_list->dn[i]); + if (dn == NULL) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_search_dn1(ac->module, dn, ares->message); + talloc_free(dn); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + /* the record has disappeared? yes, this can happen */ + talloc_free(ares); + continue; + } + + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { + /* an internal error */ + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) { + talloc_free(ares); + continue; + } + + /* filter the attributes that the user wants */ + ret = ltdb_filter_attrs(ares->message, ac->attrs); + + if (ret == -1) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + ares->type = LDB_REPLY_ENTRY; + handle->state = LDB_ASYNC_PENDING; + handle->status = ac->callback(ac->module->ldb, ac->context, ares); + + if (handle->status != LDB_SUCCESS) { + handle->state = LDB_ASYNC_DONE; + return handle->status; + } + } + + return LDB_SUCCESS; +} + +/* + search the database with a LDAP-like expression using indexes + returns -1 if an indexed search is not possible, in which + case the caller should call ltdb_search_full() +*/ +int ltdb_search_indexed(struct ldb_handle *handle) +{ + struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); + struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private); + struct dn_list *dn_list; + int ret, idxattr, idxone; + + idxattr = idxone = 0; + ret = ldb_msg_find_idx(ltdb->cache->indexlist, NULL, NULL, LTDB_IDXATTR); + if (ret == 0 ) { + idxattr = 1; + } + + /* We do one level indexing only if requested */ + ret = ldb_msg_find_idx(ltdb->cache->indexlist, NULL, NULL, LTDB_IDXONE); + if (ret == 0 ) { + idxone = 1; + } + + if ((ac->scope == LDB_SCOPE_ONELEVEL && (idxattr+idxone == 0)) || + (ac->scope == LDB_SCOPE_SUBTREE && idxattr == 0)) { + /* no indexes? must do full search */ + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = LDB_ERR_OPERATIONS_ERROR; + + dn_list = talloc_zero(handle, struct dn_list); + if (dn_list == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (ac->scope == LDB_SCOPE_BASE) { + /* with BASE searches only one DN can match */ + dn_list->dn = talloc_array(dn_list, char *, 1); + if (dn_list->dn == NULL) { + ldb_oom(ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + dn_list->dn[0] = ldb_dn_alloc_linearized(dn_list, ac->base); + if (dn_list->dn[0] == NULL) { + ldb_oom(ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + dn_list->count = 1; + ret = LDB_SUCCESS; + } + + if (ac->scope != LDB_SCOPE_BASE && idxattr == 1) { + ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list); + + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { + talloc_free(dn_list); + return ret; + } + } + + if (ac->scope == LDB_SCOPE_ONELEVEL && idxone == 1) { + ret = ltdb_index_dn_one(ac->module, ac->base, dn_list); + } + + if (ret == LDB_SUCCESS) { + /* we've got a candidate list - now filter by the full tree + and extract the needed attributes */ + ret = ltdb_index_filter(dn_list, handle); + handle->status = ret; + handle->state = LDB_ASYNC_DONE; + } + + talloc_free(dn_list); + + return ret; +} + +/* + add a index element where this is the first indexed DN for this value +*/ +static int ltdb_index_add1_new(struct ldb_context *ldb, + struct ldb_message *msg, + const char *dn) +{ + struct ldb_message_element *el; + + /* add another entry */ + el = talloc_realloc(msg, msg->elements, + struct ldb_message_element, msg->num_elements+1); + if (!el) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->elements = el; + msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX); + if (!msg->elements[msg->num_elements].name) { + return LDB_ERR_OPERATIONS_ERROR; + } + msg->elements[msg->num_elements].num_values = 0; + msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val); + if (!msg->elements[msg->num_elements].values) { + return LDB_ERR_OPERATIONS_ERROR; + } + msg->elements[msg->num_elements].values[0].length = strlen(dn); + msg->elements[msg->num_elements].values[0].data = discard_const_p(uint8_t, dn); + msg->elements[msg->num_elements].num_values = 1; + msg->num_elements++; + + return LDB_SUCCESS; +} + + +/* + add a index element where this is not the first indexed DN for this + value +*/ +static int ltdb_index_add1_add(struct ldb_context *ldb, + struct ldb_message *msg, + int idx, + const char *dn) +{ + struct ldb_val *v2; + unsigned int i; + + /* for multi-valued attributes we can end up with repeats */ + for (i=0;ielements[idx].num_values;i++) { + if (strcmp(dn, (char *)msg->elements[idx].values[i].data) == 0) { + return LDB_SUCCESS; + } + } + + v2 = talloc_realloc(msg->elements, msg->elements[idx].values, + struct ldb_val, + msg->elements[idx].num_values+1); + if (!v2) { + return LDB_ERR_OPERATIONS_ERROR; + } + msg->elements[idx].values = v2; + + msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn); + msg->elements[idx].values[msg->elements[idx].num_values].data = discard_const_p(uint8_t, dn); + msg->elements[idx].num_values++; + + return LDB_SUCCESS; +} + +/* + add an index entry for one message element +*/ +static int ltdb_index_add1(struct ldb_module *module, const char *dn, + struct ldb_message_element *el, int v_idx) +{ + struct ldb_context *ldb = module->ldb; + struct ldb_message *msg; + struct ldb_dn *dn_key; + int ret; + unsigned int i; + + msg = talloc(module, struct ldb_message); + if (msg == NULL) { + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + + dn_key = ltdb_index_key(ldb, el->name, &el->values[v_idx]); + if (!dn_key) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + talloc_steal(msg, dn_key); + + ret = ltdb_search_dn1(module, dn_key, msg); + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { + talloc_free(msg); + return ret; + } + + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + msg->dn = dn_key; + msg->num_elements = 0; + msg->elements = NULL; + } + + for (i=0;inum_elements;i++) { + if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) { + break; + } + } + + if (i == msg->num_elements) { + ret = ltdb_index_add1_new(ldb, msg, dn); + } else { + ret = ltdb_index_add1_add(ldb, msg, i, dn); + } + + if (ret == LDB_SUCCESS) { + ret = ltdb_store(module, msg, TDB_REPLACE); + } + + talloc_free(msg); + + return ret; +} + +static int ltdb_index_add0(struct ldb_module *module, const char *dn, + struct ldb_message_element *elements, int num_el) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + int ret; + unsigned int i, j; + + if (dn[0] == '@') { + return LDB_SUCCESS; + } + + if (ltdb->cache->indexlist->num_elements == 0) { + /* no indexed fields */ + return LDB_SUCCESS; + } + + for (i = 0; i < num_el; i++) { + ret = ldb_msg_find_idx(ltdb->cache->indexlist, elements[i].name, + NULL, LTDB_IDXATTR); + if (ret == -1) { + continue; + } + for (j = 0; j < elements[i].num_values; j++) { + ret = ltdb_index_add1(module, dn, &elements[i], j); + if (ret != LDB_SUCCESS) { + return ret; + } + } + } + + return LDB_SUCCESS; +} + +/* + add the index entries for a new record +*/ +int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg) +{ + const char *dn; + int ret; + + dn = ldb_dn_get_linearized(msg->dn); + if (dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements); + + return ret; +} + + +/* + delete an index entry for one message element +*/ +int ltdb_index_del_value(struct ldb_module *module, const char *dn, + struct ldb_message_element *el, int v_idx) +{ + struct ldb_context *ldb = module->ldb; + struct ldb_message *msg; + struct ldb_dn *dn_key; + int ret, i; + unsigned int j; + + if (dn[0] == '@') { + return LDB_SUCCESS; + } + + dn_key = ltdb_index_key(ldb, el->name, &el->values[v_idx]); + if (!dn_key) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg = talloc(dn_key, struct ldb_message); + if (msg == NULL) { + talloc_free(dn_key); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_search_dn1(module, dn_key, msg); + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { + talloc_free(dn_key); + return ret; + } + + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + /* it wasn't indexed. Did we have an earlier error? If we did then + its gone now */ + talloc_free(dn_key); + return LDB_SUCCESS; + } + + i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX); + if (i == -1) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "ERROR: dn %s not found in %s\n", dn, + ldb_dn_get_linearized(dn_key)); + /* it ain't there. hmmm */ + talloc_free(dn_key); + return LDB_SUCCESS; + } + + if (j != msg->elements[i].num_values - 1) { + memmove(&msg->elements[i].values[j], + &msg->elements[i].values[j+1], + (msg->elements[i].num_values-(j+1)) * + sizeof(msg->elements[i].values[0])); + } + msg->elements[i].num_values--; + + if (msg->elements[i].num_values == 0) { + ret = ltdb_delete_noindex(module, dn_key); + } else { + ret = ltdb_store(module, msg, TDB_REPLACE); + } + + talloc_free(dn_key); + + return ret; +} + +/* + delete the index entries for a record + return -1 on failure +*/ +int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + int ret; + const char *dn; + unsigned int i, j; + + /* find the list of indexed fields */ + if (ltdb->cache->indexlist->num_elements == 0) { + /* no indexed fields */ + return LDB_SUCCESS; + } + + if (ldb_dn_is_special(msg->dn)) { + return LDB_SUCCESS; + } + + dn = ldb_dn_get_linearized(msg->dn); + if (dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i = 0; i < msg->num_elements; i++) { + ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name, + NULL, LTDB_IDXATTR); + if (ret == -1) { + continue; + } + for (j = 0; j < msg->elements[i].num_values; j++) { + ret = ltdb_index_del_value(module, dn, &msg->elements[i], j); + if (ret != LDB_SUCCESS) { + return ret; + } + } + } + + return LDB_SUCCESS; +} + +/* + handle special index for one level searches +*/ +int ltdb_index_one(struct ldb_module *module, const struct ldb_message *msg, int add) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + struct ldb_message_element el; + struct ldb_val val; + struct ldb_dn *pdn; + const char *dn; + int ret; + + /* We index for ONE Level only if requested */ + ret = ldb_msg_find_idx(ltdb->cache->indexlist, NULL, NULL, LTDB_IDXONE); + if (ret != 0) { + return LDB_SUCCESS; + } + + pdn = ldb_dn_get_parent(module, msg->dn); + if (pdn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + dn = ldb_dn_get_linearized(msg->dn); + if (dn == NULL) { + talloc_free(pdn); + return LDB_ERR_OPERATIONS_ERROR; + } + + val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(pdn)); + if (val.data == NULL) { + talloc_free(pdn); + return LDB_ERR_OPERATIONS_ERROR; + } + + val.length = strlen((char *)val.data); + el.name = LTDB_IDXONE; + el.values = &val; + el.num_values = 1; + + if (add) { + ret = ltdb_index_add1(module, dn, &el, 0); + } else { /* delete */ + ret = ltdb_index_del_value(module, dn, &el, 0); + } + + talloc_free(pdn); + + return ret; +} + + +/* + traversal function that deletes all @INDEX records +*/ +static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +{ + const char *dn = "DN=" LTDB_INDEX ":"; + if (strncmp((char *)key.dptr, dn, strlen(dn)) == 0) { + return tdb_delete(tdb, key); + } + return 0; +} + +/* + traversal function that adds @INDEX records during a re index +*/ +static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +{ + struct ldb_module *module = (struct ldb_module *)state; + struct ldb_message *msg; + const char *dn = NULL; + int ret; + TDB_DATA key2; + + if (strncmp((char *)key.dptr, "DN=@", 4) == 0 || + strncmp((char *)key.dptr, "DN=", 3) != 0) { + return 0; + } + + msg = talloc(module, struct ldb_message); + if (msg == NULL) { + return -1; + } + + ret = ltdb_unpack_data(module, &data, msg); + if (ret != 0) { + talloc_free(msg); + return -1; + } + + /* check if the DN key has changed, perhaps due to the + case insensitivity of an element changing */ + key2 = ltdb_key(module, msg->dn); + if (key2.dptr == NULL) { + /* probably a corrupt record ... darn */ + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s\n", + ldb_dn_get_linearized(msg->dn)); + talloc_free(msg); + return 0; + } + if (strcmp((char *)key2.dptr, (char *)key.dptr) != 0) { + tdb_delete(tdb, key); + tdb_store(tdb, key2, data, 0); + } + talloc_free(key2.dptr); + + if (msg->dn == NULL) { + dn = (char *)key.dptr + 3; + } else { + dn = ldb_dn_get_linearized(msg->dn); + } + + ret = ltdb_index_one(module, msg, 1); + if (ret == LDB_SUCCESS) { + ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements); + } else { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, + "Adding special ONE LEVEL index failed (%s)!\n", + ldb_dn_get_linearized(msg->dn)); + } + + talloc_free(msg); + + if (ret != LDB_SUCCESS) return -1; + + return 0; +} + +/* + force a complete reindex of the database +*/ +int ltdb_reindex(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + int ret; + + if (ltdb_cache_reload(module) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* first traverse the database deleting any @INDEX records */ + ret = tdb_traverse(ltdb->tdb, delete_index, NULL); + if (ret == -1) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* if we don't have indexes we have nothing todo */ + if (ltdb->cache->indexlist->num_elements == 0) { + return LDB_SUCCESS; + } + + /* now traverse adding any indexes for normal LDB records */ + ret = tdb_traverse(ltdb->tdb, re_index, module); + if (ret == -1) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; +} diff --git a/ldb/ldb_tdb/ldb_pack.c b/ldb/ldb_tdb/ldb_pack.c new file mode 100644 index 000000000..afb07dcbc --- /dev/null +++ b/ldb/ldb_tdb/ldb_pack.c @@ -0,0 +1,289 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb pack/unpack + * + * Description: pack/unpack routines for ldb messages as key/value blobs + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" +#include "ldb_tdb.h" + +/* change this if the data format ever changes */ +#define LTDB_PACKING_FORMAT 0x26011967 + +/* old packing formats */ +#define LTDB_PACKING_FORMAT_NODN 0x26011966 + +/* use a portable integer format */ +static void put_uint32(uint8_t *p, int ofs, unsigned int val) +{ + p += ofs; + p[0] = val&0xFF; + p[1] = (val>>8) & 0xFF; + p[2] = (val>>16) & 0xFF; + p[3] = (val>>24) & 0xFF; +} + +static unsigned int pull_uint32(uint8_t *p, int ofs) +{ + p += ofs; + return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); +} + +static int attribute_storable_values(const struct ldb_message_element *el) +{ + if (el->num_values == 0) return 0; + + if (ldb_attr_cmp(el->name, "dn") == 0) return 0; + + if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0; + + return el->num_values; +} + +/* + pack a ldb message into a linear buffer in a TDB_DATA + + note that this routine avoids saving elements with zero values, + as these are equivalent to having no element + + caller frees the data buffer after use +*/ +int ltdb_pack_data(struct ldb_module *module, + const struct ldb_message *message, + struct TDB_DATA *data) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i, j, real_elements=0; + size_t size; + const char *dn; + uint8_t *p; + size_t len; + + dn = ldb_dn_get_linearized(message->dn); + if (dn == NULL) { + errno = ENOMEM; + return -1; + } + + /* work out how big it needs to be */ + size = 8; + + size += 1 + strlen(dn); + + for (i=0;inum_elements;i++) { + if (attribute_storable_values(&message->elements[i]) == 0) { + continue; + } + + real_elements++; + + size += 1 + strlen(message->elements[i].name) + 4; + for (j=0;jelements[i].num_values;j++) { + size += 4 + message->elements[i].values[j].length + 1; + } + } + + /* allocate it */ + data->dptr = talloc_array(ldb, uint8_t, size); + if (!data->dptr) { + errno = ENOMEM; + return -1; + } + data->dsize = size; + + p = data->dptr; + put_uint32(p, 0, LTDB_PACKING_FORMAT); + put_uint32(p, 4, real_elements); + p += 8; + + /* the dn needs to be packed so we can be case preserving + while hashing on a case folded dn */ + len = strlen(dn); + memcpy(p, dn, len+1); + p += len + 1; + + for (i=0;inum_elements;i++) { + if (attribute_storable_values(&message->elements[i]) == 0) { + continue; + } + len = strlen(message->elements[i].name); + memcpy(p, message->elements[i].name, len+1); + p += len + 1; + put_uint32(p, 0, message->elements[i].num_values); + p += 4; + for (j=0;jelements[i].num_values;j++) { + put_uint32(p, 0, message->elements[i].values[j].length); + memcpy(p+4, message->elements[i].values[j].data, + message->elements[i].values[j].length); + p[4+message->elements[i].values[j].length] = 0; + p += 4 + message->elements[i].values[j].length + 1; + } + } + + return 0; +} + +/* + unpack a ldb message from a linear buffer in TDB_DATA + + Free with ltdb_unpack_data_free() +*/ +int ltdb_unpack_data(struct ldb_module *module, + const struct TDB_DATA *data, + struct ldb_message *message) +{ + struct ldb_context *ldb = module->ldb; + uint8_t *p; + unsigned int remaining; + unsigned int i, j; + unsigned format; + size_t len; + + message->elements = NULL; + + p = data->dptr; + if (data->dsize < 8) { + errno = EIO; + goto failed; + } + + format = pull_uint32(p, 0); + message->num_elements = pull_uint32(p, 4); + p += 8; + + remaining = data->dsize - 8; + + switch (format) { + case LTDB_PACKING_FORMAT_NODN: + message->dn = NULL; + break; + + case LTDB_PACKING_FORMAT: + len = strnlen((char *)p, remaining); + if (len == remaining) { + errno = EIO; + goto failed; + } + message->dn = ldb_dn_new(message, ldb, (char *)p); + if (message->dn == NULL) { + errno = ENOMEM; + goto failed; + } + remaining -= len + 1; + p += len + 1; + break; + + default: + errno = EIO; + goto failed; + } + + if (message->num_elements == 0) { + message->elements = NULL; + return 0; + } + + if (message->num_elements > remaining / 6) { + errno = EIO; + goto failed; + } + + message->elements = talloc_array(message, struct ldb_message_element, message->num_elements); + if (!message->elements) { + errno = ENOMEM; + goto failed; + } + + memset(message->elements, 0, + message->num_elements * sizeof(struct ldb_message_element)); + + for (i=0;inum_elements;i++) { + if (remaining < 10) { + errno = EIO; + goto failed; + } + len = strnlen((char *)p, remaining-6); + if (len == remaining-6) { + errno = EIO; + goto failed; + } + message->elements[i].flags = 0; + message->elements[i].name = talloc_strndup(message->elements, (char *)p, len); + if (message->elements[i].name == NULL) { + errno = ENOMEM; + goto failed; + } + remaining -= len + 1; + p += len + 1; + message->elements[i].num_values = pull_uint32(p, 0); + message->elements[i].values = NULL; + if (message->elements[i].num_values != 0) { + message->elements[i].values = talloc_array(message->elements, + struct ldb_val, + message->elements[i].num_values); + if (!message->elements[i].values) { + errno = ENOMEM; + goto failed; + } + } + p += 4; + remaining -= 4; + for (j=0;jelements[i].num_values;j++) { + len = pull_uint32(p, 0); + if (len > remaining-5) { + errno = EIO; + goto failed; + } + + message->elements[i].values[j].length = len; + message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1); + if (message->elements[i].values[j].data == NULL) { + errno = ENOMEM; + goto failed; + } + memcpy(message->elements[i].values[j].data, p+4, len); + message->elements[i].values[j].data[len] = 0; + + remaining -= len+4+1; + p += len+4+1; + } + } + + if (remaining != 0) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "Error: %d bytes unread in ltdb_unpack_data\n", remaining); + } + + return 0; + +failed: + talloc_free(message->elements); + return -1; +} diff --git a/ldb/ldb_tdb/ldb_search.c b/ldb/ldb_tdb/ldb_search.c new file mode 100644 index 000000000..da899c361 --- /dev/null +++ b/ldb/ldb_tdb/ldb_search.c @@ -0,0 +1,616 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb search functions + * + * Description: functions to search ldb+tdb databases + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" + +#include "ldb_tdb.h" + +/* + add one element to a message +*/ +static int msg_add_element(struct ldb_message *ret, + const struct ldb_message_element *el, + int check_duplicates) +{ + unsigned int i; + struct ldb_message_element *e2, *elnew; + + if (check_duplicates && ldb_msg_find_element(ret, el->name)) { + /* its already there */ + return 0; + } + + e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1); + if (!e2) { + return -1; + } + ret->elements = e2; + + elnew = &e2[ret->num_elements]; + + elnew->name = talloc_strdup(ret->elements, el->name); + if (!elnew->name) { + return -1; + } + + if (el->num_values) { + elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values); + if (!elnew->values) { + return -1; + } + } else { + elnew->values = NULL; + } + + for (i=0;inum_values;i++) { + elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]); + if (elnew->values[i].length != el->values[i].length) { + return -1; + } + } + + elnew->num_values = el->num_values; + + ret->num_elements++; + + return 0; +} + +/* + add the special distinguishedName element +*/ +static int msg_add_distinguished_name(struct ldb_message *msg) +{ + struct ldb_message_element el; + struct ldb_val val; + int ret; + + el.flags = 0; + el.name = "distinguishedName"; + el.num_values = 1; + el.values = &val; + val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn); + val.length = strlen((char *)val.data); + + ret = msg_add_element(msg, &el, 1); + return ret; +} + +/* + add all elements from one message into another + */ +static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret, + const struct ldb_message *msg) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i; + int check_duplicates = (ret->num_elements != 0); + + if (msg_add_distinguished_name(ret) != 0) { + return -1; + } + + for (i=0;inum_elements;i++) { + const struct ldb_schema_attribute *a; + a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name); + if (a->flags & LDB_ATTR_FLAG_HIDDEN) { + continue; + } + if (msg_add_element(ret, &msg->elements[i], + check_duplicates) != 0) { + return -1; + } + } + + return 0; +} + + +/* + pull the specified list of attributes from a message + */ +static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, + TALLOC_CTX *mem_ctx, + const struct ldb_message *msg, + const char * const *attrs) +{ + struct ldb_message *ret; + int i; + + ret = talloc(mem_ctx, struct ldb_message); + if (!ret) { + return NULL; + } + + ret->dn = ldb_dn_copy(ret, msg->dn); + if (!ret->dn) { + talloc_free(ret); + return NULL; + } + + ret->num_elements = 0; + ret->elements = NULL; + + if (!attrs) { + if (msg_add_all_elements(module, ret, msg) != 0) { + talloc_free(ret); + return NULL; + } + return ret; + } + + for (i=0;attrs[i];i++) { + struct ldb_message_element *el; + + if (strcmp(attrs[i], "*") == 0) { + if (msg_add_all_elements(module, ret, msg) != 0) { + talloc_free(ret); + return NULL; + } + continue; + } + + if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) { + if (msg_add_distinguished_name(ret) != 0) { + return NULL; + } + continue; + } + + el = ldb_msg_find_element(msg, attrs[i]); + if (!el) { + continue; + } + if (msg_add_element(ret, el, 1) != 0) { + talloc_free(ret); + return NULL; + } + } + + return ret; +} + +/* + search the database for a single simple dn. + return LDB_ERR_NO_SUCH_OBJECT on record-not-found + and LDB_SUCCESS on success +*/ +int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + TDB_DATA tdb_key, tdb_data; + + if (ldb_dn_is_null(dn)) { + return LDB_ERR_NO_SUCH_OBJECT; + } + + /* form the key */ + tdb_key = ltdb_key(module, dn); + if (!tdb_key.dptr) { + return LDB_ERR_OPERATIONS_ERROR; + } + + tdb_data = tdb_fetch(ltdb->tdb, tdb_key); + talloc_free(tdb_key.dptr); + if (!tdb_data.dptr) { + return LDB_ERR_NO_SUCH_OBJECT; + } + + free(tdb_data.dptr); + return LDB_SUCCESS; +} + +/* + search the database for a single simple dn, returning all attributes + in a single message + + return LDB_ERR_NO_SUCH_OBJECT on record-not-found + and LDB_SUCCESS on success +*/ +int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + int ret; + TDB_DATA tdb_key, tdb_data; + + memset(msg, 0, sizeof(*msg)); + + /* form the key */ + tdb_key = ltdb_key(module, dn); + if (!tdb_key.dptr) { + return LDB_ERR_OPERATIONS_ERROR; + } + + tdb_data = tdb_fetch(ltdb->tdb, tdb_key); + talloc_free(tdb_key.dptr); + if (!tdb_data.dptr) { + return LDB_ERR_NO_SUCH_OBJECT; + } + + msg->num_elements = 0; + msg->elements = NULL; + + ret = ltdb_unpack_data(module, &tdb_data, msg); + free(tdb_data.dptr); + if (ret == -1) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (!msg->dn) { + msg->dn = ldb_dn_copy(msg, dn); + } + if (!msg->dn) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; +} + +/* + lock the database for read - use by ltdb_search +*/ +static int ltdb_lock_read(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + if (ltdb->in_transaction == 0) { + return tdb_lockall_read(ltdb->tdb); + } + return 0; +} + +/* + unlock the database after a ltdb_lock_read() +*/ +static int ltdb_unlock_read(struct ldb_module *module) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + if (ltdb->in_transaction == 0) { + return tdb_unlockall_read(ltdb->tdb); + } + return 0; +} + +/* + add a set of attributes from a record to a set of results + return 0 on success, -1 on failure +*/ +int ltdb_add_attr_results(struct ldb_module *module, + TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + const char * const attrs[], + unsigned int *count, + struct ldb_message ***res) +{ + struct ldb_message *msg2; + struct ldb_message **res2; + + /* pull the attributes that the user wants */ + msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs); + if (!msg2) { + return -1; + } + + /* add to the results list */ + res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2); + if (!res2) { + talloc_free(msg2); + return -1; + } + + (*res) = res2; + + (*res)[*count] = talloc_move(*res, &msg2); + (*res)[(*count)+1] = NULL; + (*count)++; + + return 0; +} + + + +/* + filter the specified list of attributes from a message + removing not requested attrs. + */ +int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs) +{ + int i, keep_all = 0; + + if (attrs) { + /* check for special attrs */ + for (i = 0; attrs[i]; i++) { + if (strcmp(attrs[i], "*") == 0) { + keep_all = 1; + break; + } + + if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) { + if (msg_add_distinguished_name(msg) != 0) { + return -1; + } + } + } + } else { + keep_all = 1; + } + + if (keep_all) { + if (msg_add_distinguished_name(msg) != 0) { + return -1; + } + return 0; + } + + for (i = 0; i < msg->num_elements; i++) { + int j, found; + + for (j = 0, found = 0; attrs[j]; j++) { + if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) { + found = 1; + break; + } + } + + if (!found) { + ldb_msg_remove_attr(msg, msg->elements[i].name); + i--; + } + } + + return 0; +} + +/* + search function for a non-indexed search + */ +static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +{ + struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle); + struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); + struct ldb_reply *ares = NULL; + int ret; + + if (key.dsize < 4 || + strncmp((char *)key.dptr, "DN=", 3) != 0) { + return 0; + } + + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + return -1; + } + + ares->message = ldb_msg_new(ares); + if (!ares->message) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return -1; + } + + /* unpack the record */ + ret = ltdb_unpack_data(ac->module, &data, ares->message); + if (ret == -1) { + talloc_free(ares); + return -1; + } + + if (!ares->message->dn) { + ares->message->dn = ldb_dn_new(ares->message, ac->module->ldb, (char *)key.dptr + 3); + if (ares->message->dn == NULL) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return -1; + } + } + + /* see if it matches the given expression */ + if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, + ac->base, ac->scope)) { + talloc_free(ares); + return 0; + } + + /* filter the attributes that the user wants */ + ret = ltdb_filter_attrs(ares->message, ac->attrs); + + if (ret == -1) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return -1; + } + + ares->type = LDB_REPLY_ENTRY; + handle->state = LDB_ASYNC_PENDING; + handle->status = ac->callback(ac->module->ldb, ac->context, ares); + + if (handle->status != LDB_SUCCESS) { + /* don't try to free ares here, the callback is in charge of that */ + return -1; + } + + return 0; +} + + +/* + search the database with a LDAP-like expression. + this is the "full search" non-indexed variant +*/ +static int ltdb_search_full(struct ldb_handle *handle) +{ + struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); + struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private); + int ret; + + if (ltdb->in_transaction != 0) { + ret = tdb_traverse(ltdb->tdb, search_func, handle); + } else { + ret = tdb_traverse_read(ltdb->tdb, search_func, handle); + } + + if (ret == -1) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + } + + handle->state = LDB_ASYNC_DONE; + return LDB_SUCCESS; +} + +/* + search the database with a LDAP-like expression. + choses a search method +*/ +int ltdb_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); + struct ltdb_context *ltdb_ac; + struct ldb_reply *ares; + int ret; + + if (ltdb_lock_read(module) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (ltdb_cache_load(module) != 0) { + ltdb_unlock_read(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (req->op.search.tree == NULL) { + ltdb_unlock_read(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->handle = init_ltdb_handle(ltdb, module, req); + if (req->handle == NULL) { + ltdb_unlock_read(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) { + + /* Check what we should do with a NULL dn */ + switch (req->op.search.scope) { + case LDB_SCOPE_BASE: + ldb_asprintf_errstring(module->ldb, + "NULL Base DN invalid for a base search"); + ret = LDB_ERR_INVALID_DN_SYNTAX; + break; + case LDB_SCOPE_ONELEVEL: + ldb_asprintf_errstring(module->ldb, + "NULL Base DN invalid for a one-level search"); + ret = LDB_ERR_INVALID_DN_SYNTAX; + break; + case LDB_SCOPE_SUBTREE: + default: + /* We accept subtree searches from a NULL base DN, ie over the whole DB */ + ret = LDB_SUCCESS; + } + } else if (ldb_dn_is_valid(req->op.search.base) == false) { + + /* We don't want invalid base DNs here */ + ldb_asprintf_errstring(module->ldb, + "Invalid Base DN: %s", + ldb_dn_get_linearized(req->op.search.base)); + ret = LDB_ERR_INVALID_DN_SYNTAX; + + } else if (ltdb->check_base) { + /* This database has been marked as 'checkBaseOnSearch', so do a spot check of the base dn */ + ret = ltdb_search_base(module, req->op.search.base); + + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + ldb_asprintf_errstring(module->ldb, + "No such Base DN: %s", + ldb_dn_get_linearized(req->op.search.base)); + } + + } else { + /* If we are not checking the base DN life is easy */ + ret = LDB_SUCCESS; + } + + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + ltdb_ac->tree = req->op.search.tree; + ltdb_ac->scope = req->op.search.scope; + ltdb_ac->base = req->op.search.base; + ltdb_ac->attrs = req->op.search.attrs; + + + if (ret == LDB_SUCCESS) { + ret = ltdb_search_indexed(req->handle); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + /* Not in the index, therefore OK! */ + ret = LDB_SUCCESS; + + } else if (ret == LDB_ERR_OPERATIONS_ERROR) { + /* Not indexed, so we need to do a full scan */ + ret = ltdb_search_full(req->handle); + if (ret != LDB_SUCCESS) { + ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n"); + } + } + } + + if (ret != LDB_SUCCESS) { + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = ret; + } + + /* Finally send an LDB_REPLY_DONE packet when searching is finished */ + + ares = talloc_zero(req, struct ldb_reply); + if (!ares) { + ltdb_unlock_read(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->handle->state = LDB_ASYNC_DONE; + + if (ret == LDB_SUCCESS) { + ares->type = LDB_REPLY_DONE; + + ret = req->callback(module->ldb, req->context, ares); + req->handle->status = ret; + } + + ltdb_unlock_read(module); + + return LDB_SUCCESS; +} + diff --git a/ldb/ldb_tdb/ldb_tdb.c b/ldb/ldb_tdb/ldb_tdb.c new file mode 100644 index 000000000..01d570c89 --- /dev/null +++ b/ldb/ldb_tdb/ldb_tdb.c @@ -0,0 +1,1140 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2004 + Copyright (C) Simo Sorce 2006 + + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb_tdb + * + * Component: ldb tdb backend + * + * Description: core functions for tdb backend + * + * Author: Andrew Tridgell + * Author: Stefan Metzmacher + * + * Modifications: + * + * - description: make the module use asyncronous calls + * date: Feb 2006 + * Author: Simo Sorce + */ + +#include "ldb_includes.h" + +#include "ldb_tdb.h" + + +/* + map a tdb error code to a ldb error code +*/ +static int ltdb_err_map(enum TDB_ERROR tdb_code) +{ + switch (tdb_code) { + case TDB_SUCCESS: + return LDB_SUCCESS; + case TDB_ERR_CORRUPT: + case TDB_ERR_OOM: + case TDB_ERR_EINVAL: + return LDB_ERR_OPERATIONS_ERROR; + case TDB_ERR_IO: + return LDB_ERR_PROTOCOL_ERROR; + case TDB_ERR_LOCK: + case TDB_ERR_NOLOCK: + return LDB_ERR_BUSY; + case TDB_ERR_LOCK_TIMEOUT: + return LDB_ERR_TIME_LIMIT_EXCEEDED; + case TDB_ERR_EXISTS: + return LDB_ERR_ENTRY_ALREADY_EXISTS; + case TDB_ERR_NOEXIST: + return LDB_ERR_NO_SUCH_OBJECT; + case TDB_ERR_RDONLY: + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + return LDB_ERR_OTHER; +} + + +struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, + struct ldb_module *module, + struct ldb_request *req) +{ + struct ltdb_context *ac; + struct ldb_handle *h; + + h = talloc_zero(req, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc_zero(h, struct ltdb_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->module = module; + ac->context = req->context; + ac->callback = req->callback; + + return h; +} + +/* + form a TDB_DATA for a record key + caller frees + + note that the key for a record can depend on whether the + dn refers to a case sensitive index record or not +*/ +struct TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn) +{ + struct ldb_context *ldb = module->ldb; + TDB_DATA key; + char *key_str = NULL; + const char *dn_folded = NULL; + + /* + most DNs are case insensitive. The exception is index DNs for + case sensitive attributes + + there are 3 cases dealt with in this code: + + 1) if the dn doesn't start with @ then uppercase the attribute + names and the attributes values of case insensitive attributes + 2) if the dn starts with @ then leave it alone - + the indexing code handles the rest + */ + + dn_folded = ldb_dn_get_casefold(dn); + if (!dn_folded) { + goto failed; + } + + key_str = talloc_strdup(ldb, "DN="); + if (!key_str) { + goto failed; + } + + key_str = talloc_strdup_append_buffer(key_str, dn_folded); + if (!key_str) { + goto failed; + } + + key.dptr = (uint8_t *)key_str; + key.dsize = strlen(key_str) + 1; + + return key; + +failed: + errno = ENOMEM; + key.dptr = NULL; + key.dsize = 0; + return key; +} + +/* + check special dn's have valid attributes + currently only @ATTRIBUTES is checked +*/ +int ltdb_check_special_dn(struct ldb_module *module, + const struct ldb_message *msg) +{ + int i, j; + + if (! ldb_dn_is_special(msg->dn) || + ! ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) { + return 0; + } + + /* we have @ATTRIBUTES, let's check attributes are fine */ + /* should we check that we deny multivalued attributes ? */ + for (i = 0; i < msg->num_elements; i++) { + for (j = 0; j < msg->elements[i].num_values; j++) { + if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) { + ldb_set_errstring(module->ldb, "Invalid attribute value in an @ATTRIBUTES entry"); + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + } + } + + return 0; +} + + +/* + we've made a modification to a dn - possibly reindex and + update sequence number +*/ +static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn) +{ + int ret = LDB_SUCCESS; + + if (ldb_dn_is_special(dn) && + (ldb_dn_check_special(dn, LTDB_INDEXLIST) || + ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) { + ret = ltdb_reindex(module); + } + + if (ret == LDB_SUCCESS && + !(ldb_dn_is_special(dn) && + ldb_dn_check_special(dn, LTDB_BASEINFO)) ) { + ret = ltdb_increase_sequence_number(module); + } + + return ret; +} + +/* + store a record into the db +*/ +int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs) +{ + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); + TDB_DATA tdb_key, tdb_data; + int ret; + + tdb_key = ltdb_key(module, msg->dn); + if (!tdb_key.dptr) { + return LDB_ERR_OTHER; + } + + ret = ltdb_pack_data(module, msg, &tdb_data); + if (ret == -1) { + talloc_free(tdb_key.dptr); + return LDB_ERR_OTHER; + } + + ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs); + if (ret == -1) { + ret = ltdb_err_map(tdb_error(ltdb->tdb)); + goto done; + } + + ret = ltdb_index_add(module, msg); + if (ret != LDB_SUCCESS) { + tdb_delete(ltdb->tdb, tdb_key); + } + +done: + talloc_free(tdb_key.dptr); + talloc_free(tdb_data.dptr); + + return ret; +} + + +static int ltdb_add_internal(struct ldb_module *module, + const struct ldb_message *msg) +{ + int ret; + + ret = ltdb_check_special_dn(module, msg); + if (ret != LDB_SUCCESS) { + return ret; + } + + if (ltdb_cache_load(module) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_store(module, msg, TDB_INSERT); + + if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { + ldb_asprintf_errstring(module->ldb, + "Entry %s already exists", + ldb_dn_get_linearized(msg->dn)); + return ret; + } + + if (ret == LDB_SUCCESS) { + ret = ltdb_index_one(module, msg, 1); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ltdb_modified(module, msg->dn); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return ret; +} + +/* + add a record to the database +*/ +static int ltdb_add(struct ldb_module *module, struct ldb_request *req) +{ + struct ltdb_private *ltdb; + struct ltdb_context *ltdb_ac; + int tret, ret = LDB_SUCCESS; + + ltdb = talloc_get_type(module->private_data, struct ltdb_private); + + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + + req->handle = init_ltdb_handle(ltdb, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + tret = ltdb_add_internal(module, req->op.add.message); + if (tret != LDB_SUCCESS) { + req->handle->status = tret; + goto done; + } + + if (ltdb_ac->callback) { + ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + } +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* + delete a record from the database, not updating indexes (used for deleting + index records) +*/ +int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn) +{ + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); + TDB_DATA tdb_key; + int ret; + + tdb_key = ltdb_key(module, dn); + if (!tdb_key.dptr) { + return LDB_ERR_OTHER; + } + + ret = tdb_delete(ltdb->tdb, tdb_key); + talloc_free(tdb_key.dptr); + + if (ret != 0) { + ret = ltdb_err_map(tdb_error(ltdb->tdb)); + } + + return ret; +} + +static int ltdb_delete_internal(struct ldb_module *module, struct ldb_dn *dn) +{ + struct ldb_message *msg; + int ret; + + msg = talloc(module, struct ldb_message); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* in case any attribute of the message was indexed, we need + to fetch the old record */ + ret = ltdb_search_dn1(module, dn, msg); + if (ret != LDB_SUCCESS) { + /* not finding the old record is an error */ + goto done; + } + + ret = ltdb_delete_noindex(module, dn); + if (ret != LDB_SUCCESS) { + goto done; + } + + /* remove one level attribute */ + ret = ltdb_index_one(module, msg, 0); + if (ret != LDB_SUCCESS) { + goto done; + } + + /* remove any indexed attributes */ + ret = ltdb_index_del(module, msg); + if (ret != LDB_SUCCESS) { + goto done; + } + + ret = ltdb_modified(module, dn); + if (ret != LDB_SUCCESS) { + goto done; + } + +done: + talloc_free(msg); + return ret; +} + +/* + delete a record from the database +*/ +static int ltdb_delete(struct ldb_module *module, struct ldb_request *req) +{ + struct ltdb_private *ltdb; + struct ltdb_context *ltdb_ac; + int tret, ret = LDB_SUCCESS; + + ltdb = talloc_get_type(module->private_data, struct ltdb_private); + + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + + req->handle = NULL; + + if (ltdb_cache_load(module) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + req->handle = init_ltdb_handle(ltdb, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + tret = ltdb_delete_internal(module, req->op.del.dn); + if (tret != LDB_SUCCESS) { + req->handle->status = tret; + goto done; + } + + if (ltdb_ac->callback) { + ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + } +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* + find an element by attribute name. At the moment this does a linear search, + it should be re-coded to use a binary search once all places that modify + records guarantee sorted order + + return the index of the first matching element if found, otherwise -1 +*/ +static int find_element(const struct ldb_message *msg, const char *name) +{ + unsigned int i; + for (i=0;inum_elements;i++) { + if (ldb_attr_cmp(msg->elements[i].name, name) == 0) { + return i; + } + } + return -1; +} + + +/* + add an element to an existing record. Assumes a elements array that we + can call re-alloc on, and assumed that we can re-use the data pointers from + the passed in additional values. Use with care! + + returns 0 on success, -1 on failure (and sets errno) +*/ +static int msg_add_element(struct ldb_context *ldb, + struct ldb_message *msg, + struct ldb_message_element *el) +{ + struct ldb_message_element *e2; + unsigned int i; + + e2 = talloc_realloc(msg, msg->elements, struct ldb_message_element, + msg->num_elements+1); + if (!e2) { + errno = ENOMEM; + return -1; + } + + msg->elements = e2; + + e2 = &msg->elements[msg->num_elements]; + + e2->name = el->name; + e2->flags = el->flags; + e2->values = NULL; + if (el->num_values != 0) { + e2->values = talloc_array(msg->elements, + struct ldb_val, el->num_values); + if (!e2->values) { + errno = ENOMEM; + return -1; + } + } + for (i=0;inum_values;i++) { + e2->values[i] = el->values[i]; + } + e2->num_values = el->num_values; + + msg->num_elements++; + + return 0; +} + +/* + delete all elements having a specified attribute name +*/ +static int msg_delete_attribute(struct ldb_module *module, + struct ldb_context *ldb, + struct ldb_message *msg, const char *name) +{ + const char *dn; + unsigned int i, j; + + dn = ldb_dn_get_linearized(msg->dn); + if (dn == NULL) { + return -1; + } + + for (i=0;inum_elements;i++) { + if (ldb_attr_cmp(msg->elements[i].name, name) == 0) { + for (j=0;jelements[i].num_values;j++) { + ltdb_index_del_value(module, dn, + &msg->elements[i], j); + } + talloc_free(msg->elements[i].values); + if (msg->num_elements > (i+1)) { + memmove(&msg->elements[i], + &msg->elements[i+1], + sizeof(struct ldb_message_element)* + (msg->num_elements - (i+1))); + } + msg->num_elements--; + i--; + msg->elements = talloc_realloc(msg, msg->elements, + struct ldb_message_element, + msg->num_elements); + } + } + + return 0; +} + +/* + delete all elements matching an attribute name/value + + return 0 on success, -1 on failure +*/ +static int msg_delete_element(struct ldb_module *module, + struct ldb_message *msg, + const char *name, + const struct ldb_val *val) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i; + int found; + struct ldb_message_element *el; + const struct ldb_schema_attribute *a; + + found = find_element(msg, name); + if (found == -1) { + return -1; + } + + el = &msg->elements[found]; + + a = ldb_schema_attribute_by_name(ldb, el->name); + + for (i=0;inum_values;i++) { + if (a->syntax->comparison_fn(ldb, ldb, + &el->values[i], val) == 0) { + if (inum_values-1) { + memmove(&el->values[i], &el->values[i+1], + sizeof(el->values[i])* + (el->num_values-(i+1))); + } + el->num_values--; + if (el->num_values == 0) { + return msg_delete_attribute(module, ldb, + msg, name); + } + return 0; + } + } + + return -1; +} + + +/* + modify a record - internal interface + + yuck - this is O(n^2). Luckily n is usually small so we probably + get away with it, but if we ever have really large attribute lists + then we'll need to look at this again +*/ +int ltdb_modify_internal(struct ldb_module *module, + const struct ldb_message *msg) +{ + struct ldb_context *ldb = module->ldb; + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); + TDB_DATA tdb_key, tdb_data; + struct ldb_message *msg2; + unsigned i, j; + int ret, idx; + + tdb_key = ltdb_key(module, msg->dn); + if (!tdb_key.dptr) { + return LDB_ERR_OTHER; + } + + tdb_data = tdb_fetch(ltdb->tdb, tdb_key); + if (!tdb_data.dptr) { + talloc_free(tdb_key.dptr); + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + msg2 = talloc(tdb_key.dptr, struct ldb_message); + if (msg2 == NULL) { + talloc_free(tdb_key.dptr); + return LDB_ERR_OTHER; + } + + ret = ltdb_unpack_data(module, &tdb_data, msg2); + if (ret == -1) { + ret = LDB_ERR_OTHER; + goto failed; + } + + if (!msg2->dn) { + msg2->dn = msg->dn; + } + + for (i=0;inum_elements;i++) { + struct ldb_message_element *el = &msg->elements[i]; + struct ldb_message_element *el2; + struct ldb_val *vals; + const char *dn; + + switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) { + + case LDB_FLAG_MOD_ADD: + /* add this element to the message. fail if it + already exists */ + idx = find_element(msg2, el->name); + + if (idx == -1) { + if (msg_add_element(ldb, msg2, el) != 0) { + ret = LDB_ERR_OTHER; + goto failed; + } + continue; + } + + el2 = &msg2->elements[idx]; + + /* An attribute with this name already exists, + * add all values if they don't already exist + * (check both the other elements to be added, + * and those already in the db). */ + + for (j=0;jnum_values;j++) { + if (ldb_msg_find_val(el2, &el->values[j])) { + ldb_asprintf_errstring(module->ldb, "%s: value #%d already exists", el->name, j); + ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + goto failed; + } + if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) { + ldb_asprintf_errstring(module->ldb, "%s: value #%d provided more than once", el->name, j); + ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + goto failed; + } + } + + vals = talloc_realloc(msg2->elements, el2->values, struct ldb_val, + el2->num_values + el->num_values); + + if (vals == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + for (j=0;jnum_values;j++) { + vals[el2->num_values + j] = + ldb_val_dup(vals, &el->values[j]); + } + + el2->values = vals; + el2->num_values += el->num_values; + + break; + + case LDB_FLAG_MOD_REPLACE: + /* replace all elements of this attribute name with the elements + listed. The attribute not existing is not an error */ + msg_delete_attribute(module, ldb, msg2, el->name); + + for (j=0;jnum_values;j++) { + if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) { + ldb_asprintf_errstring(module->ldb, "%s: value #%d provided more than once", el->name, j); + ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + goto failed; + } + } + + /* add the replacement element, if not empty */ + if (el->num_values != 0 && + msg_add_element(ldb, msg2, el) != 0) { + ret = LDB_ERR_OTHER; + goto failed; + } + break; + + case LDB_FLAG_MOD_DELETE: + + dn = ldb_dn_get_linearized(msg->dn); + if (dn == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + /* we could be being asked to delete all + values or just some values */ + if (msg->elements[i].num_values == 0) { + if (msg_delete_attribute(module, ldb, msg2, + msg->elements[i].name) != 0) { + ldb_asprintf_errstring(module->ldb, "No such attribute: %s for delete on %s", msg->elements[i].name, dn); + ret = LDB_ERR_NO_SUCH_ATTRIBUTE; + goto failed; + } + break; + } + for (j=0;jelements[i].num_values;j++) { + if (msg_delete_element(module, + msg2, + msg->elements[i].name, + &msg->elements[i].values[j]) != 0) { + ldb_asprintf_errstring(module->ldb, "No matching attribute value when deleting attribute: %s on %s", msg->elements[i].name, dn); + ret = LDB_ERR_NO_SUCH_ATTRIBUTE; + goto failed; + } + ret = ltdb_index_del_value(module, dn, &msg->elements[i], j); + if (ret != LDB_SUCCESS) { + goto failed; + } + } + break; + default: + ldb_asprintf_errstring(module->ldb, + "Invalid ldb_modify flags on %s: 0x%x", + msg->elements[i].name, + msg->elements[i].flags & LDB_FLAG_MOD_MASK); + ret = LDB_ERR_PROTOCOL_ERROR; + goto failed; + } + } + + /* we've made all the mods + * save the modified record back into the database */ + ret = ltdb_store(module, msg2, TDB_MODIFY); + if (ret != LDB_SUCCESS) { + goto failed; + } + + ret = ltdb_modified(module, msg->dn); + if (ret != LDB_SUCCESS) { + goto failed; + } + + talloc_free(tdb_key.dptr); + free(tdb_data.dptr); + return ret; + +failed: + talloc_free(tdb_key.dptr); + free(tdb_data.dptr); + return ret; +} + +/* + modify a record +*/ +static int ltdb_modify(struct ldb_module *module, struct ldb_request *req) +{ + struct ltdb_private *ltdb; + struct ltdb_context *ltdb_ac; + int tret, ret = LDB_SUCCESS; + + ltdb = talloc_get_type(module->private_data, struct ltdb_private); + + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + + req->handle = NULL; + + req->handle = init_ltdb_handle(ltdb, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + tret = ltdb_check_special_dn(module, req->op.mod.message); + if (tret != LDB_SUCCESS) { + req->handle->status = tret; + goto done; + } + + if (ltdb_cache_load(module) != 0) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + tret = ltdb_modify_internal(module, req->op.mod.message); + if (tret != LDB_SUCCESS) { + req->handle->status = tret; + goto done; + } + + if (ltdb_ac->callback) { + ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + } +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* + rename a record +*/ +static int ltdb_rename(struct ldb_module *module, struct ldb_request *req) +{ + struct ltdb_private *ltdb; + struct ltdb_context *ltdb_ac; + struct ldb_message *msg; + int tret, ret = LDB_SUCCESS; + + ltdb = talloc_get_type(module->private_data, struct ltdb_private); + + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + + req->handle = NULL; + + if (ltdb_cache_load(module) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + req->handle = init_ltdb_handle(ltdb, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + msg = talloc(ltdb_ac, struct ldb_message); + if (msg == NULL) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + /* in case any attribute of the message was indexed, we need + to fetch the old record */ + tret = ltdb_search_dn1(module, req->op.rename.olddn, msg); + if (tret != LDB_SUCCESS) { + /* not finding the old record is an error */ + req->handle->status = tret; + goto done; + } + + msg->dn = ldb_dn_copy(msg, req->op.rename.newdn); + if (!msg->dn) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + if (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) == 0) { + /* The rename operation is apparently only changing case - + the DNs are the same. Delete the old DN before adding + the new one to avoid a TDB_ERR_EXISTS error. + + The only drawback to this is that if the delete + succeeds but the add fails, we rely on the + transaction to roll this all back. */ + ret = ltdb_delete_internal(module, req->op.rename.olddn); + if (ret != LDB_SUCCESS) { + goto done; + } + + ret = ltdb_add_internal(module, msg); + if (ret != LDB_SUCCESS) { + goto done; + } + } else { + /* The rename operation is changing DNs. Try to add the new + DN first to avoid clobbering another DN not related to + this rename operation. */ + ret = ltdb_add_internal(module, msg); + if (ret != LDB_SUCCESS) { + goto done; + } + + tret = ltdb_delete_internal(module, req->op.rename.olddn); + if (tret != LDB_SUCCESS) { + ltdb_delete_internal(module, req->op.rename.newdn); + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + } + + if (ltdb_ac->callback) { + ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + } +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +static int ltdb_start_trans(struct ldb_module *module) +{ + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); + + if (tdb_transaction_start(ltdb->tdb) != 0) { + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + ltdb->in_transaction++; + + return LDB_SUCCESS; +} + +static int ltdb_end_trans(struct ldb_module *module) +{ + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); + + ltdb->in_transaction--; + + if (tdb_transaction_commit(ltdb->tdb) != 0) { + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + return LDB_SUCCESS; +} + +static int ltdb_del_trans(struct ldb_module *module) +{ + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); + + ltdb->in_transaction--; + + if (tdb_transaction_cancel(ltdb->tdb) != 0) { + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + return LDB_SUCCESS; +} + +static int ltdb_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + return handle->status; +} + +static int ltdb_request(struct ldb_module *module, struct ldb_request *req) +{ + /* check for oustanding critical controls + * and return an error if found */ + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + + /* search, add, modify, delete, rename are handled by their own, + * no other op supported */ + return LDB_ERR_OPERATIONS_ERROR; +} + +/* + return sequenceNumber from @BASEINFO +*/ +static int ltdb_sequence_number(struct ldb_module *module, + struct ldb_request *req) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_message *msg = NULL; + struct ldb_dn *dn; + const char *date; + int tret; + + tmp_ctx = talloc_new(req); + if (tmp_ctx == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + dn = ldb_dn_new(tmp_ctx, module->ldb, LTDB_BASEINFO); + + msg = talloc(tmp_ctx, struct ldb_message); + if (msg == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->op.seq_num.flags = 0; + + tret = ltdb_search_dn1(module, dn, msg); + if (tret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + /* zero is as good as anything when we don't know */ + req->op.seq_num.seq_num = 0; + return LDB_SUCCESS; + } + + switch (req->op.seq_num.type) { + case LDB_SEQ_HIGHEST_SEQ: + req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0); + break; + case LDB_SEQ_NEXT: + req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0); + req->op.seq_num.seq_num++; + break; + case LDB_SEQ_HIGHEST_TIMESTAMP: + date = ldb_msg_find_attr_as_string(msg, LTDB_MOD_TIMESTAMP, NULL); + if (date) { + req->op.seq_num.seq_num = ldb_string_to_time(date); + } else { + req->op.seq_num.seq_num = 0; + /* zero is as good as anything when we don't know */ + } + break; + } + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + +static const struct ldb_module_ops ltdb_ops = { + .name = "tdb", + .search = ltdb_search, + .add = ltdb_add, + .modify = ltdb_modify, + .del = ltdb_delete, + .rename = ltdb_rename, + .request = ltdb_request, + .start_transaction = ltdb_start_trans, + .end_transaction = ltdb_end_trans, + .del_transaction = ltdb_del_trans, + .wait = ltdb_wait, + .sequence_number = ltdb_sequence_number +}; + +/* + connect to the database +*/ +static int ltdb_connect(struct ldb_context *ldb, const char *url, + unsigned int flags, const char *options[], + struct ldb_module **module) +{ + const char *path; + int tdb_flags, open_flags; + struct ltdb_private *ltdb; + + /* parse the url */ + if (strchr(url, ':')) { + if (strncmp(url, "tdb://", 6) != 0) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "Invalid tdb URL '%s'", url); + return -1; + } + path = url+6; + } else { + path = url; + } + + tdb_flags = TDB_DEFAULT | TDB_SEQNUM; + + /* check for the 'nosync' option */ + if (flags & LDB_FLG_NOSYNC) { + tdb_flags |= TDB_NOSYNC; + } + + /* and nommap option */ + if (flags & LDB_FLG_NOMMAP) { + tdb_flags |= TDB_NOMMAP; + } + + if (flags & LDB_FLG_RDONLY) { + open_flags = O_RDONLY; + } else { + open_flags = O_CREAT | O_RDWR; + } + + ltdb = talloc_zero(ldb, struct ltdb_private); + if (!ltdb) { + ldb_oom(ldb); + return -1; + } + + /* note that we use quite a large default hash size */ + ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000, + tdb_flags, open_flags, + ldb->create_perms, ldb); + if (!ltdb->tdb) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "Unable to open tdb '%s'\n", path); + talloc_free(ltdb); + return -1; + } + + ltdb->sequence_number = 0; + + *module = talloc(ldb, struct ldb_module); + if (!module) { + ldb_oom(ldb); + talloc_free(ltdb); + return -1; + } + talloc_set_name_const(*module, "ldb_tdb backend"); + (*module)->ldb = ldb; + (*module)->prev = (*module)->next = NULL; + (*module)->private_data = ltdb; + (*module)->ops = <db_ops; + + if (ltdb_cache_load(*module) != 0) { + talloc_free(*module); + talloc_free(ltdb); + return -1; + } + + return 0; +} + +const struct ldb_backend_ops ldb_tdb_backend_ops = { + .name = "tdb", + .connect_fn = ltdb_connect +}; diff --git a/ldb/ldb_tdb/ldb_tdb.h b/ldb/ldb_tdb/ldb_tdb.h new file mode 100644 index 000000000..4beced30e --- /dev/null +++ b/ldb/ldb_tdb/ldb_tdb.h @@ -0,0 +1,130 @@ +#if (_SAMBA_BUILD_ == 3) +#include "tdb/include/tdb.h" +#else +#include "replace.h" +#include "system/wait.h" +#include "tdb.h" +#endif + +/* this private structure is used by the ltdb backend in the + ldb_context */ +struct ltdb_private { + TDB_CONTEXT *tdb; + unsigned int connect_flags; + + /* a double is used for portability and ease of string + handling. It has plenty of digits of precision */ + unsigned long long sequence_number; + + /* the low level tdb seqnum - used to avoid loading BASEINFO when + possible */ + int tdb_seqnum; + + struct ltdb_cache { + struct ldb_message *indexlist; + struct ldb_message *attributes; + + struct { + char *name; + int flags; + } last_attribute; + } *cache; + + int in_transaction; + + bool check_base; +}; + +/* + the async local context + holds also internal search state during a full db search +*/ +struct ltdb_context { + struct ldb_module *module; + + /* search stuff */ + const struct ldb_parse_tree *tree; + struct ldb_dn *base; + enum ldb_scope scope; + const char * const *attrs; + + /* async stuff */ + void *context; + int (*callback)(struct ldb_context *, void *, struct ldb_reply *); +}; + +/* special record types */ +#define LTDB_INDEX "@INDEX" +#define LTDB_INDEXLIST "@INDEXLIST" +#define LTDB_IDX "@IDX" +#define LTDB_IDXATTR "@IDXATTR" +#define LTDB_IDXONE "@IDXONE" +#define LTDB_BASEINFO "@BASEINFO" +#define LTDB_OPTIONS "@OPTIONS" +#define LTDB_ATTRIBUTES "@ATTRIBUTES" + +/* special attribute types */ +#define LTDB_SEQUENCE_NUMBER "sequenceNumber" +#define LTDB_CHECK_BASE "checkBaseOnSearch" +#define LTDB_MOD_TIMESTAMP "whenChanged" +#define LTDB_OBJECTCLASS "objectClass" + +/* The following definitions come from lib/ldb/ldb_tdb/ldb_cache.c */ + +int ltdb_cache_reload(struct ldb_module *module); +int ltdb_cache_load(struct ldb_module *module); +int ltdb_increase_sequence_number(struct ldb_module *module); +int ltdb_check_at_attributes_values(const struct ldb_val *value); + +/* The following definitions come from lib/ldb/ldb_tdb/ldb_index.c */ + +struct ldb_parse_tree; + +int ltdb_search_indexed(struct ldb_handle *handle); +int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg); +int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg); +int ltdb_index_one(struct ldb_module *module, const struct ldb_message *msg, int add); +int ltdb_reindex(struct ldb_module *module); + +/* The following definitions come from lib/ldb/ldb_tdb/ldb_pack.c */ + +int ltdb_pack_data(struct ldb_module *module, + const struct ldb_message *message, + struct TDB_DATA *data); +void ltdb_unpack_data_free(struct ldb_module *module, + struct ldb_message *message); +int ltdb_unpack_data(struct ldb_module *module, + const struct TDB_DATA *data, + struct ldb_message *message); + +/* The following definitions come from lib/ldb/ldb_tdb/ldb_search.c */ + +int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name, + const struct ldb_val *val); +void ltdb_search_dn1_free(struct ldb_module *module, struct ldb_message *msg); +int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg); +int ltdb_add_attr_results(struct ldb_module *module, + TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + const char * const attrs[], + unsigned int *count, + struct ldb_message ***res); +int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs); +int ltdb_search(struct ldb_module *module, struct ldb_request *req); + +/* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c */ +struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module, + struct ldb_request *req); +struct TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn); +int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs); +int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn); +int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg); + +int ltdb_index_del_value(struct ldb_module *module, const char *dn, + struct ldb_message_element *el, int v_idx); + +struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx, + const char *path, int hash_size, int tdb_flags, + int open_flags, mode_t mode, + struct ldb_context *ldb); + diff --git a/ldb/ldb_tdb/ldb_tdb_wrap.c b/ldb/ldb_tdb/ldb_tdb_wrap.c new file mode 100644 index 000000000..654574cd2 --- /dev/null +++ b/ldb/ldb_tdb/ldb_tdb_wrap.c @@ -0,0 +1,153 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +#include "ldb_includes.h" + +#include "ldb_tdb.h" + +/* + the purpose of this code is to work around the braindead posix locking + rules, to allow us to have a ldb open more than once while allowing + locking to work +*/ + +struct ltdb_wrap { + struct ltdb_wrap *next, *prev; + struct tdb_context *tdb; + dev_t device; + ino_t inode; +}; + +static struct ltdb_wrap *tdb_list; + +/* destroy the last connection to a tdb */ +static int ltdb_wrap_destructor(struct ltdb_wrap *w) +{ + tdb_close(w->tdb); + if (w->next) { + w->next->prev = w->prev; + } + if (w->prev) { + w->prev->next = w->next; + } + if (w == tdb_list) { + tdb_list = w->next; + } + return 0; +} + +static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4); +static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) +{ + va_list ap; + const char *name = tdb_name(tdb); + struct ldb_context *ldb = talloc_get_type(tdb_get_logging_private(tdb), struct ldb_context); + enum ldb_debug_level ldb_level; + char *message; + va_start(ap, fmt); + message = talloc_vasprintf(ldb, fmt, ap); + va_end(ap); + + switch (level) { + case TDB_DEBUG_FATAL: + ldb_level = LDB_DEBUG_FATAL; + break; + case TDB_DEBUG_ERROR: + ldb_level = LDB_DEBUG_ERROR; + break; + case TDB_DEBUG_WARNING: + ldb_level = LDB_DEBUG_WARNING; + break; + case TDB_DEBUG_TRACE: + ldb_level = LDB_DEBUG_TRACE; + break; + default: + ldb_level = LDB_DEBUG_FATAL; + } + + ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message); + talloc_free(message); +} + +/* + wrapped connection to a tdb database. The caller should _not_ free + this as it is not a talloc structure (as tdb does not use talloc + yet). It will auto-close when the caller frees the mem_ctx that is + passed to this call + */ +struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx, + const char *path, int hash_size, + int tdb_flags, + int open_flags, mode_t mode, + struct ldb_context *ldb) +{ + struct ltdb_wrap *w; + struct stat st; + struct tdb_logging_context log_ctx; + + log_ctx.log_fn = ltdb_log_fn; + log_ctx.log_private = ldb; + + if (stat(path, &st) == 0) { + for (w=tdb_list;w;w=w->next) { + if (st.st_dev == w->device && st.st_ino == w->inode) { + if (!talloc_reference(mem_ctx, w)) { + return NULL; + } + return w->tdb; + } + } + } + + w = talloc(mem_ctx, struct ltdb_wrap); + if (w == NULL) { + return NULL; + } + + w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode, &log_ctx, NULL); + if (w->tdb == NULL) { + talloc_free(w); + return NULL; + } + + if (fstat(tdb_fd(w->tdb), &st) != 0) { + tdb_close(w->tdb); + talloc_free(w); + return NULL; + } + + w->device = st.st_dev; + w->inode = st.st_ino; + + talloc_set_destructor(w, ltdb_wrap_destructor); + + w->next = tdb_list; + w->prev = NULL; + if (tdb_list) { + tdb_list->prev = w; + } + tdb_list = w; + + return w->tdb; +} + diff --git a/ldb/ldb_wrap.c b/ldb/ldb_wrap.c new file mode 100644 index 000000000..f9dd8471c --- /dev/null +++ b/ldb/ldb_wrap.c @@ -0,0 +1,6586 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.35 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +#define SWIGPYTHON +#define SWIG_PYTHON_NO_BUILD_NONE +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# elif defined(__HP_aCC) +/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ +/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + + + +/* Python.h has to appear first */ +#include + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The swig conversion methods, as ConvertPtr, return and integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old swig versions, you usually write code as: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit as: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + that seems to be the same, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + requires also to SWIG_ConvertPtr to return new result values, as + + int SWIG_ConvertPtr(obj, ptr,...) { + if () { + if () { + *ptr = ; + return SWIG_NEWOBJ; + } else { + *ptr = ; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + swig errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() + + + */ +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class" == "Class", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like ||... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like ||... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCompare(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + + +/* think of this as a c++ template<> or a scheme macro */ +#define SWIG_TypeCheck_Template(comparison, ty) \ + if (ty) { \ + swig_cast_info *iter = ty->cast; \ + while (iter) { \ + if (comparison) { \ + if (iter == ty->cast) return iter; \ + /* Move iter to the top of the linked list */ \ + iter->prev->next = iter->next; \ + if (iter->next) \ + iter->next->prev = iter->prev; \ + iter->next = ty->cast; \ + iter->prev = 0; \ + if (ty->cast) ty->cast->prev = iter; \ + ty->cast = iter; \ + return iter; \ + } \ + iter = iter->next; \ + } \ + } \ + return 0 + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty); +} + +/* Same as previous function, except strcmp is replaced with a pointer comparison */ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) { + SWIG_TypeCheck_Template(iter->type == from, into); +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + + +/* Add PyOS_snprintf for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# define PyOS_snprintf _snprintf +# else +# define PyOS_snprintf snprintf +# endif +#endif + +/* A crude PyString_FromFormat implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 + +#ifndef SWIG_PYBUFFER_SIZE +# define SWIG_PYBUFFER_SIZE 1024 +#endif + +static PyObject * +PyString_FromFormat(const char *fmt, ...) { + va_list ap; + char buf[SWIG_PYBUFFER_SIZE * 2]; + int res; + va_start(ap, fmt); + res = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); +} +#endif + +/* Add PyObject_Del for old Pythons */ +#if PY_VERSION_HEX < 0x01060000 +# define PyObject_Del(op) PyMem_DEL((op)) +#endif +#ifndef PyObject_DEL +# define PyObject_DEL PyObject_Del +#endif + +/* A crude PyExc_StopIteration exception for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# ifndef PyExc_StopIteration +# define PyExc_StopIteration PyExc_RuntimeError +# endif +# ifndef PyObject_GenericGetAttr +# define PyObject_GenericGetAttr 0 +# endif +#endif +/* Py_NotImplemented is defined in 2.1 and up. */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef Py_NotImplemented +# define Py_NotImplemented PyExc_RuntimeError +# endif +#endif + + +/* A crude PyString_AsStringAndSize implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef PyString_AsStringAndSize +# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} +# endif +#endif + +/* PySequence_Size for old Pythons */ +#if PY_VERSION_HEX < 0x02000000 +# ifndef PySequence_Size +# define PySequence_Size PySequence_Length +# endif +#endif + + +/* PyBool_FromLong for old Pythons */ +#if PY_VERSION_HEX < 0x02030000 +static +PyObject *PyBool_FromLong(long ok) +{ + PyObject *result = ok ? Py_True : Py_False; + Py_INCREF(result); + return result; +} +#endif + +/* Py_ssize_t for old Pythons */ +/* This code is as recommended by: */ +/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +#endif + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIME PyObject* +SWIG_Python_ErrorType(int code) { + PyObject* type = 0; + switch(code) { + case SWIG_MemoryError: + type = PyExc_MemoryError; + break; + case SWIG_IOError: + type = PyExc_IOError; + break; + case SWIG_RuntimeError: + type = PyExc_RuntimeError; + break; + case SWIG_IndexError: + type = PyExc_IndexError; + break; + case SWIG_TypeError: + type = PyExc_TypeError; + break; + case SWIG_DivisionByZero: + type = PyExc_ZeroDivisionError; + break; + case SWIG_OverflowError: + type = PyExc_OverflowError; + break; + case SWIG_SyntaxError: + type = PyExc_SyntaxError; + break; + case SWIG_ValueError: + type = PyExc_ValueError; + break; + case SWIG_SystemError: + type = PyExc_SystemError; + break; + case SWIG_AttributeError: + type = PyExc_AttributeError; + break; + default: + type = PyExc_RuntimeError; + } + return type; +} + + +SWIGRUNTIME void +SWIG_Python_AddErrorMsg(const char* mesg) +{ + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + + if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + PyErr_Clear(); + Py_XINCREF(type); + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + Py_DECREF(old_str); + Py_DECREF(value); + } else { + PyErr_SetString(PyExc_RuntimeError, mesg); + } +} + + + +#if defined(SWIG_PYTHON_NO_THREADS) +# if defined(SWIG_PYTHON_THREADS) +# undef SWIG_PYTHON_THREADS +# endif +#endif +#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ +# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) +# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ +# define SWIG_PYTHON_USE_GIL +# endif +# endif +# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ +# ifndef SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() +# endif +# ifdef __cplusplus /* C++ code */ + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + public: + void end() { if (status) { PyEval_RestoreThread(save); status = false; }} + SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} + ~SWIG_Python_Thread_Allow() { end(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow +# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() +# else /* C code */ +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() +# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() +# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) +# define SWIG_PYTHON_INITIALIZE_THREADS +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif + +/* ----------------------------------------------------------------------------- + * Python API portion that goes into the runtime + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_PY_POINTER 4 +#define SWIG_PY_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * pyrun.swg + * + * This file contains the runtime support for Python modules + * and includes code for managing global variables and pointer + * type checking. + * + * ----------------------------------------------------------------------------- */ + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) +#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) +#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(ptr, type, flags) +#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) +#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) +#define swig_owntype int + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Python_GetModule() +#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) +#define SWIG_NewClientData(obj) PySwigClientData_New(obj) + +#define SWIG_SetErrorObj SWIG_Python_SetErrorObj +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Runtime API implementation */ + +/* Error manipulation */ + +SWIGINTERN void +SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetObject(errtype, obj); + Py_DECREF(obj); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +SWIGINTERN void +SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(errtype, (char *) msg); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) + +/* Set a constant value */ + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { + PyDict_SetItemString(d, (char*) name, obj); + Py_DECREF(obj); +} + +/* Append a value to the result obj */ + +SWIGINTERN PyObject* +SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { +#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyList_Check(result)) { + PyObject *o2 = result; + result = PyList_New(1); + PyList_SetItem(result, 0, o2); + } + PyList_Append(result,obj); + Py_DECREF(obj); + } + return result; +#else + PyObject* o2; + PyObject* o3; + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyTuple_Check(result)) { + o2 = result; + result = PyTuple_New(1); + PyTuple_SET_ITEM(result, 0, o2); + } + o3 = PyTuple_New(1); + PyTuple_SET_ITEM(o3, 0, obj); + o2 = result; + result = PySequence_Concat(o2, o3); + Py_DECREF(o2); + Py_DECREF(o3); + } + return result; +#endif +} + +/* Unpack the argument tuple */ + +SWIGINTERN int +SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) +{ + if (!args) { + if (!min && !max) { + return 1; + } else { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", + name, (min == max ? "" : "at least "), (int)min); + return 0; + } + } + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); + return 0; + } else { + register Py_ssize_t l = PyTuple_GET_SIZE(args); + if (l < min) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at least "), (int)min, (int)l); + return 0; + } else if (l > max) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at most "), (int)max, (int)l); + return 0; + } else { + register int i; + for (i = 0; i < l; ++i) { + objs[i] = PyTuple_GET_ITEM(args, i); + } + for (; l < max; ++l) { + objs[l] = 0; + } + return i + 1; + } + } +} + +/* A functor is a function object with one single object argument */ +#if PY_VERSION_HEX >= 0x02020000 +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); +#else +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); +#endif + +/* + Helper for static pointer initialization for both C and C++ code, for example + static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); +*/ +#ifdef __cplusplus +#define SWIG_STATIC_POINTER(var) var +#else +#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var +#endif + +/* ----------------------------------------------------------------------------- + * Pointer declarations + * ----------------------------------------------------------------------------- */ + +/* Flags for new pointer objects */ +#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) +#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) + +#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* How to access Py_None */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# ifndef SWIG_PYTHON_NO_BUILD_NONE +# ifndef SWIG_PYTHON_BUILD_NONE +# define SWIG_PYTHON_BUILD_NONE +# endif +# endif +#endif + +#ifdef SWIG_PYTHON_BUILD_NONE +# ifdef Py_None +# undef Py_None +# define Py_None SWIG_Py_None() +# endif +SWIGRUNTIMEINLINE PyObject * +_SWIG_Py_None(void) +{ + PyObject *none = Py_BuildValue((char*)""); + Py_DECREF(none); + return none; +} +SWIGRUNTIME PyObject * +SWIG_Py_None(void) +{ + static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); + return none; +} +#endif + +/* The python void return value */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Py_Void(void) +{ + PyObject *none = Py_None; + Py_INCREF(none); + return none; +} + +/* PySwigClientData */ + +typedef struct { + PyObject *klass; + PyObject *newraw; + PyObject *newargs; + PyObject *destroy; + int delargs; + int implicitconv; +} PySwigClientData; + +SWIGRUNTIMEINLINE int +SWIG_Python_CheckImplicit(swig_type_info *ty) +{ + PySwigClientData *data = (PySwigClientData *)ty->clientdata; + return data ? data->implicitconv : 0; +} + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_ExceptionType(swig_type_info *desc) { + PySwigClientData *data = desc ? (PySwigClientData *) desc->clientdata : 0; + PyObject *klass = data ? data->klass : 0; + return (klass ? klass : PyExc_RuntimeError); +} + + +SWIGRUNTIME PySwigClientData * +PySwigClientData_New(PyObject* obj) +{ + if (!obj) { + return 0; + } else { + PySwigClientData *data = (PySwigClientData *)malloc(sizeof(PySwigClientData)); + /* the klass element */ + data->klass = obj; + Py_INCREF(data->klass); + /* the newraw method and newargs arguments used to create a new raw instance */ + if (PyClass_Check(obj)) { + data->newraw = 0; + data->newargs = obj; + Py_INCREF(obj); + } else { +#if (PY_VERSION_HEX < 0x02020000) + data->newraw = 0; +#else + data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); +#endif + if (data->newraw) { + Py_INCREF(data->newraw); + data->newargs = PyTuple_New(1); + PyTuple_SetItem(data->newargs, 0, obj); + } else { + data->newargs = obj; + } + Py_INCREF(data->newargs); + } + /* the destroy method, aka as the C++ delete method */ + data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); + if (PyErr_Occurred()) { + PyErr_Clear(); + data->destroy = 0; + } + if (data->destroy) { + int flags; + Py_INCREF(data->destroy); + flags = PyCFunction_GET_FLAGS(data->destroy); +#ifdef METH_O + data->delargs = !(flags & (METH_O)); +#else + data->delargs = 0; +#endif + } else { + data->delargs = 0; + } + data->implicitconv = 0; + return data; + } +} + +SWIGRUNTIME void +PySwigClientData_Del(PySwigClientData* data) +{ + Py_XDECREF(data->newraw); + Py_XDECREF(data->newargs); + Py_XDECREF(data->destroy); +} + +/* =============== PySwigObject =====================*/ + +typedef struct { + PyObject_HEAD + void *ptr; + swig_type_info *ty; + int own; + PyObject *next; +} PySwigObject; + +SWIGRUNTIME PyObject * +PySwigObject_long(PySwigObject *v) +{ + return PyLong_FromVoidPtr(v->ptr); +} + +SWIGRUNTIME PyObject * +PySwigObject_format(const char* fmt, PySwigObject *v) +{ + PyObject *res = NULL; + PyObject *args = PyTuple_New(1); + if (args) { + if (PyTuple_SetItem(args, 0, PySwigObject_long(v)) == 0) { + PyObject *ofmt = PyString_FromString(fmt); + if (ofmt) { + res = PyString_Format(ofmt,args); + Py_DECREF(ofmt); + } + Py_DECREF(args); + } + } + return res; +} + +SWIGRUNTIME PyObject * +PySwigObject_oct(PySwigObject *v) +{ + return PySwigObject_format("%o",v); +} + +SWIGRUNTIME PyObject * +PySwigObject_hex(PySwigObject *v) +{ + return PySwigObject_format("%x",v); +} + +SWIGRUNTIME PyObject * +#ifdef METH_NOARGS +PySwigObject_repr(PySwigObject *v) +#else +PySwigObject_repr(PySwigObject *v, PyObject *args) +#endif +{ + const char *name = SWIG_TypePrettyName(v->ty); + PyObject *hex = PySwigObject_hex(v); + PyObject *repr = PyString_FromFormat("", name, PyString_AsString(hex)); + Py_DECREF(hex); + if (v->next) { +#ifdef METH_NOARGS + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next); +#else + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next, args); +#endif + PyString_ConcatAndDel(&repr,nrep); + } + return repr; +} + +SWIGRUNTIME int +PySwigObject_print(PySwigObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ +#ifdef METH_NOARGS + PyObject *repr = PySwigObject_repr(v); +#else + PyObject *repr = PySwigObject_repr(v, NULL); +#endif + if (repr) { + fputs(PyString_AsString(repr), fp); + Py_DECREF(repr); + return 0; + } else { + return 1; + } +} + +SWIGRUNTIME PyObject * +PySwigObject_str(PySwigObject *v) +{ + char result[SWIG_BUFFER_SIZE]; + return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ? + PyString_FromString(result) : 0; +} + +SWIGRUNTIME int +PySwigObject_compare(PySwigObject *v, PySwigObject *w) +{ + void *i = v->ptr; + void *j = w->ptr; + return (i < j) ? -1 : ((i > j) ? 1 : 0); +} + +SWIGRUNTIME PyTypeObject* _PySwigObject_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigObject_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigObject_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigObject_Check(PyObject *op) { + return ((op)->ob_type == PySwigObject_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigObject") == 0); +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own); + +SWIGRUNTIME void +PySwigObject_dealloc(PyObject *v) +{ + PySwigObject *sobj = (PySwigObject *) v; + PyObject *next = sobj->next; + if (sobj->own == SWIG_POINTER_OWN) { + swig_type_info *ty = sobj->ty; + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + PyObject *destroy = data ? data->destroy : 0; + if (destroy) { + /* destroy is always a VARARGS method */ + PyObject *res; + if (data->delargs) { + /* we need to create a temporal object to carry the destroy operation */ + PyObject *tmp = PySwigObject_New(sobj->ptr, ty, 0); + res = SWIG_Python_CallFunctor(destroy, tmp); + Py_DECREF(tmp); + } else { + PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); + PyObject *mself = PyCFunction_GET_SELF(destroy); + res = ((*meth)(mself, v)); + } + Py_XDECREF(res); + } +#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) + else { + const char *name = SWIG_TypePrettyName(ty); + printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); + } +#endif + } + Py_XDECREF(next); + PyObject_DEL(v); +} + +SWIGRUNTIME PyObject* +PySwigObject_append(PyObject* v, PyObject* next) +{ + PySwigObject *sobj = (PySwigObject *) v; +#ifndef METH_O + PyObject *tmp = 0; + if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; + next = tmp; +#endif + if (!PySwigObject_Check(next)) { + return NULL; + } + sobj->next = next; + Py_INCREF(next); + return SWIG_Py_Void(); +} + +SWIGRUNTIME PyObject* +#ifdef METH_NOARGS +PySwigObject_next(PyObject* v) +#else +PySwigObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *) v; + if (sobj->next) { + Py_INCREF(sobj->next); + return sobj->next; + } else { + return SWIG_Py_Void(); + } +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_disown(PyObject *v) +#else +PySwigObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = 0; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_acquire(PyObject *v) +#else +PySwigObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = SWIG_POINTER_OWN; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +PySwigObject_own(PyObject *v, PyObject *args) +{ + PyObject *val = 0; +#if (PY_VERSION_HEX < 0x02020000) + if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) +#else + if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) +#endif + { + return NULL; + } + else + { + PySwigObject *sobj = (PySwigObject *)v; + PyObject *obj = PyBool_FromLong(sobj->own); + if (val) { +#ifdef METH_NOARGS + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v); + } else { + PySwigObject_disown(v); + } +#else + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v,args); + } else { + PySwigObject_disown(v,args); + } +#endif + } + return obj; + } +} + +#ifdef METH_O +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_NOARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_O, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_NOARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#else +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_VARARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_VARARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#endif + +#if PY_VERSION_HEX < 0x02020000 +SWIGINTERN PyObject * +PySwigObject_getattr(PySwigObject *sobj,char *name) +{ + return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); +} +#endif + +SWIGRUNTIME PyTypeObject* +_PySwigObject_type(void) { + static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; + + static PyNumberMethods PySwigObject_as_number = { + (binaryfunc)0, /*nb_add*/ + (binaryfunc)0, /*nb_subtract*/ + (binaryfunc)0, /*nb_multiply*/ + (binaryfunc)0, /*nb_divide*/ + (binaryfunc)0, /*nb_remainder*/ + (binaryfunc)0, /*nb_divmod*/ + (ternaryfunc)0,/*nb_power*/ + (unaryfunc)0, /*nb_negative*/ + (unaryfunc)0, /*nb_positive*/ + (unaryfunc)0, /*nb_absolute*/ + (inquiry)0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + (coercion)0, /*nb_coerce*/ + (unaryfunc)PySwigObject_long, /*nb_int*/ + (unaryfunc)PySwigObject_long, /*nb_long*/ + (unaryfunc)0, /*nb_float*/ + (unaryfunc)PySwigObject_oct, /*nb_oct*/ + (unaryfunc)PySwigObject_hex, /*nb_hex*/ +#if PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ +#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ +#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ + 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ +#endif + }; + + static PyTypeObject pyswigobject_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigObject", /* tp_name */ + sizeof(PySwigObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigObject_dealloc, /* tp_dealloc */ + (printfunc)PySwigObject_print, /* tp_print */ +#if PY_VERSION_HEX < 0x02020000 + (getattrfunc)PySwigObject_getattr, /* tp_getattr */ +#else + (getattrfunc)0, /* tp_getattr */ +#endif + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigObject_compare, /* tp_compare */ + (reprfunc)PySwigObject_repr, /* tp_repr */ + &PySwigObject_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigObject_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigobject_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + swigobject_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigobject_type = tmp; + pyswigobject_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigobject_type; +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own) +{ + PySwigObject *sobj = PyObject_NEW(PySwigObject, PySwigObject_type()); + if (sobj) { + sobj->ptr = ptr; + sobj->ty = ty; + sobj->own = own; + sobj->next = 0; + } + return (PyObject *)sobj; +} + +/* ----------------------------------------------------------------------------- + * Implements a simple Swig Packed type, and use it instead of string + * ----------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + void *pack; + swig_type_info *ty; + size_t size; +} PySwigPacked; + +SWIGRUNTIME int +PySwigPacked_print(PySwigPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char result[SWIG_BUFFER_SIZE]; + fputs("pack, v->size, 0, sizeof(result))) { + fputs("at ", fp); + fputs(result, fp); + } + fputs(v->ty->name,fp); + fputs(">", fp); + return 0; +} + +SWIGRUNTIME PyObject * +PySwigPacked_repr(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + return PyString_FromFormat("", result, v->ty->name); + } else { + return PyString_FromFormat("", v->ty->name); + } +} + +SWIGRUNTIME PyObject * +PySwigPacked_str(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ + return PyString_FromFormat("%s%s", result, v->ty->name); + } else { + return PyString_FromString(v->ty->name); + } +} + +SWIGRUNTIME int +PySwigPacked_compare(PySwigPacked *v, PySwigPacked *w) +{ + size_t i = v->size; + size_t j = w->size; + int s = (i < j) ? -1 : ((i > j) ? 1 : 0); + return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); +} + +SWIGRUNTIME PyTypeObject* _PySwigPacked_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigPacked_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigPacked_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigPacked_Check(PyObject *op) { + return ((op)->ob_type == _PySwigPacked_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigPacked") == 0); +} + +SWIGRUNTIME void +PySwigPacked_dealloc(PyObject *v) +{ + if (PySwigPacked_Check(v)) { + PySwigPacked *sobj = (PySwigPacked *) v; + free(sobj->pack); + } + PyObject_DEL(v); +} + +SWIGRUNTIME PyTypeObject* +_PySwigPacked_type(void) { + static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; + static PyTypeObject pyswigpacked_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigPacked", /* tp_name */ + sizeof(PySwigPacked), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigPacked_dealloc, /* tp_dealloc */ + (printfunc)PySwigPacked_print, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigPacked_compare, /* tp_compare */ + (reprfunc)PySwigPacked_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigPacked_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigpacked_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigpacked_type = tmp; + pyswigpacked_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigpacked_type; +} + +SWIGRUNTIME PyObject * +PySwigPacked_New(void *ptr, size_t size, swig_type_info *ty) +{ + PySwigPacked *sobj = PyObject_NEW(PySwigPacked, PySwigPacked_type()); + if (sobj) { + void *pack = malloc(size); + if (pack) { + memcpy(pack, ptr, size); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = size; + } else { + PyObject_DEL((PyObject *) sobj); + sobj = 0; + } + } + return (PyObject *) sobj; +} + +SWIGRUNTIME swig_type_info * +PySwigPacked_UnpackData(PyObject *obj, void *ptr, size_t size) +{ + if (PySwigPacked_Check(obj)) { + PySwigPacked *sobj = (PySwigPacked *)obj; + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIMEINLINE PyObject * +_SWIG_This(void) +{ + return PyString_FromString("this"); +} + +SWIGRUNTIME PyObject * +SWIG_This(void) +{ + static PyObject *SWIG_STATIC_POINTER(swig_this) = _SWIG_This(); + return swig_this; +} + +/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ + +SWIGRUNTIME PySwigObject * +SWIG_Python_GetSwigThis(PyObject *pyobj) +{ + if (PySwigObject_Check(pyobj)) { + return (PySwigObject *) pyobj; + } else { + PyObject *obj = 0; +#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) + if (PyInstance_Check(pyobj)) { + obj = _PyInstance_Lookup(pyobj, SWIG_This()); + } else { + PyObject **dictptr = _PyObject_GetDictPtr(pyobj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; + } else { +#ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); + return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; + } +#endif + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } + } + } +#else + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } +#endif + if (obj && !PySwigObject_Check(obj)) { + /* a PyObject is called 'this', try to get the 'real this' + PySwigObject from it */ + return SWIG_Python_GetSwigThis(obj); + } + return (PySwigObject *)obj; + } +} + +/* Acquire a pointer value */ + +SWIGRUNTIME int +SWIG_Python_AcquirePtr(PyObject *obj, int own) { + if (own == SWIG_POINTER_OWN) { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (sobj) { + int oldown = sobj->own; + sobj->own = own; + return oldown; + } + } + return 0; +} + +/* Convert a pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { + if (!obj) return SWIG_ERROR; + if (obj == Py_None) { + if (ptr) *ptr = 0; + return SWIG_OK; + } else { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (own) + *own = 0; + while (sobj) { + void *vptr = sobj->ptr; + if (ty) { + swig_type_info *to = sobj->ty; + if (to == ty) { + /* no type cast needed */ + if (ptr) *ptr = vptr; + break; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) { + sobj = (PySwigObject *)sobj->next; + } else { + if (ptr) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + } + break; + } + } + } else { + if (ptr) *ptr = vptr; + break; + } + } + if (sobj) { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + return SWIG_OK; + } else { + int res = SWIG_ERROR; + if (flags & SWIG_POINTER_IMPLICIT_CONV) { + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + if (data && !data->implicitconv) { + PyObject *klass = data->klass; + if (klass) { + PyObject *impconv; + data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ + impconv = SWIG_Python_CallFunctor(klass, obj); + data->implicitconv = 0; + if (PyErr_Occurred()) { + PyErr_Clear(); + impconv = 0; + } + if (impconv) { + PySwigObject *iobj = SWIG_Python_GetSwigThis(impconv); + if (iobj) { + void *vptr; + res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); + if (SWIG_IsOK(res)) { + if (ptr) { + *ptr = vptr; + /* transfer the ownership to 'ptr' */ + iobj->own = 0; + res = SWIG_AddCast(res); + res = SWIG_AddNewMask(res); + } else { + res = SWIG_AddCast(res); + } + } + } + Py_DECREF(impconv); + } + } + } + } + return res; + } + } +} + +/* Convert a function ptr value */ + +SWIGRUNTIME int +SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { + if (!PyCFunction_Check(obj)) { + return SWIG_ConvertPtr(obj, ptr, ty, 0); + } else { + void *vptr = 0; + + /* here we get the method pointer for callbacks */ + const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); + const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; + if (desc) { + desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; + if (!desc) return SWIG_ERROR; + } + if (ty) { + swig_cast_info *tc = SWIG_TypeCheck(desc,ty); + if (tc) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } else { + return SWIG_ERROR; + } + } else { + *ptr = vptr; + } + return SWIG_OK; + } +} + +/* Convert a packed value value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = PySwigPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Create a new pointer object + * ----------------------------------------------------------------------------- */ + +/* + Create a new instance object, whitout calling __init__, and set the + 'this' attribute. +*/ + +SWIGRUNTIME PyObject* +SWIG_Python_NewShadowInstance(PySwigClientData *data, PyObject *swig_this) +{ +#if (PY_VERSION_HEX >= 0x02020000) + PyObject *inst = 0; + PyObject *newraw = data->newraw; + if (newraw) { + inst = PyObject_Call(newraw, data->newargs, NULL); + if (inst) { +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + PyDict_SetItem(dict, SWIG_This(), swig_this); + } + } +#else + PyObject *key = SWIG_This(); + PyObject_SetAttr(inst, key, swig_this); +#endif + } + } else { + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + } + return inst; +#else +#if (PY_VERSION_HEX >= 0x02010000) + PyObject *inst; + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + return (PyObject *) inst; +#else + PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); + if (inst == NULL) { + return NULL; + } + inst->in_class = (PyClassObject *)data->newargs; + Py_INCREF(inst->in_class); + inst->in_dict = PyDict_New(); + if (inst->in_dict == NULL) { + Py_DECREF(inst); + return NULL; + } +#ifdef Py_TPFLAGS_HAVE_WEAKREFS + inst->in_weakreflist = NULL; +#endif +#ifdef Py_TPFLAGS_GC + PyObject_GC_Init(inst); +#endif + PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); + return (PyObject *) inst; +#endif +#endif +} + +SWIGRUNTIME void +SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) +{ + PyObject *dict; +#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + } + PyDict_SetItem(dict, SWIG_This(), swig_this); + return; + } +#endif + dict = PyObject_GetAttrString(inst, (char*)"__dict__"); + PyDict_SetItem(dict, SWIG_This(), swig_this); + Py_DECREF(dict); +} + + +SWIGINTERN PyObject * +SWIG_Python_InitShadowInstance(PyObject *args) { + PyObject *obj[2]; + if (!SWIG_Python_UnpackTuple(args,(char*)"swiginit", 2, 2, obj)) { + return NULL; + } else { + PySwigObject *sthis = SWIG_Python_GetSwigThis(obj[0]); + if (sthis) { + PySwigObject_append((PyObject*) sthis, obj[1]); + } else { + SWIG_Python_SetSwigThis(obj[0], obj[1]); + } + return SWIG_Py_Void(); + } +} + +/* Create a new pointer object */ + +SWIGRUNTIME PyObject * +SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int flags) { + if (!ptr) { + return SWIG_Py_Void(); + } else { + int own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; + PyObject *robj = PySwigObject_New(ptr, type, own); + PySwigClientData *clientdata = type ? (PySwigClientData *)(type->clientdata) : 0; + if (clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { + PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); + if (inst) { + Py_DECREF(robj); + robj = inst; + } + } + return robj; + } +} + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? PySwigPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_LINK_RUNTIME +void *SWIG_ReturnGlobalTypeList(void *); +#endif + +SWIGRUNTIME swig_module_info * +SWIG_Python_GetModule(void) { + static void *type_pointer = (void *)0; + /* first check if module already created */ + if (!type_pointer) { +#ifdef SWIG_LINK_RUNTIME + type_pointer = SWIG_ReturnGlobalTypeList((void *)0); +#else + type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); + if (PyErr_Occurred()) { + PyErr_Clear(); + type_pointer = (void *)0; + } +#endif + } + return (swig_module_info *) type_pointer; +} + +#if PY_MAJOR_VERSION < 2 +/* PyModule_AddObject function was introduced in Python 2.0. The following function + is copied out of Python/modsupport.c in python version 2.3.4 */ +SWIGINTERN int +PyModule_AddObject(PyObject *m, char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs module as first arg"); + return SWIG_ERROR; + } + if (!o) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs non-NULL value"); + return SWIG_ERROR; + } + + dict = PyModule_GetDict(m); + if (dict == NULL) { + /* Internal error -- modules must have a dict! */ + PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", + PyModule_GetName(m)); + return SWIG_ERROR; + } + if (PyDict_SetItemString(dict, name, o)) + return SWIG_ERROR; + Py_DECREF(o); + return SWIG_OK; +} +#endif + +SWIGRUNTIME void +SWIG_Python_DestroyModule(void *vptr) +{ + swig_module_info *swig_module = (swig_module_info *) vptr; + swig_type_info **types = swig_module->types; + size_t i; + for (i =0; i < swig_module->size; ++i) { + swig_type_info *ty = types[i]; + if (ty->owndata) { + PySwigClientData *data = (PySwigClientData *) ty->clientdata; + if (data) PySwigClientData_Del(data); + } + } + Py_DECREF(SWIG_This()); +} + +SWIGRUNTIME void +SWIG_Python_SetModule(swig_module_info *swig_module) { + static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} };/* Sentinel */ + + PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + swig_empty_runtime_method_table); + PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +} + +/* The python cached type query */ +SWIGRUNTIME PyObject * +SWIG_Python_TypeCache(void) { + static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); + return cache; +} + +SWIGRUNTIME swig_type_info * +SWIG_Python_TypeQuery(const char *type) +{ + PyObject *cache = SWIG_Python_TypeCache(); + PyObject *key = PyString_FromString(type); + PyObject *obj = PyDict_GetItem(cache, key); + swig_type_info *descriptor; + if (obj) { + descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); + } else { + swig_module_info *swig_module = SWIG_Python_GetModule(); + descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); + if (descriptor) { + obj = PyCObject_FromVoidPtr(descriptor, NULL); + PyDict_SetItem(cache, key, obj); + Py_DECREF(obj); + } + } + Py_DECREF(key); + return descriptor; +} + +/* + For backward compatibility only +*/ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) +#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) + +SWIGRUNTIME int +SWIG_Python_AddErrMesg(const char* mesg, int infront) +{ + if (PyErr_Occurred()) { + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + Py_XINCREF(type); + PyErr_Clear(); + if (infront) { + PyErr_Format(type, "%s %s", mesg, PyString_AsString(old_str)); + } else { + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + } + Py_DECREF(old_str); + } + return 1; + } else { + return 0; + } +} + +SWIGRUNTIME int +SWIG_Python_ArgFail(int argnum) +{ + if (PyErr_Occurred()) { + /* add information about failing argument */ + char mesg[256]; + PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); + return SWIG_Python_AddErrMesg(mesg, 1); + } else { + return 0; + } +} + +SWIGRUNTIMEINLINE const char * +PySwigObject_GetDesc(PyObject *self) +{ + PySwigObject *v = (PySwigObject *)self; + swig_type_info *ty = v ? v->ty : 0; + return ty ? ty->str : (char*)""; +} + +SWIGRUNTIME void +SWIG_Python_TypeError(const char *type, PyObject *obj) +{ + if (type) { +#if defined(SWIG_COBJECT_TYPES) + if (obj && PySwigObject_Check(obj)) { + const char *otype = (const char *) PySwigObject_GetDesc(obj); + if (otype) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'PySwigObject(%s)' is received", + type, otype); + return; + } + } else +#endif + { + const char *otype = (obj ? obj->ob_type->tp_name : 0); + if (otype) { + PyObject *str = PyObject_Str(obj); + const char *cstr = str ? PyString_AsString(str) : 0; + if (cstr) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", + type, otype, cstr); + } else { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", + type, otype); + } + Py_XDECREF(str); + return; + } + } + PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); + } else { + PyErr_Format(PyExc_TypeError, "unexpected type is received"); + } +} + + +/* Convert a pointer value, signal an exception on a type mismatch */ +SWIGRUNTIME void * +SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) { + void *result; + if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { + PyErr_Clear(); + if (flags & SWIG_POINTER_EXCEPTION) { + SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); + SWIG_Python_ArgFail(argnum); + } + } + return result; +} + + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + + #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_TALLOC_CTX swig_types[0] +#define SWIGTYPE_p_char swig_types[1] +#define SWIGTYPE_p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void swig_types[2] +#define SWIGTYPE_p_int swig_types[3] +#define SWIGTYPE_p_ldb_context swig_types[4] +#define SWIGTYPE_p_ldb_dn swig_types[5] +#define SWIGTYPE_p_ldb_ldif swig_types[6] +#define SWIGTYPE_p_ldb_message swig_types[7] +#define SWIGTYPE_p_ldb_message_element swig_types[8] +#define SWIGTYPE_p_ldb_module_ops swig_types[9] +#define SWIGTYPE_p_ldb_result swig_types[10] +#define SWIGTYPE_p_ldb_val swig_types[11] +#define SWIGTYPE_p_long_long swig_types[12] +#define SWIGTYPE_p_p_char swig_types[13] +#define SWIGTYPE_p_p_ldb_control swig_types[14] +#define SWIGTYPE_p_p_ldb_result swig_types[15] +#define SWIGTYPE_p_short swig_types[16] +#define SWIGTYPE_p_signed_char swig_types[17] +#define SWIGTYPE_p_unsigned_char swig_types[18] +#define SWIGTYPE_p_unsigned_int swig_types[19] +#define SWIGTYPE_p_unsigned_long swig_types[20] +#define SWIGTYPE_p_unsigned_long_long swig_types[21] +#define SWIGTYPE_p_unsigned_short swig_types[22] +#define SWIGTYPE_p_void swig_types[23] +static swig_type_info *swig_types[25]; +static swig_module_info swig_module = {swig_types, 24, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#if (PY_VERSION_HEX <= 0x02000000) +# if !defined(SWIG_PYTHON_CLASSIC) +# error "This python version requires swig to be run with the '-classic' option" +# endif +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodern' option" +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodernargs' option" +#endif +#ifndef METH_O +# error "This python version requires swig to be run with the '-nofastunpack' option" +#endif +#ifdef SWIG_TypeQuery +# undef SWIG_TypeQuery +#endif +#define SWIG_TypeQuery SWIG_Python_TypeQuery + +/*----------------------------------------------- + @(target):= _ldb.so + ------------------------------------------------*/ +#define SWIG_init init_ldb + +#define SWIG_name "_ldb" + +#define SWIGVERSION 0x010335 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + + +#include +#include +#include "talloc.h" +#include "events.h" +#include "ldb.h" +#include "ldb_errors.h" +#include "ldb_private.h" + +typedef struct ldb_message ldb_msg; +typedef struct ldb_context ldb; +typedef struct ldb_dn ldb_dn; +typedef struct ldb_ldif ldb_ldif; +typedef struct ldb_message_element ldb_message_element; +typedef int ldb_error; +typedef int ldb_int_error; + + + + #define SWIG_From_long PyInt_FromLong + + +SWIGINTERNINLINE PyObject * +SWIG_From_int (int value) +{ + return SWIG_From_long (value); +} + + +PyObject *ldb_val_to_py_object(struct ldb_context *ldb_ctx, + struct ldb_message_element *el, + struct ldb_val *val) +{ + const struct ldb_schema_attribute *a; + struct ldb_val new_val; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + PyObject *ret; + + new_val = *val; + + if (ldb_ctx != NULL) { + a = ldb_schema_attribute_by_name(ldb_ctx, el->name); + + if (a != NULL) { + if (a->syntax->ldif_write_fn(ldb_ctx, mem_ctx, val, &new_val) != 0) { + talloc_free(mem_ctx); + return NULL; + } + } + } + + ret = PyString_FromStringAndSize((const char *)new_val.data, new_val.length); + + talloc_free(mem_ctx); + + return ret; +} + + + +SWIGINTERN swig_type_info* +SWIG_pchar_descriptor(void) +{ + static int init = 0; + static swig_type_info* info = 0; + if (!init) { + info = SWIG_TypeQuery("_p_char"); + init = 1; + } + return info; +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) +{ + if (PyString_Check(obj)) { + char *cstr; Py_ssize_t len; + PyString_AsStringAndSize(obj, &cstr, &len); + if (cptr) { + if (alloc) { + /* + In python the user should not be able to modify the inner + string representation. To warranty that, if you define + SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string + buffer is always returned. + + The default behavior is just to return the pointer value, + so, be careful. + */ +#if defined(SWIG_PYTHON_SAFE_CSTRINGS) + if (*alloc != SWIG_OLDOBJ) +#else + if (*alloc == SWIG_NEWOBJ) +#endif + { + *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + *cptr = PyString_AsString(obj); + } + } + if (psize) *psize = len + 1; + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + void* vptr = 0; + if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = (char *) vptr; + if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + +SWIGINTERN ldb_dn *new_ldb_dn(ldb *ldb_ctx,char const *str){ + ldb_dn *ret = ldb_dn_new(ldb_ctx, ldb_ctx, str); + /* ldb_dn_new() doesn't accept NULL as memory context, so + we do it this way... */ + talloc_steal(NULL, ret); + + if (ret == NULL) + SWIG_exception(SWIG_ValueError, + "unable to parse dn string"); +fail: + return ret; + } +SWIGINTERN void delete_ldb_dn(ldb_dn *self){ talloc_free(self); } + +SWIGINTERNINLINE PyObject* + SWIG_From_bool (bool value) +{ + return PyBool_FromLong(value ? 1 : 0); +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + if (carray) { + if (size > INT_MAX) { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + return pchar_descriptor ? + SWIG_NewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void(); + } else { + return PyString_FromStringAndSize(carray, (int)(size)); + } + } else { + return SWIG_Py_Void(); + } +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtr(const char *cptr) +{ + return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); +} + +SWIGINTERN ldb_dn *ldb_dn_parent(ldb_dn *self){ return ldb_dn_get_parent(NULL, self); } +SWIGINTERN char const *ldb_dn_canonical_str(ldb_dn *self){ + return ldb_dn_canonical_string(self, self); + } +SWIGINTERN char const *ldb_dn_canonical_ex_str(ldb_dn *self){ + return ldb_dn_canonical_ex_string(self, self); + } +SWIGINTERN char *ldb_dn___repr__(ldb_dn *self){ + char *dn = ldb_dn_get_linearized(self), *ret; + asprintf(&ret, "Dn('%s')", dn); + talloc_free(dn); + return ret; + } +SWIGINTERN ldb_dn *ldb_dn___add__(ldb_dn *self,ldb_dn *other){ + ldb_dn *ret = ldb_dn_copy(NULL, self); + ldb_dn_add_child(ret, other); + return ret; + } + +struct ldb_context *ldb_context_from_py_object(PyObject *py_obj) +{ + struct ldb_context *ldb_ctx; + if (SWIG_ConvertPtr(py_obj, (void *)&ldb_ctx, SWIGTYPE_p_ldb_context, 0 | 0 ) < 0) + return NULL; + return ldb_ctx; +} + +int ldb_dn_from_pyobject(TALLOC_CTX *mem_ctx, PyObject *object, + struct ldb_context *ldb_ctx, ldb_dn **dn) +{ + int ret; + struct ldb_dn *odn; + if (ldb_ctx != NULL && PyString_Check(object)) { + odn = ldb_dn_new(mem_ctx, ldb_ctx, PyString_AsString(object)); + if (!odn) { + return SWIG_ERROR; + } + *dn = odn; + return 0; + } + ret = SWIG_ConvertPtr(object, (void **)&odn, SWIGTYPE_p_ldb_dn, + SWIG_POINTER_EXCEPTION); + *dn = ldb_dn_copy(mem_ctx, odn); + if (odn && !*dn) { + return SWIG_ERROR; + } + return ret; +} + +ldb_message_element *ldb_msg_element_from_pyobject(TALLOC_CTX *mem_ctx, + PyObject *set_obj, int flags, + const char *attr_name) +{ + struct ldb_message_element *me = talloc(mem_ctx, struct ldb_message_element); + me->name = attr_name; + me->flags = flags; + if (PyString_Check(set_obj)) { + me->num_values = 1; + me->values = talloc_array(me, struct ldb_val, me->num_values); + me->values[0].length = PyString_Size(set_obj); + me->values[0].data = (uint8_t *)talloc_strdup(me->values, + PyString_AsString(set_obj)); + } else if (PySequence_Check(set_obj)) { + int i; + me->num_values = PySequence_Size(set_obj); + me->values = talloc_array(me, struct ldb_val, me->num_values); + for (i = 0; i < me->num_values; i++) { + PyObject *obj = PySequence_GetItem(set_obj, i); + me->values[i].length = PyString_Size(obj); + me->values[i].data = (uint8_t *)PyString_AsString(obj); + } + } else { + talloc_free(me); + me = NULL; + } + + return me; +} + +PyObject *ldb_msg_element_to_set(struct ldb_context *ldb_ctx, + ldb_message_element *me) +{ + int i; + PyObject *result; + + /* Python << 2.5 doesn't have PySet_New and PySet_Add. */ + result = PyList_New(me->num_values); + + for (i = 0; i < me->num_values; i++) { + PyList_SetItem(result, i, + ldb_val_to_py_object(ldb_ctx, me, &me->values[i])); + } + + return result; +} + + +SWIGINTERN int ldb_message_element___cmp__(ldb_message_element *self,ldb_message_element *other){ + return ldb_msg_element_compare(self, other); + } +SWIGINTERN PyObject *ldb_message_element___iter__(ldb_message_element *self){ + return PyObject_GetIter(ldb_msg_element_to_set(NULL, self)); + } +SWIGINTERN PyObject *ldb_message_element___set__(ldb_message_element *self){ + return ldb_msg_element_to_set(NULL, self); + } + +#include +#if !defined(SWIG_NO_LLONG_MAX) +# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) +# define LLONG_MAX __LONG_LONG_MAX__ +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +# endif +#endif + + +SWIGINTERN int +SWIG_AsVal_double (PyObject *obj, double *val) +{ + int res = SWIG_TypeError; + if (PyFloat_Check(obj)) { + if (val) *val = PyFloat_AsDouble(obj); + return SWIG_OK; + } else if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + double v = PyLong_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + double d = PyFloat_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = d; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); + } else { + PyErr_Clear(); + } + } + } +#endif + return res; +} + + +#include + + +#include + + +SWIGINTERNINLINE int +SWIG_CanCastAsInteger(double *d, double min, double max) { + double x = *d; + if ((min <= x && x <= max)) { + double fx = floor(x); + double cx = ceil(x); + double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ + if ((errno == EDOM) || (errno == ERANGE)) { + errno = 0; + } else { + double summ, reps, diff; + if (rd < x) { + diff = x - rd; + } else if (rd > x) { + diff = rd - x; + } else { + return 1; + } + summ = rd + x; + reps = diff/summ; + if (reps < 8*DBL_EPSILON) { + *d = rd; + return 1; + } + } + } + return 0; +} + + +SWIGINTERN int +SWIG_AsVal_long (PyObject *obj, long* val) +{ + if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + long v = PyInt_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { + if (val) *val = (long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_int (PyObject * obj, int *val) +{ + long v; + int res = SWIG_AsVal_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v < INT_MIN || v > INT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (int)(v); + } + } + return res; +} + +SWIGINTERN ldb_message_element *new_ldb_message_element(PyObject *set_obj,int flags,char const *name){ + return ldb_msg_element_from_pyobject(NULL, set_obj, flags, name); + } +SWIGINTERN int ldb_message_element___len__(ldb_message_element *self){ + return self->num_values; + } +SWIGINTERN PyObject *ldb_message_element_get(ldb_message_element *self,int i){ + if (i < 0 || i >= self->num_values) + return Py_None; + + return ldb_val_to_py_object(NULL, self, &self->values[i]); + } +SWIGINTERN void delete_ldb_message_element(ldb_message_element *self){ talloc_free(self); } + + PyObject *ldb_msg_list_elements(ldb_msg *msg) + { + int i, j = 0; + PyObject *obj = PyList_New(msg->num_elements+(msg->dn != NULL?1:0)); + if (msg->dn != NULL) { + PyList_SetItem(obj, j, PyString_FromString("dn")); + j++; + } + for (i = 0; i < msg->num_elements; i++) { + PyList_SetItem(obj, j, PyString_FromString(msg->elements[i].name)); + j++; + } + return obj; + } + +SWIGINTERN ldb_msg *new_ldb_msg(ldb_dn *dn){ + ldb_msg *ret = ldb_msg_new(NULL); + ret->dn = talloc_reference(ret, dn); + return ret; + } +SWIGINTERN void delete_ldb_msg(ldb_msg *self){ talloc_free(self); } +SWIGINTERN void ldb_msg___setitem____SWIG_0(ldb_msg *self,char const *attr_name,ldb_message_element *val){ + struct ldb_message_element *el; + + ldb_msg_remove_attr(self, attr_name); + + el = talloc(self, struct ldb_message_element); + el->name = talloc_strdup(el, attr_name); + el->num_values = val->num_values; + el->values = talloc_reference(el, val->values); + + ldb_msg_add(self, el, val->flags); + } +SWIGINTERN void ldb_msg___setitem____SWIG_1(ldb_msg *self,char const *attr_name,PyObject *val){ + struct ldb_message_element *el = ldb_msg_element_from_pyobject(NULL, + val, 0, attr_name); + talloc_steal(self, el); + ldb_msg_remove_attr(self, attr_name); + ldb_msg_add(self, el, el->flags); + } +SWIGINTERN unsigned int ldb_msg___len__(ldb_msg *self){ return self->num_elements; } + +SWIGINTERNINLINE PyObject* +SWIG_From_unsigned_SS_long (unsigned long value) +{ + return (value > LONG_MAX) ? + PyLong_FromUnsignedLong(value) : PyInt_FromLong((long)(value)); +} + + +SWIGINTERNINLINE PyObject * +SWIG_From_unsigned_SS_int (unsigned int value) +{ + return SWIG_From_unsigned_SS_long (value); +} + +SWIGINTERN PyObject *ldb_msg_keys(ldb_msg *self){ + return ldb_msg_list_elements(self); + } +SWIGINTERN PyObject *ldb_msg___iter__(ldb_msg *self){ + return PyObject_GetIter(ldb_msg_list_elements(self)); + } + +static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3, 0); + +static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) +{ + char *text; + PyObject *fn = context; + + vasprintf(&text, fmt, ap); + PyObject_CallFunction(fn, (char *)"(i,s)", level, text); + free(text); +} + + + static PyObject *ldb_ldif_to_pyobject(ldb_ldif *ldif) + { + if (ldif == NULL) { + return Py_None; + } else { + return Py_BuildValue((char *)"(iO)", ldif->changetype, + SWIG_NewPointerObj(ldif->msg, SWIGTYPE_p_ldb_message, 0)); + } + } + + +PyObject *PyExc_LdbError; + +SWIGINTERN ldb *new_ldb(){ + return ldb_init(NULL, event_context_init(NULL)); + } + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_long (PyObject *obj, unsigned long *val) +{ + if (PyInt_Check(obj)) { + long v = PyInt_AsLong(obj); + if (v >= 0) { + if (val) *val = v; + return SWIG_OK; + } else { + return SWIG_OverflowError; + } + } else if (PyLong_Check(obj)) { + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { + if (val) *val = (unsigned long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_int (PyObject * obj, unsigned int *val) +{ + unsigned long v; + int res = SWIG_AsVal_unsigned_SS_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v > UINT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (unsigned int)(v); + } + } + return res; +} + +SWIGINTERN void delete_ldb(ldb *self){ talloc_free(self); } +SWIGINTERN ldb_error ldb_search_ex(ldb *self,TALLOC_CTX *mem_ctx,ldb_dn *base,enum ldb_scope scope,char const *expression,char const *const *attrs,struct ldb_control **controls,struct ldb_result **OUT){ + int ret; + struct ldb_result *res; + struct ldb_request *req; + res = talloc_zero(mem_ctx, struct ldb_result); + if (!res) { + return 1; + } + + ret = ldb_build_search_req(&req, self, mem_ctx, + base?base:ldb_get_default_basedn(self), + scope, + expression, + attrs, + controls, + res, + ldb_search_default_callback); + + if (ret != 0) { + talloc_free(res); + return ret; + } + + ldb_set_timeout(self, req, 0); /* use default timeout */ + + ret = ldb_request(self, req); + + if (ret == 0) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + + *OUT = res; + return ret; + } +SWIGINTERN PyObject *ldb_schema_format_value(ldb *self,char const *element_name,PyObject *val){ + const struct ldb_schema_attribute *a; + struct ldb_val old_val; + struct ldb_val new_val; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + PyObject *ret; + + old_val.data = PyString_AsString(val); + old_val.length = PyString_Size(val); + + a = ldb_schema_attribute_by_name(self, element_name); + + if (a == NULL) { + return Py_None; + } + + if (a->syntax->ldif_write_fn(self, mem_ctx, &old_val, &new_val) != 0) { + talloc_free(mem_ctx); + return Py_None; + } + + ret = PyString_FromStringAndSize((const char *)new_val.data, new_val.length); + + talloc_free(mem_ctx); + + return ret; + } +SWIGINTERN ldb_error ldb___contains__(ldb *self,ldb_dn *dn,struct ldb_result **result_as_bool){ + return ldb_search(self, dn, LDB_SCOPE_BASE, NULL, NULL, + result_as_bool); + } +SWIGINTERN PyObject *ldb_parse_ldif(ldb *self,char const *s){ + PyObject *list = PyList_New(0); + struct ldb_ldif *ldif; + while ((ldif = ldb_ldif_read_string(self, &s)) != NULL) { + PyList_Append(list, ldb_ldif_to_pyobject(ldif)); + } + return PyObject_GetIter(list); + } +SWIGINTERN char *ldb___repr__(ldb *self){ + char *ret; + asprintf(&ret, "", ret); + return ret; + } + +static char *timestring(time_t t) +{ + char *tresult = ldb_timestring(NULL, t); + char *result = strdup(tresult); + talloc_free(tresult); + return result; +} + +#ifdef __cplusplus +extern "C" { +#endif +SWIGINTERN PyObject *_wrap_ldb_val_to_py_object(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct ldb_message_element *arg2 = (struct ldb_message_element *) 0 ; + struct ldb_val *arg3 = (struct ldb_val *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "ldb_ctx",(char *) "el",(char *) "val", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:ldb_val_to_py_object",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_val_to_py_object" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ldb_message_element, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ldb_val_to_py_object" "', argument " "2"" of type '" "struct ldb_message_element *""'"); + } + arg2 = (struct ldb_message_element *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_ldb_val, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "ldb_val_to_py_object" "', argument " "3"" of type '" "struct ldb_val *""'"); + } + arg3 = (struct ldb_val *)(argp3); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (PyObject *)ldb_val_to_py_object(arg1,arg2,arg3); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_new_Dn(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + ldb_dn *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb_ctx",(char *) "str", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:new_Dn",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Dn" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Dn" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (ldb_dn *)new_ldb_dn(arg1,(char const *)arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_dn, SWIG_POINTER_NEW | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_delete_Dn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Dn" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + delete_ldb_dn(arg1); + + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_validate(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + bool result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_validate" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (bool)ldb_dn_validate(arg1); + resultobj = SWIG_From_bool((bool)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_get_casefold(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_get_casefold" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (char *)ldb_dn_get_casefold(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn___str__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn___str__" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (char *)ldb_dn_get_linearized(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_parent(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + ldb_dn *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_parent" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (ldb_dn *)ldb_dn_parent(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_dn, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn___cmp__(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + ldb_dn *arg2 = (ldb_dn *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "other", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn___cmp__",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn___cmp__" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dn___cmp__" "', argument " "2"" of type '" "ldb_dn *""'"); + } + arg2 = (ldb_dn *)(argp2); + result = (int)ldb_dn_compare(arg1,arg2); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_is_valid(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + bool result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_is_valid" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (bool)ldb_dn_is_valid(arg1); + resultobj = SWIG_From_bool((bool)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_is_special(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + bool result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_is_special" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (bool)ldb_dn_is_special(arg1); + resultobj = SWIG_From_bool((bool)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_is_null(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + bool result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_is_null" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (bool)ldb_dn_is_null(arg1); + resultobj = SWIG_From_bool((bool)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_check_special(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + char *arg2 = (char *) 0 ; + bool result; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "name", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn_check_special",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_check_special" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dn_check_special" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = (bool)ldb_dn_check_special(arg1,(char const *)arg2); + resultobj = SWIG_From_bool((bool)(result)); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn___len__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn___len__" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (int)ldb_dn_get_comp_num(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_add_child(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + ldb_dn *arg2 = (ldb_dn *) 0 ; + bool result; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "child", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn_add_child",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_add_child" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dn_add_child" "', argument " "2"" of type '" "ldb_dn *""'"); + } + arg2 = (ldb_dn *)(argp2); + result = (bool)ldb_dn_add_child(arg1,arg2); + resultobj = SWIG_From_bool((bool)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_add_base(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + ldb_dn *arg2 = (ldb_dn *) 0 ; + bool result; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "base", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn_add_base",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_add_base" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dn_add_base" "', argument " "2"" of type '" "ldb_dn *""'"); + } + arg2 = (ldb_dn *)(argp2); + result = (bool)ldb_dn_add_base(arg1,arg2); + resultobj = SWIG_From_bool((bool)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_canonical_str(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_canonical_str" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (char *)ldb_dn_canonical_str(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn_canonical_ex_str(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn_canonical_ex_str" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (char *)ldb_dn_canonical_ex_str(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn___repr__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn___repr__" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + result = (char *)ldb_dn___repr__(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Dn___add__(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) 0 ; + ldb_dn *arg2 = (ldb_dn *) 0 ; + ldb_dn *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "other", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn___add__",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dn___add__" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dn___add__" "', argument " "2"" of type '" "ldb_dn *""'"); + } + arg2 = (ldb_dn *)(argp2); + result = (ldb_dn *)ldb_dn___add__(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_dn, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *Dn_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_ldb_dn, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject *Dn_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + return SWIG_Python_InitShadowInstance(args); +} + +SWIGINTERN PyObject *_wrap_MessageElement___cmp__(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_message_element *arg1 = (ldb_message_element *) 0 ; + ldb_message_element *arg2 = (ldb_message_element *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "other", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:MessageElement___cmp__",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message_element, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MessageElement___cmp__" "', argument " "1"" of type '" "ldb_message_element *""'"); + } + arg1 = (ldb_message_element *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ldb_message_element, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "MessageElement___cmp__" "', argument " "2"" of type '" "ldb_message_element *""'"); + } + arg2 = (ldb_message_element *)(argp2); + result = (int)ldb_message_element___cmp__(arg1,arg2); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_MessageElement___iter__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_message_element *arg1 = (ldb_message_element *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message_element, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MessageElement___iter__" "', argument " "1"" of type '" "ldb_message_element *""'"); + } + arg1 = (ldb_message_element *)(argp1); + result = (PyObject *)ldb_message_element___iter__(arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_MessageElement___set__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_message_element *arg1 = (ldb_message_element *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message_element, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MessageElement___set__" "', argument " "1"" of type '" "ldb_message_element *""'"); + } + arg1 = (ldb_message_element *)(argp1); + result = (PyObject *)ldb_message_element___set__(arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_new_MessageElement(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + int arg2 = (int) 0 ; + char *arg3 = (char *) NULL ; + ldb_message_element *result = 0 ; + int val2 ; + int ecode2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "set_obj",(char *) "flags",(char *) "name", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OO:new_MessageElement",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + arg1 = obj0; + if (obj1) { + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_MessageElement" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + } + if (obj2) { + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "new_MessageElement" "', argument " "3"" of type '" "char const *""'"); + } + arg3 = (char *)(buf3); + } + result = (ldb_message_element *)new_ldb_message_element(arg1,arg2,(char const *)arg3); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_message_element, SWIG_POINTER_NEW | 0 ); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_MessageElement___len__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_message_element *arg1 = (ldb_message_element *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message_element, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MessageElement___len__" "', argument " "1"" of type '" "ldb_message_element *""'"); + } + arg1 = (ldb_message_element *)(argp1); + result = (int)ldb_message_element___len__(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_MessageElement_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_message_element *arg1 = (ldb_message_element *) 0 ; + int arg2 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "i", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:MessageElement_get",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message_element, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MessageElement_get" "', argument " "1"" of type '" "ldb_message_element *""'"); + } + arg1 = (ldb_message_element *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "MessageElement_get" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (PyObject *)ldb_message_element_get(arg1,arg2); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_delete_MessageElement(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_message_element *arg1 = (ldb_message_element *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message_element, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_MessageElement" "', argument " "1"" of type '" "ldb_message_element *""'"); + } + arg1 = (ldb_message_element *)(argp1); + delete_ldb_message_element(arg1); + + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *MessageElement_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_ldb_message_element, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject *MessageElement_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + return SWIG_Python_InitShadowInstance(args); +} + +SWIGINTERN PyObject *_wrap_ldb_msg_list_elements(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "msg", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:ldb_msg_list_elements",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_msg_list_elements" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + result = (PyObject *)ldb_msg_list_elements(arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message_dn_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + ldb_dn *arg2 = (ldb_dn *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject *swig_obj[2] ; + + if (!SWIG_Python_UnpackTuple(args,"Message_dn_set",2,2,swig_obj)) SWIG_fail; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message_dn_set" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_ldb_dn, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Message_dn_set" "', argument " "2"" of type '" "ldb_dn *""'"); + } + arg2 = (ldb_dn *)(argp2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + if (arg1) (arg1)->dn = arg2; + + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message_dn_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + ldb_dn *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message_dn_get" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + result = (ldb_dn *) ((arg1)->dn); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_dn, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_new_Message(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_dn *arg1 = (ldb_dn *) NULL ; + ldb_msg *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "dn", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|O:new_Message",kwnames,&obj0)) SWIG_fail; + if (obj0) { + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Message" "', argument " "1"" of type '" "ldb_dn *""'"); + } + arg1 = (ldb_dn *)(argp1); + } + result = (ldb_msg *)new_ldb_msg(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_message, SWIG_POINTER_NEW | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_delete_Message(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Message" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + delete_ldb_msg(arg1); + + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message_find_element(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + char *arg2 = (char *) 0 ; + ldb_message_element *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "name", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Message_find_element",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message_find_element" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Message_find_element" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + result = (ldb_message_element *)ldb_msg_find_element(arg1,(char const *)arg2); + { + if (result == NULL) + PyErr_SetString(PyExc_KeyError, "no such element"); + else + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_ldb_message_element, 0); + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message___setitem____SWIG_0(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + char *arg2 = (char *) 0 ; + ldb_message_element *arg3 = (ldb_message_element *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + + if ((nobjs < 3) || (nobjs > 3)) SWIG_fail; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message___setitem__" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + res2 = SWIG_AsCharPtrAndSize(swig_obj[1], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Message___setitem__" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_ConvertPtr(swig_obj[2], &argp3,SWIGTYPE_p_ldb_message_element, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Message___setitem__" "', argument " "3"" of type '" "ldb_message_element *""'"); + } + arg3 = (ldb_message_element *)(argp3); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + ldb_msg___setitem____SWIG_0(arg1,(char const *)arg2,arg3); + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message___setitem____SWIG_1(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + char *arg2 = (char *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + + if ((nobjs < 3) || (nobjs > 3)) SWIG_fail; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message___setitem__" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + res2 = SWIG_AsCharPtrAndSize(swig_obj[1], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Message___setitem__" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + arg3 = swig_obj[2]; + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + ldb_msg___setitem____SWIG_1(arg1,(char const *)arg2,arg3); + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message___setitem__(PyObject *self, PyObject *args) { + int argc; + PyObject *argv[4]; + + if (!(argc = SWIG_Python_UnpackTuple(args,"Message___setitem__",0,3,argv))) SWIG_fail; + --argc; + if (argc == 3) { + int _v = 0; + { + void *vptr = 0; + int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_ldb_message_element, 0); + _v = SWIG_CheckState(res); + } + if (!_v) goto check_1; + return _wrap_Message___setitem____SWIG_0(self, argc, argv); + } +check_1: + + if (argc == 3) { + return _wrap_Message___setitem____SWIG_1(self, argc, argv); + } + +fail: + SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Message___setitem__'.\n" + " Possible C/C++ prototypes are:\n" + " __setitem__(ldb_msg *,char const *,ldb_message_element *)\n" + " __setitem__(ldb_msg *,char const *,PyObject *)\n"); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message___len__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + unsigned int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message___len__" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + result = (unsigned int)ldb_msg___len__(arg1); + resultobj = SWIG_From_unsigned_SS_int((unsigned int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message_keys(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message_keys" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + result = (PyObject *)ldb_msg_keys(arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message___iter__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message___iter__" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + result = (PyObject *)ldb_msg___iter__(arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Message___delitem__(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_msg *arg1 = (ldb_msg *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "name", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Message___delitem__",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Message___delitem__" "', argument " "1"" of type '" "ldb_msg *""'"); + } + arg1 = (ldb_msg *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Message___delitem__" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + ldb_msg_remove_attr(arg1,(char const *)arg2); + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *Message_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_ldb_message, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject *Message_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + return SWIG_Python_InitShadowInstance(args); +} + +SWIGINTERN PyObject *_wrap_ldb_ldif_to_pyobject(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb_ldif *arg1 = (ldb_ldif *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "ldif", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:ldb_ldif_to_pyobject",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_ldif, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_ldif_to_pyobject" "', argument " "1"" of type '" "ldb_ldif *""'"); + } + arg1 = (ldb_ldif *)(argp1); + result = (PyObject *)ldb_ldif_to_pyobject(arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_new_Ldb(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *result = 0 ; + + if (!SWIG_Python_UnpackTuple(args,"new_Ldb",0,0,0)) SWIG_fail; + result = (ldb *)new_ldb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_context, SWIG_POINTER_NEW | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_connect(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + unsigned int arg3 = (unsigned int) 0 ; + char **arg4 = (char **) (char **)NULL ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + unsigned int val3 ; + int ecode3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "url",(char *) "flags",(char *) "options", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|OO:Ldb_connect",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_connect" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_connect" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (obj2) { + ecode3 = SWIG_AsVal_unsigned_SS_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Ldb_connect" "', argument " "3"" of type '" "unsigned int""'"); + } + arg3 = (unsigned int)(val3); + } + if (obj3) { + res4 = SWIG_ConvertPtr(obj3, &argp4,SWIGTYPE_p_p_char, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Ldb_connect" "', argument " "4"" of type '" "char const *[]""'"); + } + arg4 = (char **)(argp4); + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_connect(arg1,(char const *)arg2,arg3,(char const *(*))arg4); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_delete_Ldb(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Ldb" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + delete_ldb(arg1); + + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_search_ex(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + TALLOC_CTX *arg2 = (TALLOC_CTX *) 0 ; + ldb_dn *arg3 = (ldb_dn *) NULL ; + enum ldb_scope arg4 = (enum ldb_scope) LDB_SCOPE_DEFAULT ; + char *arg5 = (char *) NULL ; + char **arg6 = (char **) NULL ; + struct ldb_control **arg7 = (struct ldb_control **) NULL ; + struct ldb_result **arg8 = (struct ldb_result **) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + int val4 ; + int ecode4 = 0 ; + int res5 ; + char *buf5 = 0 ; + int alloc5 = 0 ; + void *argp7 = 0 ; + int res7 = 0 ; + struct ldb_result *temp_ldb_result8 ; + int i8 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject * obj5 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "base",(char *) "scope",(char *) "expression",(char *) "attrs",(char *) "controls", NULL + }; + + arg2 = NULL; + arg8 = &temp_ldb_result8; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOOO:Ldb_search_ex",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_search_ex" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (obj1) { + if (ldb_dn_from_pyobject(NULL, obj1, arg1, &arg3) != 0) { + SWIG_fail; + } + } + if (obj2) { + ecode4 = SWIG_AsVal_int(obj2, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Ldb_search_ex" "', argument " "4"" of type '" "enum ldb_scope""'"); + } + arg4 = (enum ldb_scope)(val4); + } + if (obj3) { + res5 = SWIG_AsCharPtrAndSize(obj3, &buf5, NULL, &alloc5); + if (!SWIG_IsOK(res5)) { + SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "Ldb_search_ex" "', argument " "5"" of type '" "char const *""'"); + } + arg5 = (char *)(buf5); + } + if (obj4) { + if (obj4 == Py_None) { + arg6 = NULL; + } else if (PySequence_Check(obj4)) { + int i; + arg6 = talloc_array(NULL, char *, PySequence_Size(obj4)+1); + for(i = 0; i < PySequence_Size(obj4); i++) + arg6[i] = PyString_AsString(PySequence_GetItem(obj4, i)); + arg6[i] = NULL; + } else { + SWIG_exception(SWIG_TypeError, "expected sequence"); + } + } + if (obj5) { + res7 = SWIG_ConvertPtr(obj5, &argp7,SWIGTYPE_p_p_ldb_control, 0 | 0 ); + if (!SWIG_IsOK(res7)) { + SWIG_exception_fail(SWIG_ArgError(res7), "in method '" "Ldb_search_ex" "', argument " "7"" of type '" "struct ldb_control **""'"); + } + arg7 = (struct ldb_control **)(argp7); + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_search_ex(arg1,arg2,arg3,arg4,(char const *)arg5,(char const *const *)arg6,arg7,arg8); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + resultobj = PyList_New((*arg8)->count); + for (i8 = 0; i8 < (*arg8)->count; i8++) { + PyList_SetItem(resultobj, i8, + SWIG_NewPointerObj((*arg8)->msgs[i8], SWIGTYPE_p_ldb_message, 0) + ); + } + talloc_free(arg3); + if (alloc5 == SWIG_NEWOBJ) free((char*)buf5); + talloc_free(arg6); + return resultobj; +fail: + talloc_free(arg3); + if (alloc5 == SWIG_NEWOBJ) free((char*)buf5); + talloc_free(arg6); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_delete(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_dn *arg2 = (ldb_dn *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "dn", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_delete",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_delete" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (ldb_dn_from_pyobject(NULL, obj1, arg1, &arg2) != 0) { + SWIG_fail; + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_delete(arg1,arg2); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + talloc_free(arg2); + return resultobj; +fail: + talloc_free(arg2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_rename(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_dn *arg2 = (ldb_dn *) 0 ; + ldb_dn *arg3 = (ldb_dn *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "olddn",(char *) "newdn", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Ldb_rename",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_rename" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (ldb_dn_from_pyobject(NULL, obj1, arg1, &arg2) != 0) { + SWIG_fail; + } + if (ldb_dn_from_pyobject(NULL, obj2, arg1, &arg3) != 0) { + SWIG_fail; + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_rename(arg1,arg2,arg3); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + talloc_free(arg2); + talloc_free(arg3); + return resultobj; +fail: + talloc_free(arg2); + talloc_free(arg3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_parse_control_strings(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + TALLOC_CTX *arg2 = (TALLOC_CTX *) 0 ; + char **arg3 = (char **) 0 ; + struct ldb_control **result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "control_strings", NULL + }; + + arg2 = NULL; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_parse_control_strings",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_parse_control_strings" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (obj1 == Py_None) { + arg3 = NULL; + } else if (PySequence_Check(obj1)) { + int i; + arg3 = talloc_array(NULL, char *, PySequence_Size(obj1)+1); + for(i = 0; i < PySequence_Size(obj1); i++) + arg3[i] = PyString_AsString(PySequence_GetItem(obj1, i)); + arg3[i] = NULL; + } else { + SWIG_exception(SWIG_TypeError, "expected sequence"); + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (struct ldb_control **)ldb_parse_control_strings(arg1,arg2,(char const *const *)arg3); + if (result == NULL) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(s)", ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_p_ldb_control, 0); + talloc_free(arg3); + return resultobj; +fail: + talloc_free(arg3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_add(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_msg *arg2 = (ldb_msg *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "add_msg", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_add",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_add" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + { + Py_ssize_t dict_pos, msg_pos; + ldb_message_element *msgel; + PyObject *key, *value; + + if (PyDict_Check(obj1)) { + PyObject *dn_value = PyDict_GetItemString(obj1, "dn"); + arg2 = ldb_msg_new(NULL); + arg2->elements = talloc_zero_array(arg2, struct ldb_message_element, PyDict_Size(obj1)); + msg_pos = dict_pos = 0; + if (dn_value) { + /* using argp1 (magic SWIG value) here is a hack */ + if (ldb_dn_from_pyobject(arg2, dn_value, argp1, &arg2->dn) != 0) { + SWIG_exception(SWIG_TypeError, "unable to import dn object"); + } + if (arg2->dn == NULL) { + SWIG_exception(SWIG_TypeError, "dn set but not found"); + } + } + + while (PyDict_Next(obj1, &dict_pos, &key, &value)) { + char *key_str = PyString_AsString(key); + if (strcmp(key_str, "dn") != 0) { + msgel = ldb_msg_element_from_pyobject(arg2->elements, value, 0, key_str); + if (msgel == NULL) { + SWIG_exception(SWIG_TypeError, "unable to import element"); + } + memcpy(&arg2->elements[msg_pos], msgel, sizeof(*msgel)); + msg_pos++; + } + } + + if (arg2->dn == NULL) { + SWIG_exception(SWIG_TypeError, "no dn set"); + } + + arg2->num_elements = msg_pos; + } else { + if (SWIG_ConvertPtr(obj1, (void **)&arg2, SWIGTYPE_p_ldb_message, 0) != 0) { + SWIG_exception(SWIG_TypeError, "unable to convert ldb message"); + } + } + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + if (arg2 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + result = ldb_add(arg1,arg2); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_modify(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_msg *arg2 = (ldb_msg *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "message", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_modify",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_modify" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ldb_message, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_modify" "', argument " "2"" of type '" "ldb_msg *""'"); + } + arg2 = (ldb_msg *)(argp2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + if (arg2 == NULL) + SWIG_exception(SWIG_ValueError, + "Message can not be None"); + result = ldb_modify(arg1,arg2); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_get_config_basedn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_dn *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_get_config_basedn" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (ldb_dn *)ldb_get_config_basedn(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_dn, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_get_root_basedn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_dn *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_get_root_basedn" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (ldb_dn *)ldb_get_root_basedn(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_dn, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_get_schema_basedn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_dn *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_get_schema_basedn" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (ldb_dn *)ldb_get_schema_basedn(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_dn, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_get_default_basedn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_dn *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_get_default_basedn" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (ldb_dn *)ldb_get_default_basedn(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ldb_dn, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_schema_format_value(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "element_name",(char *) "val", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Ldb_schema_format_value",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_schema_format_value" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_schema_format_value" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + arg3 = obj2; + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (PyObject *)ldb_schema_format_value(arg1,(char const *)arg2,arg3); + resultobj = result; + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_errstring(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_errstring" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (char *)ldb_errstring(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_set_create_perms(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + unsigned int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + unsigned int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "perms", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_set_create_perms",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_set_create_perms" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + ecode2 = SWIG_AsVal_unsigned_SS_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Ldb_set_create_perms" "', argument " "2"" of type '" "unsigned int""'"); + } + arg2 = (unsigned int)(val2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + ldb_set_create_perms(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_set_modules_dir(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "path", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_set_modules_dir",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_set_modules_dir" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_set_modules_dir" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + ldb_set_modules_dir(arg1,(char const *)arg2); + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_set_debug(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + void (*arg2)(void *,enum ldb_debug_level,char const *,va_list) = (void (*)(void *,enum ldb_debug_level,char const *,va_list)) 0 ; + void *arg3 = (void *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "debug", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_set_debug",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_set_debug" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + arg2 = py_ldb_debug; + /* FIXME: Should be decreased somewhere as well. Perhaps register a + destructor and tie it to the ldb context ? */ + Py_INCREF(obj1); + arg3 = obj1; + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_set_debug(arg1,arg2,arg3); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_set_opaque(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + void *arg3 = (void *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "name",(char *) "value", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Ldb_set_opaque",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_set_opaque" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_set_opaque" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3), 0, 0); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Ldb_set_opaque" "', argument " "3"" of type '" "void *""'"); + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_set_opaque(arg1,(char const *)arg2,arg3); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_get_opaque(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + void *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "name", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_get_opaque",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_get_opaque" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_get_opaque" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (void *)ldb_get_opaque(arg1,(char const *)arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_transaction_start(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_transaction_start" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_transaction_start(arg1); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_transaction_commit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_transaction_commit" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_transaction_commit(arg1); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_transaction_cancel(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_transaction_cancel" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_transaction_cancel(arg1); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_schema_attribute_remove(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "name", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_schema_attribute_remove",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_schema_attribute_remove" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_schema_attribute_remove" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + ldb_schema_attribute_remove(arg1,(char const *)arg2); + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_schema_attribute_add(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + unsigned int arg3 ; + char *arg4 = (char *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + unsigned int val3 ; + int ecode3 = 0 ; + int res4 ; + char *buf4 = 0 ; + int alloc4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "attribute",(char *) "flags",(char *) "syntax", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOO:Ldb_schema_attribute_add",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_schema_attribute_add" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_schema_attribute_add" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_unsigned_SS_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Ldb_schema_attribute_add" "', argument " "3"" of type '" "unsigned int""'"); + } + arg3 = (unsigned int)(val3); + res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Ldb_schema_attribute_add" "', argument " "4"" of type '" "char const *""'"); + } + arg4 = (char *)(buf4); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_schema_attribute_add(arg1,(char const *)arg2,arg3,(char const *)arg4); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_setup_wellknown_attributes(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_setup_wellknown_attributes" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb_setup_wellknown_attributes(arg1); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb___contains__(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + ldb_dn *arg2 = (ldb_dn *) 0 ; + struct ldb_result **arg3 = (struct ldb_result **) 0 ; + ldb_error result; + void *argp1 = 0 ; + int res1 = 0 ; + struct ldb_result *tmp3 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "dn", NULL + }; + + arg3 = &tmp3; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb___contains__",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb___contains__" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (ldb_dn_from_pyobject(NULL, obj1, arg1, &arg2) != 0) { + SWIG_fail; + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = ldb___contains__(arg1,arg2,arg3); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_errstring(arg1))); + SWIG_fail; + } + resultobj = Py_None; + resultobj = ((*arg3)->count > 0)?Py_True:Py_False; + talloc_free(arg2); + talloc_free(*arg3); + return resultobj; +fail: + talloc_free(arg2); + talloc_free(*arg3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb_parse_ldif(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *arg2 = (char *) 0 ; + PyObject *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "s", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_parse_ldif",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_parse_ldif" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_parse_ldif" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (PyObject *)ldb_parse_ldif(arg1,(char const *)arg2); + resultobj = result; + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Ldb___repr__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ldb *arg1 = (ldb *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb___repr__" "', argument " "1"" of type '" "ldb *""'"); + } + arg1 = (ldb *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (char *)ldb___repr__(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *Ldb_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_ldb_context, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject *Ldb_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + return SWIG_Python_InitShadowInstance(args); +} + +SWIGINTERN PyObject *_wrap_valid_attr_name(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int result; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "s", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:valid_attr_name",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "valid_attr_name" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + result = (int)ldb_valid_attr_name((char const *)arg1); + resultobj = SWIG_From_int((int)(result)); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_timestring(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + time_t arg1 ; + char *result = 0 ; + unsigned long val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "t", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:timestring",kwnames,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_unsigned_SS_long(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "timestring" "', argument " "1"" of type '" "time_t""'"); + } + arg1 = (time_t)(val1); + result = (char *)timestring(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_string_to_time(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + time_t result; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "s", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:string_to_time",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "string_to_time" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + result = (time_t)ldb_string_to_time((char const *)arg1); + resultobj = SWIG_From_unsigned_SS_long((unsigned long)(result)); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_register_module(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_module_ops *arg1 = (struct ldb_module_ops *) 0 ; + ldb_int_error result; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *)"arg1", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:register_module",kwnames,&obj0)) SWIG_fail; + arg1 = talloc_zero(talloc_autofree_context(), struct ldb_module_ops); + + arg1->name = (char *)PyObject_GetAttrString(obj0, (char *)"name"); + result = ldb_register_module((struct ldb_module_ops const *)arg1); + if (result != 0) { + PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_strerror(result))); + SWIG_fail; + } + resultobj = Py_None; + return resultobj; +fail: + return NULL; +} + + +static PyMethodDef SwigMethods[] = { + { (char *)"ldb_val_to_py_object", (PyCFunction) _wrap_ldb_val_to_py_object, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"new_Dn", (PyCFunction) _wrap_new_Dn, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.__init__(ldb, string)\n" + "Create a new DN.\n" + ""}, + { (char *)"delete_Dn", (PyCFunction)_wrap_delete_Dn, METH_O, NULL}, + { (char *)"Dn_validate", (PyCFunction)_wrap_Dn_validate, METH_O, (char *)"\n" + "S.validate() -> bool\n" + "Validate DN is correct.\n" + ""}, + { (char *)"Dn_get_casefold", (PyCFunction)_wrap_Dn_get_casefold, METH_O, NULL}, + { (char *)"Dn___str__", (PyCFunction)_wrap_Dn___str__, METH_O, NULL}, + { (char *)"Dn_parent", (PyCFunction)_wrap_Dn_parent, METH_O, (char *)"\n" + "S.parent() -> dn\n" + "Get the parent for this DN.\n" + ""}, + { (char *)"Dn___cmp__", (PyCFunction) _wrap_Dn___cmp__, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Dn_is_valid", (PyCFunction)_wrap_Dn_is_valid, METH_O, NULL}, + { (char *)"Dn_is_special", (PyCFunction)_wrap_Dn_is_special, METH_O, (char *)"\n" + "S.is_special() -> bool\n" + "Check whether this is a special LDB DN.\n" + ""}, + { (char *)"Dn_is_null", (PyCFunction)_wrap_Dn_is_null, METH_O, (char *)"\n" + "S.is_null() -> bool\n" + "Check whether this is a null DN.\n" + ""}, + { (char *)"Dn_check_special", (PyCFunction) _wrap_Dn_check_special, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Dn___len__", (PyCFunction)_wrap_Dn___len__, METH_O, NULL}, + { (char *)"Dn_add_child", (PyCFunction) _wrap_Dn_add_child, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.add_child(dn) -> None\n" + "Add a child DN to this DN.\n" + ""}, + { (char *)"Dn_add_base", (PyCFunction) _wrap_Dn_add_base, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.add_base(dn) -> None\n" + "Add a base DN to this DN.\n" + ""}, + { (char *)"Dn_canonical_str", (PyCFunction)_wrap_Dn_canonical_str, METH_O, (char *)"\n" + "S.canonical_str() -> string\n" + "Canonical version of this DN (like a posix path).\n" + ""}, + { (char *)"Dn_canonical_ex_str", (PyCFunction)_wrap_Dn_canonical_ex_str, METH_O, (char *)"\n" + "S.canonical_ex_str() -> string\n" + "Canonical version of this DN (like a posix path, with terminating newline).\n" + ""}, + { (char *)"Dn___repr__", (PyCFunction)_wrap_Dn___repr__, METH_O, NULL}, + { (char *)"Dn___add__", (PyCFunction) _wrap_Dn___add__, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Dn_swigregister", Dn_swigregister, METH_VARARGS, NULL}, + { (char *)"Dn_swiginit", Dn_swiginit, METH_VARARGS, NULL}, + { (char *)"MessageElement___cmp__", (PyCFunction) _wrap_MessageElement___cmp__, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"MessageElement___iter__", (PyCFunction)_wrap_MessageElement___iter__, METH_O, NULL}, + { (char *)"MessageElement___set__", (PyCFunction)_wrap_MessageElement___set__, METH_O, NULL}, + { (char *)"new_MessageElement", (PyCFunction) _wrap_new_MessageElement, METH_VARARGS | METH_KEYWORDS, (char *)"Message element."}, + { (char *)"MessageElement___len__", (PyCFunction)_wrap_MessageElement___len__, METH_O, NULL}, + { (char *)"MessageElement_get", (PyCFunction) _wrap_MessageElement_get, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"delete_MessageElement", (PyCFunction)_wrap_delete_MessageElement, METH_O, NULL}, + { (char *)"MessageElement_swigregister", MessageElement_swigregister, METH_VARARGS, NULL}, + { (char *)"MessageElement_swiginit", MessageElement_swiginit, METH_VARARGS, NULL}, + { (char *)"ldb_msg_list_elements", (PyCFunction) _wrap_ldb_msg_list_elements, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Message_dn_set", _wrap_Message_dn_set, METH_VARARGS, NULL}, + { (char *)"Message_dn_get", (PyCFunction)_wrap_Message_dn_get, METH_O, NULL}, + { (char *)"new_Message", (PyCFunction) _wrap_new_Message, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"delete_Message", (PyCFunction)_wrap_delete_Message, METH_O, NULL}, + { (char *)"Message_find_element", (PyCFunction) _wrap_Message_find_element, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Message___setitem__", _wrap_Message___setitem__, METH_VARARGS, NULL}, + { (char *)"Message___len__", (PyCFunction)_wrap_Message___len__, METH_O, NULL}, + { (char *)"Message_keys", (PyCFunction)_wrap_Message_keys, METH_O, NULL}, + { (char *)"Message___iter__", (PyCFunction)_wrap_Message___iter__, METH_O, NULL}, + { (char *)"Message___delitem__", (PyCFunction) _wrap_Message___delitem__, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Message_swigregister", Message_swigregister, METH_VARARGS, NULL}, + { (char *)"Message_swiginit", Message_swiginit, METH_VARARGS, NULL}, + { (char *)"ldb_ldif_to_pyobject", (PyCFunction) _wrap_ldb_ldif_to_pyobject, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"new_Ldb", (PyCFunction)_wrap_new_Ldb, METH_NOARGS, NULL}, + { (char *)"Ldb_connect", (PyCFunction) _wrap_Ldb_connect, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.connect(url,flags=0,options=None) -> None\n" + "Connect to a LDB URL.\n" + ""}, + { (char *)"delete_Ldb", (PyCFunction)_wrap_delete_Ldb, METH_O, NULL}, + { (char *)"Ldb_search_ex", (PyCFunction) _wrap_Ldb_search_ex, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Ldb_delete", (PyCFunction) _wrap_Ldb_delete, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.delete(dn) -> None\n" + "Remove an entry.\n" + ""}, + { (char *)"Ldb_rename", (PyCFunction) _wrap_Ldb_rename, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.rename(old_dn, new_dn) -> None\n" + "Rename an entry.\n" + ""}, + { (char *)"Ldb_parse_control_strings", (PyCFunction) _wrap_Ldb_parse_control_strings, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Ldb_add", (PyCFunction) _wrap_Ldb_add, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.add(message) -> None\n" + "Add an entry.\n" + ""}, + { (char *)"Ldb_modify", (PyCFunction) _wrap_Ldb_modify, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.modify(message) -> None\n" + "Modify an entry.\n" + ""}, + { (char *)"Ldb_get_config_basedn", (PyCFunction)_wrap_Ldb_get_config_basedn, METH_O, NULL}, + { (char *)"Ldb_get_root_basedn", (PyCFunction)_wrap_Ldb_get_root_basedn, METH_O, NULL}, + { (char *)"Ldb_get_schema_basedn", (PyCFunction)_wrap_Ldb_get_schema_basedn, METH_O, NULL}, + { (char *)"Ldb_get_default_basedn", (PyCFunction)_wrap_Ldb_get_default_basedn, METH_O, NULL}, + { (char *)"Ldb_schema_format_value", (PyCFunction) _wrap_Ldb_schema_format_value, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Ldb_errstring", (PyCFunction)_wrap_Ldb_errstring, METH_O, NULL}, + { (char *)"Ldb_set_create_perms", (PyCFunction) _wrap_Ldb_set_create_perms, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.set_create_perms(mode) -> None\n" + "Set mode to use when creating new LDB files.\n" + ""}, + { (char *)"Ldb_set_modules_dir", (PyCFunction) _wrap_Ldb_set_modules_dir, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.set_modules_dir(path) -> None\n" + "Set path LDB should search for modules\n" + ""}, + { (char *)"Ldb_set_debug", (PyCFunction) _wrap_Ldb_set_debug, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.set_debug(callback) -> None\n" + "Set callback for LDB debug messages.\n" + "The callback should accept a debug level and debug text.\n" + ""}, + { (char *)"Ldb_set_opaque", (PyCFunction) _wrap_Ldb_set_opaque, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.set_opaque(name, value) -> None\n" + "Set an opaque value on this LDB connection. \n" + ":note: Passing incorrect values may cause crashes.\n" + ""}, + { (char *)"Ldb_get_opaque", (PyCFunction) _wrap_Ldb_get_opaque, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.get_opaque(name) -> value\n" + "Get an opaque value set on this LDB connection. \n" + ":note: The returned value may not be useful in Python.\n" + ""}, + { (char *)"Ldb_transaction_start", (PyCFunction)_wrap_Ldb_transaction_start, METH_O, (char *)"\n" + "S.transaction_start() -> None\n" + "Start a new transaction.\n" + ""}, + { (char *)"Ldb_transaction_commit", (PyCFunction)_wrap_Ldb_transaction_commit, METH_O, (char *)"\n" + "S.transaction_commit() -> None\n" + "Commit currently active transaction.\n" + ""}, + { (char *)"Ldb_transaction_cancel", (PyCFunction)_wrap_Ldb_transaction_cancel, METH_O, (char *)"\n" + "S.transaction_cancel() -> None\n" + "Cancel currently active transaction.\n" + ""}, + { (char *)"Ldb_schema_attribute_remove", (PyCFunction) _wrap_Ldb_schema_attribute_remove, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Ldb_schema_attribute_add", (PyCFunction) _wrap_Ldb_schema_attribute_add, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Ldb_setup_wellknown_attributes", (PyCFunction)_wrap_Ldb_setup_wellknown_attributes, METH_O, NULL}, + { (char *)"Ldb___contains__", (PyCFunction) _wrap_Ldb___contains__, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Ldb_parse_ldif", (PyCFunction) _wrap_Ldb_parse_ldif, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.parse_ldif(ldif) -> iter(messages)\n" + "Parse a string formatted using LDIF.\n" + ""}, + { (char *)"Ldb___repr__", (PyCFunction)_wrap_Ldb___repr__, METH_O, NULL}, + { (char *)"Ldb_swigregister", Ldb_swigregister, METH_VARARGS, NULL}, + { (char *)"Ldb_swiginit", Ldb_swiginit, METH_VARARGS, NULL}, + { (char *)"valid_attr_name", (PyCFunction) _wrap_valid_attr_name, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.valid_attr_name(name) -> bool\n" + "Check whether the supplied name is a valid attribute name.\n" + ""}, + { (char *)"timestring", (PyCFunction) _wrap_timestring, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.timestring(int) -> string\n" + "Generate a LDAP time string from a UNIX timestamp\n" + ""}, + { (char *)"string_to_time", (PyCFunction) _wrap_string_to_time, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.string_to_time(string) -> int\n" + "Parse a LDAP time string into a UNIX timestamp.\n" + ""}, + { (char *)"register_module", (PyCFunction) _wrap_register_module, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.register_module(module) -> None\n" + "Register a LDB module.\n" + ""}, + { NULL, NULL, 0, NULL } +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_TALLOC_CTX = {"_p_TALLOC_CTX", "TALLOC_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void = {"_p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void", "void (*)(void *,enum ldb_debug_level,char const *,va_list)", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_context = {"_p_ldb_context", "struct ldb_context *|ldb *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_dn = {"_p_ldb_dn", "struct ldb_dn *|ldb_dn *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_ldif = {"_p_ldb_ldif", "struct ldb_ldif *|ldb_ldif *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_message = {"_p_ldb_message", "ldb_msg *|struct ldb_message *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_message_element = {"_p_ldb_message_element", "struct ldb_message_element *|ldb_message_element *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_module_ops = {"_p_ldb_module_ops", "struct ldb_module_ops *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_result = {"_p_ldb_result", "struct ldb_result *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_val = {"_p_ldb_val", "struct ldb_val *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_ldb_control = {"_p_p_ldb_control", "struct ldb_control **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_ldb_result = {"_p_p_ldb_result", "struct ldb_result **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_long = {"_p_unsigned_long", "unsigned long *|time_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_void = {"_p_void", "void *", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_TALLOC_CTX, + &_swigt__p_char, + &_swigt__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void, + &_swigt__p_int, + &_swigt__p_ldb_context, + &_swigt__p_ldb_dn, + &_swigt__p_ldb_ldif, + &_swigt__p_ldb_message, + &_swigt__p_ldb_message_element, + &_swigt__p_ldb_module_ops, + &_swigt__p_ldb_result, + &_swigt__p_ldb_val, + &_swigt__p_long_long, + &_swigt__p_p_char, + &_swigt__p_p_ldb_control, + &_swigt__p_p_ldb_result, + &_swigt__p_short, + &_swigt__p_signed_char, + &_swigt__p_unsigned_char, + &_swigt__p_unsigned_int, + &_swigt__p_unsigned_long, + &_swigt__p_unsigned_long_long, + &_swigt__p_unsigned_short, + &_swigt__p_void, +}; + +static swig_cast_info _swigc__p_TALLOC_CTX[] = { {&_swigt__p_TALLOC_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void[] = { {&_swigt__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_context[] = { {&_swigt__p_ldb_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_dn[] = { {&_swigt__p_ldb_dn, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_ldif[] = { {&_swigt__p_ldb_ldif, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_message[] = { {&_swigt__p_ldb_message, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_message_element[] = { {&_swigt__p_ldb_message_element, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_module_ops[] = { {&_swigt__p_ldb_module_ops, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_result[] = { {&_swigt__p_ldb_result, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_val[] = { {&_swigt__p_ldb_val, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_long_long[] = { {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_char[] = { {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_ldb_control[] = { {&_swigt__p_p_ldb_control, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_ldb_result[] = { {&_swigt__p_p_ldb_result, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_short[] = { {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_signed_char[] = { {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_int[] = { {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_long[] = { {&_swigt__p_unsigned_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_long_long[] = { {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_short[] = { {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_void[] = { {&_swigt__p_void, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_TALLOC_CTX, + _swigc__p_char, + _swigc__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void, + _swigc__p_int, + _swigc__p_ldb_context, + _swigc__p_ldb_dn, + _swigc__p_ldb_ldif, + _swigc__p_ldb_message, + _swigc__p_ldb_message_element, + _swigc__p_ldb_module_ops, + _swigc__p_ldb_result, + _swigc__p_ldb_val, + _swigc__p_long_long, + _swigc__p_p_char, + _swigc__p_p_ldb_control, + _swigc__p_p_ldb_result, + _swigc__p_short, + _swigc__p_signed_char, + _swigc__p_unsigned_char, + _swigc__p_unsigned_int, + _swigc__p_unsigned_long, + _swigc__p_unsigned_long_long, + _swigc__p_unsigned_short, + _swigc__p_void, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_const_info swig_const_table[] = { +{0, 0, 0, 0.0, 0, 0}}; + +#ifdef __cplusplus +} +#endif +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found, init; + + clientdata = clientdata; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + init = 1; + } else { + init = 0; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* When multiple interpeters are used, a module could have already been initialized in + a different interpreter, but not yet have a pointer in this interpreter. + In this case, we do not want to continue adding types... everything should be + set up already */ + if (init == 0) return; + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + /* Python-specific SWIG API */ +#define SWIG_newvarlink() SWIG_Python_newvarlink() +#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) +#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) + + /* ----------------------------------------------------------------------------- + * global variable support code. + * ----------------------------------------------------------------------------- */ + + typedef struct swig_globalvar { + char *name; /* Name of global variable */ + PyObject *(*get_attr)(void); /* Return the current value */ + int (*set_attr)(PyObject *); /* Set the value */ + struct swig_globalvar *next; + } swig_globalvar; + + typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar *vars; + } swig_varlinkobject; + + SWIGINTERN PyObject * + swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { + return PyString_FromString(""); + } + + SWIGINTERN PyObject * + swig_varlink_str(swig_varlinkobject *v) { + PyObject *str = PyString_FromString("("); + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + PyString_ConcatAndDel(&str,PyString_FromString(var->name)); + if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); + } + PyString_ConcatAndDel(&str,PyString_FromString(")")); + return str; + } + + SWIGINTERN int + swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + PyObject *str = swig_varlink_str(v); + fprintf(fp,"Swig global variables "); + fprintf(fp,"%s\n", PyString_AsString(str)); + Py_DECREF(str); + return 0; + } + + SWIGINTERN void + swig_varlink_dealloc(swig_varlinkobject *v) { + swig_globalvar *var = v->vars; + while (var) { + swig_globalvar *n = var->next; + free(var->name); + free(var); + var = n; + } + } + + SWIGINTERN PyObject * + swig_varlink_getattr(swig_varlinkobject *v, char *n) { + PyObject *res = NULL; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->get_attr)(); + break; + } + var = var->next; + } + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN int + swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { + int res = 1; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->set_attr)(p); + break; + } + var = var->next; + } + if (res == 1 && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN PyTypeObject* + swig_varlink_type(void) { + static char varlink__doc__[] = "Swig var link object"; + static PyTypeObject varlink_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* Number of items in variable part (ob_size) */ + (char *)"swigvarlink", /* Type name (tp_name) */ + sizeof(swig_varlinkobject), /* Basic size (tp_basicsize) */ + 0, /* Itemsize (tp_itemsize) */ + (destructor) swig_varlink_dealloc, /* Deallocator (tp_dealloc) */ + (printfunc) swig_varlink_print, /* Print (tp_print) */ + (getattrfunc) swig_varlink_getattr, /* get attr (tp_getattr) */ + (setattrfunc) swig_varlink_setattr, /* Set attr (tp_setattr) */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)swig_varlink_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + varlink__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + varlink_type = tmp; + varlink_type.ob_type = &PyType_Type; + type_init = 1; + } + return &varlink_type; + } + + /* Create a variable linking object for use later */ + SWIGINTERN PyObject * + SWIG_Python_newvarlink(void) { + swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); + if (result) { + result->vars = 0; + } + return ((PyObject*) result); + } + + SWIGINTERN void + SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { + swig_varlinkobject *v = (swig_varlinkobject *) p; + swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + if (gv) { + size_t size = strlen(name)+1; + gv->name = (char *)malloc(size); + if (gv->name) { + strncpy(gv->name,name,size); + gv->get_attr = get_attr; + gv->set_attr = set_attr; + gv->next = v->vars; + } + } + v->vars = gv; + } + + SWIGINTERN PyObject * + SWIG_globals(void) { + static PyObject *_SWIG_globals = 0; + if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); + return _SWIG_globals; + } + + /* ----------------------------------------------------------------------------- + * constants/methods manipulation + * ----------------------------------------------------------------------------- */ + + /* Install Constants */ + SWIGINTERN void + SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { + PyObject *obj = 0; + size_t i; + for (i = 0; constants[i].type; ++i) { + switch(constants[i].type) { + case SWIG_PY_POINTER: + obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); + break; + case SWIG_PY_BINARY: + obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); + break; + default: + obj = 0; + break; + } + if (obj) { + PyDict_SetItemString(d, constants[i].name, obj); + Py_DECREF(obj); + } + } + } + + /* -----------------------------------------------------------------------------*/ + /* Fix SwigMethods to carry the callback ptrs when needed */ + /* -----------------------------------------------------------------------------*/ + + SWIGINTERN void + SWIG_Python_FixMethods(PyMethodDef *methods, + swig_const_info *const_table, + swig_type_info **types, + swig_type_info **types_initial) { + size_t i; + for (i = 0; methods[i].ml_name; ++i) { + const char *c = methods[i].ml_doc; + if (c && (c = strstr(c, "swig_ptr: "))) { + int j; + swig_const_info *ci = 0; + const char *name = c + 10; + for (j = 0; const_table[j].type; ++j) { + if (strncmp(const_table[j].name, name, + strlen(const_table[j].name)) == 0) { + ci = &(const_table[j]); + break; + } + } + if (ci) { + size_t shift = (ci->ptype) - types; + swig_type_info *ty = types_initial[shift]; + size_t ldoc = (c - methods[i].ml_doc); + size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; + char *ndoc = (char*)malloc(ldoc + lptr + 10); + if (ndoc) { + char *buff = ndoc; + void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; + if (ptr) { + strncpy(buff, methods[i].ml_doc, ldoc); + buff += ldoc; + strncpy(buff, "swig_ptr: ", 10); + buff += 10; + SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); + methods[i].ml_doc = ndoc; + } + } + } + } + } + } + +#ifdef __cplusplus +} +#endif + +/* -----------------------------------------------------------------------------* + * Partial Init method + * -----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" +#endif +SWIGEXPORT void SWIG_init(void) { + PyObject *m, *d; + + /* Fix SwigMethods to carry the callback ptrs when needed */ + SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); + + m = Py_InitModule((char *) SWIG_name, SwigMethods); + d = PyModule_GetDict(m); + + SWIG_InitializeModule(0); + SWIG_InstallConstants(d,swig_const_table); + + + SWIG_Python_SetConstant(d, "SCOPE_DEFAULT",SWIG_From_int((int)(LDB_SCOPE_DEFAULT))); + SWIG_Python_SetConstant(d, "SCOPE_BASE",SWIG_From_int((int)(LDB_SCOPE_BASE))); + SWIG_Python_SetConstant(d, "SCOPE_ONELEVEL",SWIG_From_int((int)(LDB_SCOPE_ONELEVEL))); + SWIG_Python_SetConstant(d, "SCOPE_SUBTREE",SWIG_From_int((int)(LDB_SCOPE_SUBTREE))); + SWIG_Python_SetConstant(d, "CHANGETYPE_NONE",SWIG_From_int((int)(LDB_CHANGETYPE_NONE))); + SWIG_Python_SetConstant(d, "CHANGETYPE_ADD",SWIG_From_int((int)(LDB_CHANGETYPE_ADD))); + SWIG_Python_SetConstant(d, "CHANGETYPE_DELETE",SWIG_From_int((int)(LDB_CHANGETYPE_DELETE))); + SWIG_Python_SetConstant(d, "CHANGETYPE_MODIFY",SWIG_From_int((int)(LDB_CHANGETYPE_MODIFY))); + + PyExc_LdbError = PyErr_NewException((char *)"_ldb.LdbError", NULL, NULL); + PyDict_SetItemString(d, "LdbError", PyExc_LdbError); + + SWIG_Python_SetConstant(d, "LDB_ERR_OPERATIONS_ERROR",SWIG_From_int((int)(1))); + SWIG_Python_SetConstant(d, "LDB_ERR_PROTOCOL_ERROR",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, "LDB_ERR_TIME_LIMIT_EXCEEDED",SWIG_From_int((int)(3))); + SWIG_Python_SetConstant(d, "LDB_ERR_SIZE_LIMIT_EXCEEDED",SWIG_From_int((int)(4))); + SWIG_Python_SetConstant(d, "LDB_ERR_COMPARE_FALSE",SWIG_From_int((int)(5))); + SWIG_Python_SetConstant(d, "LDB_ERR_COMPARE_TRUE",SWIG_From_int((int)(6))); + SWIG_Python_SetConstant(d, "LDB_ERR_AUTH_METHOD_NOT_SUPPORTED",SWIG_From_int((int)(7))); + SWIG_Python_SetConstant(d, "LDB_ERR_STRONG_AUTH_REQUIRED",SWIG_From_int((int)(8))); + SWIG_Python_SetConstant(d, "LDB_ERR_REFERRAL",SWIG_From_int((int)(10))); + SWIG_Python_SetConstant(d, "LDB_ERR_ADMIN_LIMIT_EXCEEDED",SWIG_From_int((int)(11))); + SWIG_Python_SetConstant(d, "LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION",SWIG_From_int((int)(12))); + SWIG_Python_SetConstant(d, "LDB_ERR_CONFIDENTIALITY_REQUIRED",SWIG_From_int((int)(13))); + SWIG_Python_SetConstant(d, "LDB_ERR_SASL_BIND_IN_PROGRESS",SWIG_From_int((int)(14))); + SWIG_Python_SetConstant(d, "LDB_ERR_NO_SUCH_ATTRIBUTE",SWIG_From_int((int)(16))); + SWIG_Python_SetConstant(d, "LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE",SWIG_From_int((int)(17))); + SWIG_Python_SetConstant(d, "LDB_ERR_INAPPROPRIATE_MATCHING",SWIG_From_int((int)(18))); + SWIG_Python_SetConstant(d, "LDB_ERR_CONSTRAINT_VIOLATION",SWIG_From_int((int)(19))); + SWIG_Python_SetConstant(d, "LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS",SWIG_From_int((int)(20))); + SWIG_Python_SetConstant(d, "LDB_ERR_INVALID_ATTRIBUTE_SYNTAX",SWIG_From_int((int)(21))); + SWIG_Python_SetConstant(d, "LDB_ERR_NO_SUCH_OBJECT",SWIG_From_int((int)(32))); + SWIG_Python_SetConstant(d, "LDB_ERR_ALIAS_PROBLEM",SWIG_From_int((int)(33))); + SWIG_Python_SetConstant(d, "LDB_ERR_INVALID_DN_SYNTAX",SWIG_From_int((int)(34))); + SWIG_Python_SetConstant(d, "LDB_ERR_ALIAS_DEREFERENCING_PROBLEM",SWIG_From_int((int)(36))); + SWIG_Python_SetConstant(d, "LDB_ERR_INAPPROPRIATE_AUTHENTICATION",SWIG_From_int((int)(48))); + SWIG_Python_SetConstant(d, "LDB_ERR_INVALID_CREDENTIALS",SWIG_From_int((int)(49))); + SWIG_Python_SetConstant(d, "LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS",SWIG_From_int((int)(50))); + SWIG_Python_SetConstant(d, "LDB_ERR_BUSY",SWIG_From_int((int)(51))); + SWIG_Python_SetConstant(d, "LDB_ERR_UNAVAILABLE",SWIG_From_int((int)(52))); + SWIG_Python_SetConstant(d, "LDB_ERR_UNWILLING_TO_PERFORM",SWIG_From_int((int)(53))); + SWIG_Python_SetConstant(d, "LDB_ERR_LOOP_DETECT",SWIG_From_int((int)(54))); + SWIG_Python_SetConstant(d, "LDB_ERR_NAMING_VIOLATION",SWIG_From_int((int)(64))); + SWIG_Python_SetConstant(d, "LDB_ERR_OBJECT_CLASS_VIOLATION",SWIG_From_int((int)(65))); + SWIG_Python_SetConstant(d, "LDB_ERR_NOT_ALLOWED_ON_NON_LEAF",SWIG_From_int((int)(66))); + SWIG_Python_SetConstant(d, "LDB_ERR_NOT_ALLOWED_ON_RDN",SWIG_From_int((int)(67))); + SWIG_Python_SetConstant(d, "LDB_ERR_ENTRY_ALREADY_EXISTS",SWIG_From_int((int)(68))); + SWIG_Python_SetConstant(d, "LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED",SWIG_From_int((int)(69))); + SWIG_Python_SetConstant(d, "LDB_ERR_AFFECTS_MULTIPLE_DSAS",SWIG_From_int((int)(71))); + SWIG_Python_SetConstant(d, "LDB_ERR_OTHER",SWIG_From_int((int)(80))); +} + diff --git a/ldb/libldb.m4 b/ldb/libldb.m4 new file mode 100644 index 000000000..77ebcc5ff --- /dev/null +++ b/ldb/libldb.m4 @@ -0,0 +1,7 @@ + +# disable ldb_sqlite3 by default +SMB_ENABLE(ldb_sqlite3, NO) + +if test x"$with_sqlite3_support" = x"yes"; then + SMB_ENABLE(ldb_sqlite3, YES) +fi diff --git a/ldb/mainpage.dox b/ldb/mainpage.dox new file mode 100644 index 000000000..bbd8d9c50 --- /dev/null +++ b/ldb/mainpage.dox @@ -0,0 +1,80 @@ +/** + +\mainpage ldb + +\section Overview + +ldb is a LDAP-like embedded database. It is not at all LDAP standards +compliant, so if you want a standards compliant database then please +see the excellent OpenLDAP +project.

+ +What ldb does is provide a fast database with an LDAP-like API +designed to be used within an application. In some ways it can be seen +as a intermediate solution between key-value pair databases and a real +LDAP database.

+ +ldb is the database engine used in Samba4. + +\section Features + +The main features that separate ldb from other solutions are: + - Safe multi-reader, multi-writer, using byte range locking + - LDAP-like API + - fast operation + - choice of local tdb, local sqlite3 or remote LDAP backends + - integration with talloc + - schema-less operation, for trivial setup + - modules for extensions (such as schema support) + - easy setup of indexes and attribute properties + - ldbedit tool for database editing (reminiscent of 'vipw') + - ldif for import/export + +\section Documentation + +ldb has limited programmer and administrator documentation: + - a list of functions + - a list of examples + - a list of data structures + - a list of constants + +If you need more information than is presented in this document, you +may wish to look at the source code, especially the source code in the +tools directory. + +ldb makes use of the LDAP Data Interchange Format (LDIF), which is +documented in RFC +2849. + +\section Support + +ldb does not currently have its own mailing list or bug tracking +system. For now, please use the samba-technical +mailing list, and the Samba +bugzilla bug tracking system. + +\section Download + +You can download the latest release either via rsync or anonymous +svn. To fetch via svn use the following commands: + +\verbatim + svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/ldb ldb + svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/tdb tdb + svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/talloc talloc +\endverbatim + +To fetch via rsync use these commands: + +\verbatim + rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/ldb . + rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/tdb . + rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/talloc . +\endverbatim + +\section Credits + +ldb is another product of the prolific Andrew Tridgell. + +*/ diff --git a/ldb/man/ad2oLschema.1.xml b/ldb/man/ad2oLschema.1.xml new file mode 100644 index 000000000..6ae899647 --- /dev/null +++ b/ldb/man/ad2oLschema.1.xml @@ -0,0 +1,87 @@ + + + + + + ad2oLschema + 1 + + + + + ad2oLschema + Converts AC-like LDAP schemas to OpenLDAP + compatible schema files + + + + + ad2oLschema + -I INPUT-FILE + -O OUTPUT-FILE + + + + + DESCRIPTION + + ad2oLschema is a simple tool that converts AD-like LDIF + schema files into OpenLDAP schema files. + + + + + OPTIONS + + + + -H url + URL to an LDB or LDAP server with an AD schema to read. + + + + -I input-file AD schema + to read. If neither this nor -H is specified, the + schema file will be read from standard input. + + + + + -O output-file + File to write OpenLDAP version of schema to. + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbdel, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + ad2oLschema was written by Andrew Bartlett. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + + + diff --git a/ldb/man/ldb.3.xml b/ldb/man/ldb.3.xml new file mode 100644 index 000000000..19d9a89e1 --- /dev/null +++ b/ldb/man/ldb.3.xml @@ -0,0 +1,262 @@ + + + + + + ldb + 3 + + + + ldb + The Samba Project + A light-weight database library + + + + #include <ldb.h> + + + + description + + +ldb is a light weight embedded database library and API. With a +programming interface that is very similar to LDAP, ldb can store its +data either in a tdb(3) database or in a real LDAP database. + + + +When used with the tdb backend ldb does not require any database +daemon. Instead, ldb function calls are processed immediately by the +ldb library, which does IO directly on the database, while allowing +multiple readers/writers using operating system byte range locks. This +leads to an API with very low overheads, often resulting in speeds of +more than 10x what can be achieved with a more traditional LDAP +architecture. + + + +In a taxonomy of databases ldb would sit half way between key/value +pair databases (such as berkley db or tdb) and a full LDAP +database. With a structured attribute oriented API like LDAP and good +indexing capabilities, ldb can be used for quite sophisticated +applications that need a light weight database, without the +administrative overhead of a full LDAP installation. + + + +Included with ldb are a number of useful command line tools for +manipulating a ldb database. These tools are similar in style to the +equivalent ldap command line tools. + + + +In its default mode of operation with a tdb backend, ldb can also be +seen as a "schema-less LDAP". By default ldb does not require a +schema, which greatly reduces the complexity of getting started with +ldb databases. As the complexity of you application grows you can take +advantage of some of the optional schema-like attributes that ldb +offers, or you can migrate to using the full LDAP api while keeping +your exiting ldb code. + + + +If you are new to ldb, then I suggest starting with the manual pages +for ldbsearch(1) and ldbedit(1), and experimenting with a local +database. Then I suggest you look at the ldb_connect(3) and +ldb_search(3) manual pages. + + + + + TOOLS + + + + ldbsearch(1) + - command line ldb search utility + + + + ldbedit(1) + - edit all or part of a ldb database using your favourite editor + + + + ldbadd(1) + - add records to a ldb database using LDIF formatted input + + + + ldbdel(1) + - delete records from a ldb database + + + + ldbmodify(1) + - modify records in a ldb database using LDIF formatted input + + + + + + FUNCTIONS + + + + ldb_connect(3) + - connect to a ldb backend + + + + ldb_search(3) + - perform a database search + + + + ldb_add(3) + - add a record to the database + + + + ldb_delete(3) + - delete a record from the database + + + + ldb_modify(3) + - modify a record in the database + + + + ldb_errstring(3) + - retrieve extended error information from the last operation + + + + ldb_ldif_write(3) + - write a LDIF formatted message + + + + ldb_ldif_write_file(3) + - write a LDIF formatted message to a file + + + + ldb_ldif_read(3) + - read a LDIF formatted message + + + + ldb_ldif_read_free(3) + - free the result of a ldb_ldif_read() + + + + ldb_ldif_read_file(3) + - read a LDIF message from a file + + + + ldb_ldif_read_string(3) + - read a LDIF message from a string + + + + ldb_msg_find_element(3) + - find an element in a ldb_message + + + + ldb_val_equal_exact(3) + - compare two ldb_val structures + + + + ldb_msg_find_val(3) + - find an element by value + + + + ldb_msg_add_empty(3) + - add an empty message element to a ldb_message + + + + + ldb_msg_add(3) + - add a non-empty message element to a ldb_message + + + + + ldb_msg_element_compare(3) + - compare two ldb_message_element structures + + + + + ldb_msg_find_int(3) + - return an integer value from a ldb_message + + + + + ldb_msg_find_uint(3) + - return an unsigned integer value from a ldb_message + + + + + ldb_msg_find_double(3) + - return a double value from a ldb_message + + + + + ldb_msg_find_string(3) + - return a string value from a ldb_message + + + + + ldb_set_alloc(3) + - set the memory allocation function to be used by ldb + + + + + ldb_set_debug(3) + - set a debug handler to be used by ldb + + + + + ldb_set_debug_stderr(3) + - set a debug handler for stderr output + + + + + + Author + + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + +ldb is released under the GNU Lesser General Public License version 2 +or later. Please see the file COPYING for license details. + + + diff --git a/ldb/man/ldbadd.1.xml b/ldb/man/ldbadd.1.xml new file mode 100644 index 000000000..7ad0f835d --- /dev/null +++ b/ldb/man/ldbadd.1.xml @@ -0,0 +1,105 @@ + + + + + + ldbadd + 1 + + + + + ldbadd + Command-line utility for adding records to an LDB + + + + + ldbadd + -h + -H LDB-URL + ldif-file1 + ldif-file2 + ... + + + + + DESCRIPTION + + ldbadd adds records to an ldb(7) database. It reads + the ldif(5) files specified on the command line and adds + the records from these files to the LDB database, which is specified + by the -H option or the LDB_URL environment variable. + + + If - is specified as a ldb file, the ldif input is read from + standard input. + + + + + + OPTIONS + + + + -h + + Show list of available options. + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbdel, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/ldb/man/ldbdel.1.xml b/ldb/man/ldbdel.1.xml new file mode 100644 index 000000000..7dfc7366f --- /dev/null +++ b/ldb/man/ldbdel.1.xml @@ -0,0 +1,105 @@ + + + + + + ldbdel + 1 + + + + + ldbdel + Command-line program for deleting LDB records + + + + + ldbdel + -h + -H LDB-URL + dn + ... + + + + + DESCRIPTION + + ldbdel deletes records from an ldb(7) database. + It deletes the records identified by the dn's specified + on the command-line. + + ldbdel uses either the database that is specified with + the -H option or the database specified by the LDB_URL environment + variable. + + + + + + OPTIONS + + + + -h + + Show list of available options. + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbadd, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + ldbdel was written by Andrew Tridgell. + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/ldb/man/ldbedit.1.xml b/ldb/man/ldbedit.1.xml new file mode 100644 index 000000000..15c69b1b2 --- /dev/null +++ b/ldb/man/ldbedit.1.xml @@ -0,0 +1,200 @@ + + + + + + ldbedit + 1 + + + + + ldbedit + Edit LDB databases using your preferred editor + + + + + ldbedit + -? + --usage + -s base|one|sub + -b basedn + -a + -e editor + -H LDB-URL + expression + attributes + + + + + DESCRIPTION + + ldbedit is a utility that allows you to edit LDB entries (in + tdb files, sqlite files or LDAP servers) using your preferred editor. + ldbedit generates an LDIF file based on your query, allows you to edit + the LDIF, and then merges that LDIF back into the LDB backend. + + + + + + + OPTIONS + + + + -? + --help + + + Show list of available options, and a phrase describing what that option + does. + + + + + + --usage + + + Show list of available options. This is similar to the help option, + however it does not provide any description, and is hence shorter. + + + + + + -H <ldb-url> + + + LDB URL to connect to. For a tdb database, + this will be of the form + tdb://filename. + For a LDAP connection over unix domain + sockets, this will be of the form + ldapi://socket. For + a (potentially remote) LDAP connection over + TCP, this will be of the form + ldap://hostname. For + an SQLite database, this will be of the form + sqlite://filename. + + + + + + -s one|sub|base + Search scope to use. One-level, subtree or base. + + + + -a + -all + + Edit all records. This allows you to + apply the same change to a number of records + at once. You probably want to combine this + with an expression of the form + "objectclass=*". + + + + + + -e editor + --editor editor + + Specify the editor that should be used (overrides + the VISUAL and EDITOR environment + variables). If this option is not used, and + neither VISUAL nor EDITOR environment variables + are set, then the vi editor will be used. + + + + + + -b basedn + Specify Base Distinguished Name to use. + + + + -v + --verbose + + Make ldbedit more verbose about the + operations that are being performed. Without + this option, ldbedit will only provide a + summary change line. + + + + + + + + + + ENVIRONMENT + + + + LDB_URL + + LDB URL to connect to. This can be + overridden by using the -H command-line option.) + + + + + VISUAL and EDITOR + + + Environment variables used to determine what + editor to use. VISUAL takes precedence over + EDITOR, and both are overridden by the + -e command-line option. + + + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify(1), ldbdel(1), ldif(5), vi(1) + + + + + AUTHOR + + + ldb was written by + Andrew Tridgell. + + + + If you wish to report a problem or make a suggestion then please see + the web site for + current contact and maintainer information. + + + + This manpage was written by Jelmer Vernooij and updated + by Brad Hards. + + + + + diff --git a/ldb/man/ldbmodify.1.xml b/ldb/man/ldbmodify.1.xml new file mode 100644 index 000000000..bc1964778 --- /dev/null +++ b/ldb/man/ldbmodify.1.xml @@ -0,0 +1,93 @@ + + + + + + ldbmodify + 1 + + + + + ldbmodify + Modify records in a LDB database + + + + + ldbmodify + -H LDB-URL + ldif-file + + + + + DESCRIPTION + + + ldbmodify changes, adds and deletes records in a LDB database. + The changes that should be made to the LDB database are read from + the specified LDIF-file. If - is specified as the filename, input is read from stdin. + + + For now, see ldapmodify(1) for details on the LDIF file format. + + + + + + OPTIONS + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbedit + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/ldb/man/ldbrename.1.xml b/ldb/man/ldbrename.1.xml new file mode 100644 index 000000000..391ec84cc --- /dev/null +++ b/ldb/man/ldbrename.1.xml @@ -0,0 +1,107 @@ + + + + + + ldbrename + 1 + + + + + ldbrename + Edit LDB databases using your favorite editor + + + + + ldbrename + -h + -o options + olddn + newdb + + + + + DESCRIPTION + + ldbrename is a utility that allows you to rename trees in + an LDB database based by DN. This utility takes + two arguments: the original + DN name of the top element and the DN to change it to. + + + + + + + OPTIONS + + + + -h + + Show list of available options. + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + -o options + Extra ldb options, such as + modules. + + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbdel, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/ldb/man/ldbsearch.1.xml b/ldb/man/ldbsearch.1.xml new file mode 100644 index 000000000..ed3749b92 --- /dev/null +++ b/ldb/man/ldbsearch.1.xml @@ -0,0 +1,119 @@ + + + + + + ldbsearch + 1 + + + + + ldbsearch + Search for records in a LDB database + + + + + ldbsearch + -h + -s base|one|sub + -b basedn + -i + -H LDB-URL + expression + attributes + + + + + DESCRIPTION + + ldbsearch searches a LDB database for records matching the + specified expression (see the ldapsearch(1) manpage for + a description of the expression format). For each + record, the specified attributes are printed. + + + + + + + OPTIONS + + + + -h + + Show list of available options. + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + -s one|sub|base + Search scope to use. One-level, subtree or base. + + + + -i + Read search expressions from stdin. + + + + -b basedn + Specify Base DN to use. + + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbedit(1) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/ldb/man/oLschema2ldif.1.xml b/ldb/man/oLschema2ldif.1.xml new file mode 100644 index 000000000..b1e681be4 --- /dev/null +++ b/ldb/man/oLschema2ldif.1.xml @@ -0,0 +1,79 @@ + + + + + + oLschema2ldif + 1 + + + + + oLschema2ldif + Converts LDAP schema's to LDB-compatible LDIF + + + + + oLschema2ldif + -I INPUT-FILE + -O OUTPUT-FILE + + + + + DESCRIPTION + + oLschema2ldif is a simple tool that converts standard OpenLDAP schema files to a LDIF format that is understood by LDB. + + + + + OPTIONS + + + + -I input-file + OpenLDAP schema to read. If none are specified, +the schema file will be read from standard input. + + + + + -O output-file + File to write ldif version of schema to. + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbdel, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + oLschema2ldif was written by Simo Sorce. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + + + diff --git a/ldb/modules/asq.c b/ldb/modules/asq.c new file mode 100644 index 000000000..eb27263b1 --- /dev/null +++ b/ldb/modules/asq.c @@ -0,0 +1,481 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb attribute scoped query control module + * + * Description: this module searches all the the objects pointed + * by the DNs contained in the references attribute + * + * Author: Simo Sorce + */ + +#include "ldb_includes.h" + +struct asq_context { + + enum {ASQ_INIT, ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step; + + struct ldb_module *module; + struct ldb_request *orig_req; + + struct ldb_asq_control *asq_ctrl; + + const char * const *req_attrs; + char *req_attribute; + enum { + ASQ_CTRL_SUCCESS = 0, + ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21, + ASQ_CTRL_UNWILLING_TO_PERFORM = 53, + ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71 + } asq_ret; + + struct ldb_request *base_req; + struct ldb_reply *base_res; + + struct ldb_request **reqs; + int num_reqs; + int cur_req; + + struct ldb_control **controls; +}; + +static struct ldb_handle *init_handle(struct ldb_request *req, struct ldb_module *module) +{ + struct asq_context *ac; + struct ldb_handle *h; + + h = talloc_zero(req, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc_zero(h, struct asq_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->step = ASQ_INIT; + ac->module = module; + ac->orig_req = req; + + return h; +} + +static int asq_terminate(struct ldb_handle *handle) +{ + struct asq_context *ac; + struct ldb_reply *ares; + struct ldb_asq_control *asq; + int i; + + ac = talloc_get_type(handle->private_data, struct asq_context); + if (ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + handle->status = LDB_SUCCESS; + handle->state = LDB_ASYNC_DONE; + + ares = talloc_zero(ac, struct ldb_reply); + if (ares == NULL) + return LDB_ERR_OPERATIONS_ERROR; + + ares->type = LDB_REPLY_DONE; + + if (ac->controls) { + for (i = 0; ac->controls[i]; i++); + ares->controls = talloc_move(ares, &ac->controls); + } else { + i = 0; + } + + ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, i + 2); + + if (ares->controls == NULL) + return LDB_ERR_OPERATIONS_ERROR; + + ares->controls[i] = talloc(ares->controls, struct ldb_control); + if (ares->controls[i] == NULL) + return LDB_ERR_OPERATIONS_ERROR; + + ares->controls[i]->oid = LDB_CONTROL_ASQ_OID; + ares->controls[i]->critical = 0; + + asq = talloc_zero(ares->controls[i], struct ldb_asq_control); + if (asq == NULL) + return LDB_ERR_OPERATIONS_ERROR; + + asq->result = ac->asq_ret; + + ares->controls[i]->data = asq; + + ares->controls[i + 1] = NULL; + + ac->orig_req->callback(ac->module->ldb, ac->orig_req->context, ares); + + return LDB_SUCCESS; +} + +static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct asq_context *ac; + + if (!context || !ares) { + ldb_set_errstring(ldb, "NULL Context or Result in callback"); + goto error; + } + + ac = talloc_get_type(context, struct asq_context); + if (ac == NULL) { + goto error; + } + + /* we are interested only in the single reply (base search) we receive here */ + if (ares->type == LDB_REPLY_ENTRY) { + ac->base_res = talloc_move(ac, &ares); + } else { + talloc_free(ares); + } + + return LDB_SUCCESS; +error: + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; +} + +static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct asq_context *ac; + + if (!context || !ares) { + ldb_set_errstring(ldb, "NULL Context or Result in callback"); + goto error; + } + + ac = talloc_get_type(context, struct asq_context); + if (ac == NULL) { + goto error; + } + + /* we are interested only in the single reply (base search) we receive here */ + if (ares->type == LDB_REPLY_ENTRY) { + + /* pass the message up to the original callback as we + * do not have to elaborate on it any further */ + return ac->orig_req->callback(ac->module->ldb, ac->orig_req->context, ares); + + } else { /* ignore any REFERRAL or DONE reply */ + talloc_free(ares); + } + + return LDB_SUCCESS; +error: + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; +} + +static int asq_build_first_request(struct asq_context *ac) +{ + char **base_attrs; + + ac->base_req = talloc_zero(ac, struct ldb_request); + if (ac->base_req == NULL) return LDB_ERR_OPERATIONS_ERROR; + + ac->base_req->operation = ac->orig_req->operation; + ac->base_req->op.search.base = ac->orig_req->op.search.base; + ac->base_req->op.search.scope = LDB_SCOPE_BASE; + ac->base_req->op.search.tree = ac->orig_req->op.search.tree; + base_attrs = talloc_array(ac->base_req, char *, 2); + if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR; + + base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute); + if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR; + + base_attrs[1] = NULL; + ac->base_req->op.search.attrs = (const char * const *)base_attrs; + + ac->base_req->context = ac; + ac->base_req->callback = asq_base_callback; + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->base_req); + + return LDB_SUCCESS; +} + +static int asq_build_multiple_requests(struct asq_context *ac, struct ldb_handle *handle) +{ + struct ldb_message_element *el; + int i; + + /* look up the DNs */ + if (ac->base_res == NULL) { + return LDB_ERR_NO_SUCH_OBJECT; + } + el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute); + /* no values found */ + if (el == NULL) { + ac->asq_ret = ASQ_CTRL_SUCCESS; + return asq_terminate(handle); + } + + ac->num_reqs = el->num_values; + ac->cur_req = 0; + ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs); + if (ac->reqs == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i = 0; i < el->num_values; i++) { + + ac->reqs[i] = talloc_zero(ac->reqs, struct ldb_request); + if (ac->reqs[i] == NULL) + return LDB_ERR_OPERATIONS_ERROR; + ac->reqs[i]->operation = LDB_SEARCH; + ac->reqs[i]->op.search.base = ldb_dn_new(ac->reqs[i], ac->module->ldb, (const char *)el->values[i].data); + if ( ! ldb_dn_validate(ac->reqs[i]->op.search.base)) { + ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX; + return asq_terminate(handle); + } + ac->reqs[i]->op.search.scope = LDB_SCOPE_BASE; + ac->reqs[i]->op.search.tree = ac->base_req->op.search.tree; + ac->reqs[i]->op.search.attrs = ac->req_attrs; + + ac->reqs[i]->context = ac; + ac->reqs[i]->callback = asq_reqs_callback; + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->base_req, ac->reqs[i]); + } + + return LDB_SUCCESS; +} + +static int asq_search_continue(struct ldb_handle *handle) +{ + struct asq_context *ac; + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (handle->state == LDB_ASYNC_DONE) { + return handle->status; + } + + ac = talloc_get_type(handle->private_data, struct asq_context); + if (ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + switch (ac->step) { + case ASQ_INIT: + /* check the search is well formed */ + if (ac->orig_req->op.search.scope != LDB_SCOPE_BASE) { + ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM; + return asq_terminate(handle); + } + + ac->req_attrs = ac->orig_req->op.search.attrs; + ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute); + if (ac->req_attribute == NULL) + return LDB_ERR_OPERATIONS_ERROR; + + /* get the object to retrieve the DNs to search */ + ret = asq_build_first_request(ac); + if (ret != LDB_SUCCESS) { + return ret; + } + + ac->step = ASQ_SEARCH_BASE; + + handle->state = LDB_ASYNC_PENDING; + handle->status = LDB_SUCCESS; + + return ldb_request(ac->module->ldb, ac->base_req); + + case ASQ_SEARCH_BASE: + + ret = ldb_wait(ac->base_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + + if (ac->base_req->handle->status != LDB_SUCCESS) { + handle->status = ac->base_req->handle->status; + goto done; + } + + if (ac->base_req->handle->state == LDB_ASYNC_DONE) { + + /* build up the requests call chain */ + ret = asq_build_multiple_requests(ac, handle); + if (ret != LDB_SUCCESS) { + return ret; + } + if (handle->state == LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + ac->step = ASQ_SEARCH_MULTI; + + return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]); + } + + /* request still pending, return to cycle again */ + return LDB_SUCCESS; + + case ASQ_SEARCH_MULTI: + + ret = ldb_wait(ac->reqs[ac->cur_req]->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->reqs[ac->cur_req]->handle->status != LDB_SUCCESS) { + handle->status = ac->reqs[ac->cur_req]->handle->status; + } + + if (ac->reqs[ac->cur_req]->handle->state == LDB_ASYNC_DONE) { + ac->cur_req++; + + if (ac->cur_req < ac->num_reqs) { + return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]); + } + + return asq_terminate(handle); + } + + /* request still pending, return to cycle again */ + return LDB_SUCCESS; + + default: + ret = LDB_ERR_OPERATIONS_ERROR; + break; + } + +done: + handle->state = LDB_ASYNC_DONE; + return ret; +} + +static int asq_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_control *control; + struct asq_context *ac; + struct ldb_handle *h; + + /* check if there's a paged request control */ + control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID); + if (control == NULL) { + /* not found go on */ + return ldb_next_request(module, req); + } + + req->handle = NULL; + + if (!req->callback || !req->context) { + ldb_set_errstring(module->ldb, + "Async interface called with NULL callback function or NULL context"); + return LDB_ERR_OPERATIONS_ERROR; + } + + h = init_handle(req, module); + if (!h) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct asq_context); + + ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control); + if (!ac->asq_ctrl) { + return LDB_ERR_PROTOCOL_ERROR; + } + + req->handle = h; + + return asq_search_continue(h); +} + +static int asq_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (type == LDB_WAIT_ALL) { + while (handle->state != LDB_ASYNC_DONE) { + ret = asq_search_continue(handle); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return handle->status; + } + + return asq_search_continue(handle); +} + +static int asq_init(struct ldb_module *module) +{ + struct ldb_request *req; + int ret; + + req = talloc_zero(module, struct ldb_request); + if (req == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Out of memory!\n"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_REQ_REGISTER_CONTROL; + req->op.reg_control.oid = LDB_CONTROL_ASQ_OID; + + ret = ldb_request(module->ldb, req); + if (ret != LDB_SUCCESS) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n"); + } + + return ldb_next_init(module); +} + +const struct ldb_module_ops ldb_asq_module_ops = { + .name = "asq", + .search = asq_search, + .wait = asq_wait, + .init_context = asq_init +}; diff --git a/ldb/modules/operational.c b/ldb/modules/operational.c new file mode 100644 index 000000000..a59e81bec --- /dev/null +++ b/ldb/modules/operational.c @@ -0,0 +1,305 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Simo Sorce 2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ +/* + handle operational attributes + */ + +/* + createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated + modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged + + for the above two, we do the search as normal, and if + createTimestamp or modifyTimestamp is asked for, then do + additional searches for whenCreated and whenChanged and fill in + the resulting values + + we also need to replace these with the whenCreated/whenChanged + equivalent in the search expression trees + + whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE + whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE + + on init we need to setup attribute handlers for these so + comparisons are done correctly. The resolution is 1 second. + + on add we need to add both the above, for current time + + on modify we need to change whenChanged + + + subschemaSubentry: HIDDEN, not-searchable, + points at DN CN=Aggregate,$SCHEMADN + + for this one we do the search as normal, then add the static + value if requested. How do we work out the $BASEDN from inside a + module? + + + structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass? + + for this one we do the search as normal, then if requested ask + for objectclass, change the attribute name, and add it + + allowedAttributesEffective: HIDDEN, CONSTRUCTED, not-searchable, + list of attributes that can be modified - requires schema lookup + + + attributeTypes: in schema only + objectClasses: in schema only + matchingRules: in schema only + matchingRuleUse: in schema only + creatorsName: not supported by w2k3? + modifiersName: not supported by w2k3? +*/ + +#include "ldb_includes.h" + +/* + construct a canonical name from a message +*/ +static int construct_canonical_name(struct ldb_module *module, struct ldb_message *msg) +{ + char *canonicalName; + canonicalName = ldb_dn_canonical_string(msg, msg->dn); + if (canonicalName == NULL) { + return -1; + } + return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName); +} + +/* + a list of attribute names that should be substituted in the parse + tree before the search is done +*/ +static const struct { + const char *attr; + const char *replace; +} parse_tree_sub[] = { + { "createTimestamp", "whenCreated" }, + { "modifyTimestamp", "whenChanged" } +}; + + +/* + a list of attribute names that are hidden, but can be searched for + using another (non-hidden) name to produce the correct result +*/ +static const struct { + const char *attr; + const char *replace; + int (*constructor)(struct ldb_module *, struct ldb_message *); +} search_sub[] = { + { "createTimestamp", "whenCreated", NULL }, + { "modifyTimestamp", "whenChanged", NULL }, + { "structuralObjectClass", "objectClass", NULL }, + { "canonicalName", "distinguishedName", construct_canonical_name } +}; + +/* + post process a search result record. For any search_sub[] attributes that were + asked for, we need to call the appropriate copy routine to copy the result + into the message, then remove any attributes that we added to the search but were + not asked for by the user +*/ +static int operational_search_post_process(struct ldb_module *module, + struct ldb_message *msg, + const char * const *attrs) +{ + int i, a=0; + + for (a=0;attrs && attrs[a];a++) { + for (i=0;ildb, LDB_DEBUG_WARNING, + "operational_search_post_process failed for attribute '%s'\n", + attrs[a]); + return -1; +} + + +/* + hook search operations +*/ + +struct operational_context { + + struct ldb_module *module; + void *up_context; + int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *); + + const char * const *attrs; +}; + +static int operational_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct operational_context *ac; + + if (!context || !ares) { + ldb_set_errstring(ldb, "NULL Context or Result in callback"); + goto error; + } + + ac = talloc_get_type(context, struct operational_context); + + if (ares->type == LDB_REPLY_ENTRY) { + /* for each record returned post-process to add any derived + attributes that have been asked for */ + if (operational_search_post_process(ac->module, ares->message, ac->attrs) != 0) { + goto error; + } + } + + return ac->up_callback(ldb, ac->up_context, ares); + +error: + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; +} + +static int operational_search(struct ldb_module *module, struct ldb_request *req) +{ + struct operational_context *ac; + struct ldb_request *down_req; + const char **search_attrs = NULL; + int i, a, ret; + + req->handle = NULL; + + ac = talloc(req, struct operational_context); + if (ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->module = module; + ac->up_context = req->context; + ac->up_callback = req->callback; + ac->attrs = req->op.search.attrs; + + down_req = talloc_zero(req, struct ldb_request); + if (down_req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + down_req->operation = req->operation; + down_req->op.search.base = req->op.search.base; + down_req->op.search.scope = req->op.search.scope; + down_req->op.search.tree = req->op.search.tree; + + /* FIXME: I hink we should copy the tree and keep the original + * unmodified. SSS */ + /* replace any attributes in the parse tree that are + searchable, but are stored using a different name in the + backend */ + for (i=0;iop.search.tree, + parse_tree_sub[i].attr, + parse_tree_sub[i].replace); + } + + /* in the list of attributes we are looking for, rename any + attributes to the alias for any hidden attributes that can + be fetched directly using non-hidden names */ + for (a=0;ac->attrs && ac->attrs[a];a++) { + for (i=0;iattrs[a], search_sub[i].attr) == 0 && + search_sub[i].replace) { + if (!search_attrs) { + search_attrs = ldb_attr_list_copy(req, ac->attrs); + if (search_attrs == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + search_attrs[a] = search_sub[i].replace; + } + } + } + + /* use new set of attrs if any */ + if (search_attrs) down_req->op.search.attrs = search_attrs; + else down_req->op.search.attrs = req->op.search.attrs; + + down_req->controls = req->controls; + + down_req->context = ac; + down_req->callback = operational_callback; + ldb_set_timeout_from_prev_req(module->ldb, req, down_req); + + /* perform the search */ + ret = ldb_next_request(module, down_req); + + /* do not free down_req as the call results may be linked to it, + * it will be freed when the upper level request get freed */ + if (ret == LDB_SUCCESS) { + req->handle = down_req->handle; + } + + return ret; +} + +static int operational_init(struct ldb_module *ctx) +{ + int ret = 0; + + if (ret != 0) { + return ret; + } + + return ldb_next_init(ctx); +} + +const struct ldb_module_ops ldb_operational_module_ops = { + .name = "operational", + .search = operational_search, + .init_context = operational_init +}; diff --git a/ldb/modules/paged_results.c b/ldb/modules/paged_results.c new file mode 100644 index 000000000..b62b1f92c --- /dev/null +++ b/ldb/modules/paged_results.c @@ -0,0 +1,557 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005-2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: paged_result + * + * Component: ldb paged results control module + * + * Description: this module caches a complete search and sends back + * results in chunks as asked by the client + * + * Author: Simo Sorce + */ + +#include "ldb_includes.h" + +struct message_store { + /* keep the whole ldb_reply as an optimization + * instead of freeing and talloc-ing the container + * on each result */ + struct ldb_reply *r; + struct message_store *next; +}; + +struct private_data; + +struct results_store { + + struct private_data *priv; + + char *cookie; + time_t timestamp; + + struct results_store *prev; + struct results_store *next; + + struct message_store *first; + struct message_store *last; + int num_entries; + + struct message_store *first_ref; + struct message_store *last_ref; + + struct ldb_control **controls; + + struct ldb_request *req; +}; + +struct private_data { + + int next_free_id; + struct results_store *store; + +}; + +int store_destructor(struct results_store *store) +{ + if (store->prev) { + store->prev->next = store->next; + } + if (store->next) { + store->next->prev = store->prev; + } + + if (store == store->priv->store) { + store->priv->store = NULL; + } + + return 0; +} + +static struct results_store *new_store(struct private_data *priv) +{ + struct results_store *newr; + int new_id = priv->next_free_id++; + + /* TODO: we should have a limit on the number of + * outstanding paged searches + */ + + newr = talloc(priv, struct results_store); + if (!newr) return NULL; + + newr->priv = priv; + + newr->cookie = talloc_asprintf(newr, "%d", new_id); + if (!newr->cookie) { + talloc_free(newr); + return NULL; + } + + newr->timestamp = time(NULL); + + newr->first = NULL; + newr->num_entries = 0; + newr->first_ref = NULL; + newr->controls = NULL; + + /* put this entry as first */ + newr->prev = NULL; + newr->next = priv->store; + if (priv->store != NULL) priv->store->prev = newr; + priv->store = newr; + + talloc_set_destructor(newr, store_destructor); + + return newr; +} + +struct paged_context { + struct ldb_module *module; + void *up_context; + int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *); + + int size; + + struct results_store *store; +}; + +static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +{ + struct paged_context *ac; + struct ldb_handle *h; + + h = talloc_zero(mem_ctx, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc_zero(h, struct paged_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->module = module; + ac->up_context = context; + ac->up_callback = callback; + + return h; +} + +static int paged_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct paged_context *ac = NULL; + + if (!context || !ares) { + ldb_set_errstring(ldb, "NULL Context or Result in callback"); + goto error; + } + + ac = talloc_get_type(context, struct paged_context); + + if (ares->type == LDB_REPLY_ENTRY) { + if (ac->store->first == NULL) { + ac->store->first = ac->store->last = talloc(ac->store, struct message_store); + } else { + ac->store->last->next = talloc(ac->store, struct message_store); + ac->store->last = ac->store->last->next; + } + if (ac->store->last == NULL) { + goto error; + } + + ac->store->num_entries++; + + ac->store->last->r = talloc_steal(ac->store->last, ares); + ac->store->last->next = NULL; + } + + if (ares->type == LDB_REPLY_REFERRAL) { + if (ac->store->first_ref == NULL) { + ac->store->first_ref = ac->store->last_ref = talloc(ac->store, struct message_store); + } else { + ac->store->last_ref->next = talloc(ac->store, struct message_store); + ac->store->last_ref = ac->store->last_ref->next; + } + if (ac->store->last_ref == NULL) { + goto error; + } + + ac->store->last_ref->r = talloc_steal(ac->store->last, ares); + ac->store->last_ref->next = NULL; + } + + if (ares->type == LDB_REPLY_DONE) { + ac->store->controls = talloc_move(ac->store, &ares->controls); + talloc_free(ares); + } + + return LDB_SUCCESS; + +error: + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; +} + +static int paged_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_control *control; + struct private_data *private_data; + struct ldb_paged_control *paged_ctrl; + struct ldb_control **saved_controls; + struct paged_context *ac; + struct ldb_handle *h; + int ret; + + /* check if there's a paged request control */ + control = ldb_request_get_control(req, LDB_CONTROL_PAGED_RESULTS_OID); + if (control == NULL) { + /* not found go on */ + return ldb_next_request(module, req); + } + + private_data = talloc_get_type(module->private_data, struct private_data); + + req->handle = NULL; + + if (!req->callback || !req->context) { + ldb_set_errstring(module->ldb, + "Async interface called with NULL callback function or NULL context"); + return LDB_ERR_OPERATIONS_ERROR; + } + + paged_ctrl = talloc_get_type(control->data, struct ldb_paged_control); + if (!paged_ctrl) { + return LDB_ERR_PROTOCOL_ERROR; + } + + h = init_handle(req, module, req->context, req->callback); + if (!h) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct paged_context); + + ac->size = paged_ctrl->size; + + /* check if it is a continuation search the store */ + if (paged_ctrl->cookie_len == 0) { + + ac->store = new_store(private_data); + if (ac->store == NULL) { + talloc_free(h); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + ac->store->req = talloc(ac->store, struct ldb_request); + if (!ac->store->req) + return LDB_ERR_OPERATIONS_ERROR; + + ac->store->req->operation = req->operation; + ac->store->req->op.search.base = req->op.search.base; + ac->store->req->op.search.scope = req->op.search.scope; + ac->store->req->op.search.tree = req->op.search.tree; + ac->store->req->op.search.attrs = req->op.search.attrs; + ac->store->req->controls = req->controls; + + /* save it locally and remove it from the list */ + /* we do not need to replace them later as we + * are keeping the original req intact */ + if (!save_controls(control, ac->store->req, &saved_controls)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->store->req->context = ac; + ac->store->req->callback = paged_search_callback; + ldb_set_timeout_from_prev_req(module->ldb, req, ac->store->req); + + ret = ldb_next_request(module, ac->store->req); + + } else { + struct results_store *current = NULL; + + for (current = private_data->store; current; current = current->next) { + if (strcmp(current->cookie, paged_ctrl->cookie) == 0) { + current->timestamp = time(NULL); + break; + } + } + if (current == NULL) { + talloc_free(h); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + ac->store = current; + ret = LDB_SUCCESS; + } + + req->handle = h; + + /* check if it is an abandon */ + if (ac->size == 0) { + talloc_free(ac->store); + h->status = LDB_SUCCESS; + h->state = LDB_ASYNC_DONE; + return LDB_SUCCESS; + } + + /* TODO: age out old outstanding requests */ + + return ret; + +} + +static int paged_results(struct ldb_handle *handle) +{ + struct paged_context *ac; + struct ldb_paged_control *paged; + struct ldb_reply *ares; + struct message_store *msg; + int i, num_ctrls, ret; + + ac = talloc_get_type(handle->private_data, struct paged_context); + + if (ac->store == NULL) + return LDB_ERR_OPERATIONS_ERROR; + + while (ac->store->num_entries > 0 && ac->size > 0) { + msg = ac->store->first; + ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r); + if (ret != LDB_SUCCESS) { + handle->status = ret; + handle->state = LDB_ASYNC_DONE; + return ret; + } + + ac->store->first = msg->next; + talloc_free(msg); + ac->store->num_entries--; + ac->size--; + } + + handle->state = LDB_ASYNC_DONE; + + while (ac->store->first_ref != NULL) { + msg = ac->store->first_ref; + ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r); + if (ret != LDB_SUCCESS) { + handle->status = ret; + handle->state = LDB_ASYNC_DONE; + return ret; + } + + ac->store->first_ref = msg->next; + talloc_free(msg); + } + + ares = talloc_zero(ac->store, struct ldb_reply); + if (ares == NULL) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; + } + num_ctrls = 2; + i = 0; + + if (ac->store->controls != NULL) { + ares->controls = ac->store->controls; + while (ares->controls[i]) i++; /* counting */ + + ares->controls = talloc_move(ares, &ac->store->controls); + num_ctrls += i; + } + + ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, num_ctrls); + if (ares->controls == NULL) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; + } + + ares->controls[i] = talloc(ares->controls, struct ldb_control); + if (ares->controls[i] == NULL) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; + } + + ares->controls[i]->oid = talloc_strdup(ares->controls[i], LDB_CONTROL_PAGED_RESULTS_OID); + if (ares->controls[i]->oid == NULL) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; + } + + ares->controls[i]->critical = 0; + ares->controls[i + 1] = NULL; + + paged = talloc(ares->controls[i], struct ldb_paged_control); + if (paged == NULL) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; + } + + ares->controls[i]->data = paged; + + if (ac->size > 0) { + paged->size = 0; + paged->cookie = NULL; + paged->cookie_len = 0; + } else { + paged->size = ac->store->num_entries; + paged->cookie = talloc_strdup(paged, ac->store->cookie); + paged->cookie_len = strlen(paged->cookie) + 1; + } + + ares->type = LDB_REPLY_DONE; + + ret = ac->up_callback(ac->module->ldb, ac->up_context, ares); + + handle->status = ret; + + return ret; +} + +static int paged_wait_once(struct ldb_handle *handle) { + struct paged_context *ac; + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (handle->state == LDB_ASYNC_DONE) { + return handle->status; + } + + handle->state = LDB_ASYNC_PENDING; + + ac = talloc_get_type(handle->private_data, struct paged_context); + + if (ac->store->req->handle->state == LDB_ASYNC_DONE) { + /* if lower level is finished we do not need to call it anymore */ + /* return all we have until size == 0 or we empty storage */ + ret = paged_results(handle); + + /* we are done, if num_entries is zero free the storage + * as that mean we delivered the last batch */ + if (ac->store->num_entries == 0) { + talloc_free(ac->store); + } + + return ret; + } + + ret = ldb_wait(ac->store->req->handle, LDB_WAIT_NONE); + if (ret != LDB_SUCCESS) { + handle->state = LDB_ASYNC_DONE; + handle->status = ret; + return ret; + } + + handle->status = ret; + + if (ac->store->num_entries >= ac->size || + ac->store->req->handle->state == LDB_ASYNC_DONE) { + + ret = paged_results(handle); + + /* we are done, if num_entries is zero free the storage + * as that mean we delivered the last batch */ + if (ac->store->num_entries == 0) { + talloc_free(ac->store); + } + } + + return ret; +} + +static int paged_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (type == LDB_WAIT_ALL) { + while (handle->state != LDB_ASYNC_DONE) { + ret = paged_wait_once(handle); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return handle->status; + } + + return paged_wait_once(handle); +} + +static int paged_request_init(struct ldb_module *module) +{ + struct private_data *data; + struct ldb_request *req; + int ret; + + data = talloc(module, struct private_data); + if (data == NULL) { + return LDB_ERR_OTHER; + } + + data->next_free_id = 1; + data->store = NULL; + module->private_data = data; + + req = talloc(module, struct ldb_request); + if (req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_REQ_REGISTER_CONTROL; + req->op.reg_control.oid = LDB_CONTROL_PAGED_RESULTS_OID; + req->controls = NULL; + + ret = ldb_request(module->ldb, req); + if (ret != LDB_SUCCESS) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "paged_request: Unable to register control with rootdse!\n"); + } + + talloc_free(req); + return ldb_next_init(module); +} + +const struct ldb_module_ops ldb_paged_results_module_ops = { + .name = "paged_results", + .search = paged_search, + .wait = paged_wait, + .init_context = paged_request_init +}; diff --git a/ldb/modules/paged_searches.c b/ldb/modules/paged_searches.c new file mode 100644 index 000000000..40e87f70d --- /dev/null +++ b/ldb/modules/paged_searches.c @@ -0,0 +1,463 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005-2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: paged_searches + * + * Component: ldb paged searches module + * + * Description: this module detects if the remote ldap server supports + * paged results and use them to transparently access all objects + * + * Author: Simo Sorce + */ + +#include "includes.h" +#include "ldb_includes.h" + +#define PS_DEFAULT_PAGE_SIZE 500 +/* 500 objects per query seem to be a decent compromise + * the default AD limit per request is 1000 entries */ + +struct private_data { + + bool paged_supported; +}; + +struct ps_context { + struct ldb_module *module; + void *up_context; + int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *); + + struct ldb_request *orig_req; + + struct ldb_request *new_req; + + bool pending; + + char **saved_referrals; + int num_referrals; +}; + +static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +{ + struct ps_context *ac; + struct ldb_handle *h; + + h = talloc_zero(mem_ctx, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc_zero(h, struct ps_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->module = module; + ac->up_context = context; + ac->up_callback = callback; + + ac->pending = false; + + + + ac->saved_referrals = NULL; + ac->num_referrals = 0; + + return h; +} + +static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac) +{ + struct ldb_paged_control *rep_control, *req_control; + + /* look up our paged control */ + if (!ares->controls || strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[0]->oid) != 0) { + /* something wrong here */ + return LDB_ERR_OPERATIONS_ERROR; + } + + rep_control = talloc_get_type(ares->controls[0]->data, struct ldb_paged_control); + if (rep_control->cookie_len == 0) { + /* we are done */ + ac->pending = false; + return LDB_SUCCESS; + } + + /* more processing required */ + /* let's fill in the request control with the new cookie */ + /* if there's a reply control we must find a request + * control matching it */ + + if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ac->new_req->controls[0]->oid) != 0) { + /* something wrong here */ + return LDB_ERR_OPERATIONS_ERROR; + } + + req_control = talloc_get_type(ac->new_req->controls[0]->data, struct ldb_paged_control); + + if (req_control->cookie) { + talloc_free(req_control->cookie); + } + + req_control->cookie = talloc_memdup(req_control, + rep_control->cookie, + rep_control->cookie_len); + req_control->cookie_len = rep_control->cookie_len; + + ac->pending = true; + return LDB_SUCCESS; +} + +static int store_referral(char *referral, struct ps_context *ac) +{ + ac->saved_referrals = talloc_realloc(ac, ac->saved_referrals, char *, ac->num_referrals + 2); + if (!ac->saved_referrals) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->saved_referrals[ac->num_referrals] = talloc_strdup(ac->saved_referrals, referral); + if (!ac->saved_referrals[ac->num_referrals]) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->num_referrals++; + ac->saved_referrals[ac->num_referrals] = NULL; + + return LDB_SUCCESS; +} + +static int send_referrals(struct ldb_context *ldb, struct ps_context *ac) +{ + struct ldb_reply *ares; + int i; + + for (i = 0; i < ac->num_referrals; i++) { + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ares->type = LDB_REPLY_REFERRAL; + ares->referral = ac->saved_referrals[i]; + + ac->up_callback(ldb, ac->up_context, ares); + } + + return LDB_SUCCESS; +} + +static int ps_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct ps_context *ac = NULL; + int ret = LDB_ERR_OPERATIONS_ERROR; + + if (!context || !ares) { + ldb_set_errstring(ldb, "NULL Context or Result in callback"); + goto error; + } + + ac = talloc_get_type(context, struct ps_context); + + switch (ares->type) { + case LDB_REPLY_ENTRY: + ac->up_callback(ldb, ac->up_context, ares); + break; + + case LDB_REPLY_REFERRAL: + ret = store_referral(ares->referral, ac); + if (ret != LDB_SUCCESS) { + goto error; + } + break; + + case LDB_REPLY_DONE: + ret = check_ps_continuation(ares, ac); + if (ret != LDB_SUCCESS) { + goto error; + } + if (!ac->pending) { + /* send referrals */ + ret = send_referrals(ldb, ac); + if (ret != LDB_SUCCESS) { + goto error; + } + + /* send REPLY_DONE */ + ac->up_callback(ldb, ac->up_context, ares); + } + break; + default: + goto error; + } + + return LDB_SUCCESS; + +error: + talloc_free(ares); + return ret; +} + +static int ps_search(struct ldb_module *module, struct ldb_request *req) +{ + struct private_data *private_data; + struct ldb_paged_control *control; + struct ps_context *ac; + struct ldb_handle *h; + + private_data = talloc_get_type(module->private_data, struct private_data); + + /* check if paging is supported and if there is a any control */ + if (!private_data || !private_data->paged_supported || req->controls) { + /* do not touch this request paged controls not + * supported or explicit controls have been set or we + * are just not setup yet */ + return ldb_next_request(module, req); + } + + if (!req->callback || !req->context) { + ldb_set_errstring(module->ldb, + "Async interface called with NULL callback function or NULL context"); + return LDB_ERR_OPERATIONS_ERROR; + } + + h = init_handle(req, module, req->context, req->callback); + if (!h) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct ps_context); + + ac->new_req = talloc(ac, struct ldb_request); + if (!ac->new_req) return LDB_ERR_OPERATIONS_ERROR; + + ac->new_req->controls = talloc_array(ac->new_req, struct ldb_control *, 2); + if (!ac->new_req->controls) return LDB_ERR_OPERATIONS_ERROR; + + ac->new_req->controls[0] = talloc(ac->new_req->controls, struct ldb_control); + if (!ac->new_req->controls[0]) return LDB_ERR_OPERATIONS_ERROR; + + control = talloc(ac->new_req->controls[0], struct ldb_paged_control); + if (!control) return LDB_ERR_OPERATIONS_ERROR; + + control->size = PS_DEFAULT_PAGE_SIZE; + control->cookie = NULL; + control->cookie_len = 0; + + ac->new_req->controls[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID; + ac->new_req->controls[0]->critical = 1; + ac->new_req->controls[0]->data = control; + + ac->new_req->controls[1] = NULL; + + ac->new_req->operation = req->operation; + ac->new_req->op.search.base = req->op.search.base; + ac->new_req->op.search.scope = req->op.search.scope; + ac->new_req->op.search.tree = req->op.search.tree; + ac->new_req->op.search.attrs = req->op.search.attrs; + ac->new_req->context = ac; + ac->new_req->callback = ps_callback; + ldb_set_timeout_from_prev_req(module->ldb, req, ac->new_req); + + req->handle = h; + + return ldb_next_request(module, ac->new_req); +} + +static int ps_continuation(struct ldb_handle *handle) +{ + struct ps_context *ac; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac = talloc_get_type(handle->private_data, struct ps_context); + + /* reset the requests handle */ + ac->new_req->handle = NULL; + + return ldb_next_request(handle->module, ac->new_req); +} + +static int ps_wait_once(struct ldb_handle *handle) +{ + struct ps_context *ac; + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (handle->state == LDB_ASYNC_DONE) { + return handle->status; + } + + handle->state = LDB_ASYNC_PENDING; + handle->status = LDB_SUCCESS; + + ac = talloc_get_type(handle->private_data, struct ps_context); + + ret = ldb_wait(ac->new_req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + + if (ac->new_req->handle->status != LDB_SUCCESS) { + handle->status = ac->new_req->handle->status; + goto done; + } + + if (ac->new_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + /* see if we need to send another request for the next batch */ + if (ac->pending) { + ret = ps_continuation(handle); + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + + /* continue the search with the next request */ + return LDB_SUCCESS; + } + + ret = LDB_SUCCESS; + +done: + handle->state = LDB_ASYNC_DONE; + return ret; +} + +static int ps_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (type == LDB_WAIT_ALL) { + while (handle->state != LDB_ASYNC_DONE) { + ret = ps_wait_once(handle); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return handle->status; + } + return ps_wait_once(handle); +} + +static int check_supported_paged(struct ldb_context *ldb, void *context, + struct ldb_reply *ares) +{ + struct private_data *data; + data = talloc_get_type(context, + struct private_data); + if (ares->type == LDB_REPLY_ENTRY) { + if (ldb_msg_check_string_attribute(ares->message, + "supportedControl", + LDB_CONTROL_PAGED_RESULTS_OID)) { + data->paged_supported = true; + } + } + return LDB_SUCCESS; +} + + +static int ps_init(struct ldb_module *module) +{ + static const char *attrs[] = { "supportedControl", NULL }; + struct private_data *data; + int ret; + struct ldb_request *req; + + data = talloc(module, struct private_data); + if (data == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return LDB_ERR_OTHER; + } + module->private_data = data; + data->paged_supported = false; + + req = talloc(module, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_SEARCH; + req->op.search.base = ldb_dn_new(req, module->ldb, ""); + req->op.search.scope = LDB_SCOPE_BASE; + + req->op.search.tree = ldb_parse_tree(req, "objectClass=*"); + if (req->op.search.tree == NULL) { + ldb_set_errstring(module->ldb, "Unable to parse search expression"); + talloc_free(req); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->op.search.attrs = attrs; + req->controls = NULL; + req->context = data; + req->callback = check_supported_paged; + ldb_set_timeout(module->ldb, req, 0); /* use default timeout */ + + ret = ldb_next_request(module, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + if (ret != LDB_SUCCESS) { + return ret; + } + + return ldb_next_init(module); +} + +_PUBLIC_ const struct ldb_module_ops ldb_paged_searches_module_ops = { + .name = "paged_searches", + .search = ps_search, + .wait = ps_wait, + .init_context = ps_init +}; diff --git a/ldb/modules/rdn_name.c b/ldb/modules/rdn_name.c new file mode 100644 index 000000000..65c044c0f --- /dev/null +++ b/ldb/modules/rdn_name.c @@ -0,0 +1,335 @@ +/* + ldb database library + + Copyright (C) Andrew Bartlet 2005 + Copyright (C) Simo Sorce 2006 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: rdb_name + * + * Component: ldb rdn name module + * + * Description: keep a consistent name attribute on objects manpulations + * + * Author: Andrew Bartlet + * + * Modifications: + * - made the module async + * Simo Sorce Mar 2006 + */ + +#include "ldb_includes.h" + +static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name) +{ + int i; + + for (i = 0; i < msg->num_elements; i++) { + if (ldb_attr_cmp(name, msg->elements[i].name) == 0) { + return &msg->elements[i]; + } + } + + return NULL; +} + +static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_request *down_req; + struct ldb_message *msg; + struct ldb_message_element *attribute; + const char *rdn_name; + struct ldb_val rdn_val; + int i, ret; + + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n"); + + /* do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.add.message->dn)) { + return ldb_next_request(module, req); + } + + down_req = talloc(req, struct ldb_request); + if (down_req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + *down_req = *req; + + down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + rdn_name = ldb_dn_get_rdn_name(msg->dn); + if (rdn_name == NULL) { + talloc_free(down_req); + return LDB_ERR_OPERATIONS_ERROR; + } + + rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn)); + + /* Perhaps someone above us tried to set this? */ + if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) { + attribute->num_values = 0; + } + + if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { + talloc_free(down_req); + return LDB_ERR_OPERATIONS_ERROR; + } + + attribute = rdn_name_find_attribute(msg, rdn_name); + + if (!attribute) { + if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { + talloc_free(down_req); + return LDB_ERR_OPERATIONS_ERROR; + } + } else { + const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, rdn_name); + + for (i = 0; i < attribute->num_values; i++) { + if (a->syntax->comparison_fn(module->ldb, msg, &rdn_val, &attribute->values[i]) == 0) { + /* overwrite so it matches in case */ + attribute->values[i] = rdn_val; + break; + } + } + if (i == attribute->num_values) { + ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, + "RDN mismatch on %s: %s (%s)", + ldb_dn_get_linearized(msg->dn), rdn_name, rdn_val.data); + talloc_free(down_req); + /* Match AD's error here */ + return LDB_ERR_INVALID_DN_SYNTAX; + } + } + + /* go on with the call chain */ + ret = ldb_next_request(module, down_req); + + /* do not free down_req as the call results may be linked to it, + * it will be freed when the upper level request get freed */ + if (ret == LDB_SUCCESS) { + req->handle = down_req->handle; + } + + return ret; +} + +struct rename_context { + + enum {RENAME_RENAME, RENAME_MODIFY} step; + struct ldb_request *orig_req; + struct ldb_request *down_req; + struct ldb_request *mod_req; +}; + +static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_handle *h; + struct rename_context *ac; + + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n"); + + /* do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.rename.newdn)) { + return ldb_next_request(module, req); + } + + h = talloc_zero(req, struct ldb_handle); + if (h == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + h->module = module; + + ac = talloc_zero(h, struct rename_context); + if (ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->orig_req = req; + ac->down_req = talloc(req, struct ldb_request); + if (ac->down_req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + *(ac->down_req) = *req; + + ac->step = RENAME_RENAME; + + req->handle = h; + + /* rename first, modify "name" if rename is ok */ + return ldb_next_request(module, ac->down_req); +} + +static int rdn_name_rename_do_mod(struct ldb_handle *h) { + + struct rename_context *ac; + const char *rdn_name; + struct ldb_val rdn_val; + struct ldb_message *msg; + + ac = talloc_get_type(h->private_data, struct rename_context); + + ac->mod_req = talloc_zero(ac, struct ldb_request); + + ac->mod_req->operation = LDB_MODIFY; + ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->dn = ldb_dn_copy(msg, ac->orig_req->op.rename.newdn); + if (msg->dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + rdn_name = ldb_dn_get_rdn_name(ac->orig_req->op.rename.newdn); + if (rdn_name == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->orig_req->op.rename.newdn)); + + if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ldb_set_timeout_from_prev_req(h->module->ldb, ac->orig_req, ac->mod_req); + + ac->step = RENAME_MODIFY; + + /* do the mod call */ + return ldb_request(h->module->ldb, ac->mod_req); +} + +static int rdn_name_wait_once(struct ldb_handle *handle) +{ + struct rename_context *ac; + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (handle->state == LDB_ASYNC_DONE) { + return handle->status; + } + + handle->state = LDB_ASYNC_PENDING; + handle->status = LDB_SUCCESS; + + ac = talloc_get_type(handle->private_data, struct rename_context); + + switch(ac->step) { + case RENAME_RENAME: + ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE); + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->down_req->handle->status != LDB_SUCCESS) { + handle->status = ac->down_req->handle->status; + goto done; + } + + if (ac->down_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + /* rename operation done */ + return rdn_name_rename_do_mod(handle); + + case RENAME_MODIFY: + ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE); + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (ac->mod_req->handle->status != LDB_SUCCESS) { + handle->status = ac->mod_req->handle->status; + goto done; + } + + if (ac->mod_req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + break; + + default: + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + ret = LDB_SUCCESS; + +done: + handle->state = LDB_ASYNC_DONE; + return ret; +} + +static int rdn_name_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (type == LDB_WAIT_ALL) { + while (handle->state != LDB_ASYNC_DONE) { + ret = rdn_name_wait_once(handle); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return handle->status; + } + + return rdn_name_wait_once(handle); +} + +const struct ldb_module_ops ldb_rdn_name_module_ops = { + .name = "rdn_name", + .add = rdn_name_add, + .rename = rdn_name_rename, + .wait = rdn_name_wait +}; diff --git a/ldb/modules/skel.c b/ldb/modules/skel.c new file mode 100644 index 000000000..0cd29ac4b --- /dev/null +++ b/ldb/modules/skel.c @@ -0,0 +1,131 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb skel module + * + * Description: example module + * + * Author: Simo Sorce + */ + +#include "ldb_includes.h" + +struct private_data { + + char *some_private_data; +}; + +/* search */ +static int skel_search(struct ldb_module *module, struct ldb_request *req) +{ + return ldb_next_request(module, req); +} + +/* add */ +static int skel_add(struct ldb_module *module, struct ldb_request *req){ + return ldb_next_request(module, req); +} + +/* modify */ +static int skel_modify(struct ldb_module *module, struct ldb_request *req) +{ + return ldb_next_request(module, req); +} + +/* delete */ +static int skel_delete(struct ldb_module *module, struct ldb_request *req) +{ + return ldb_next_request(module, req); +} + +/* rename */ +static int skel_rename(struct ldb_module *module, struct ldb_request *req) +{ + return ldb_next_request(module, req); +} + +/* start a transaction */ +static int skel_start_trans(struct ldb_module *module) +{ + return ldb_next_start_trans(module); +} + +/* end a transaction */ +static int skel_end_trans(struct ldb_module *module) +{ + return ldb_next_end_trans(module); +} + +/* delete a transaction */ +static int skel_del_trans(struct ldb_module *module) +{ + return ldb_next_del_trans(module); +} + +static int skel_destructor(struct ldb_module *ctx) +{ + struct private_data *data = talloc_get_type(ctx->private_data, struct private_data); + /* put your clean-up functions here */ + if (data->some_private_data) talloc_free(data->some_private_data); + return 0; +} + +static int skel_request(struct ldb_module *module, struct ldb_request *req) +{ + return ldb_next_request(module, req); +} + +static int skel_init(struct ldb_module *module) +{ + struct private_data *data; + + data = talloc(module, struct private_data); + if (data == NULL) { + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + data->some_private_data = NULL; + module->private_data = data; + + talloc_set_destructor (module, skel_destructor); + + return ldb_next_init(module); +} + +const struct ldb_module_ops ldb_skel_module_ops = { + .name = "skel", + .init_context = skel_init, + .search = skel_search, + .add = skel_add, + .modify = skel_modify, + .del = skel_delete, + .rename = skel_rename, + .request = skel_request, + .start_transaction = skel_start_trans, + .end_transaction = skel_end_trans, + .del_transaction = skel_del_trans, +}; diff --git a/ldb/modules/sort.c b/ldb/modules/sort.c new file mode 100644 index 000000000..746befa55 --- /dev/null +++ b/ldb/modules/sort.c @@ -0,0 +1,458 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb server side sort control module + * + * Description: this module sorts the results of a search + * + * Author: Simo Sorce + */ + +#include "ldb_includes.h" + +struct opaque { + struct ldb_context *ldb; + const struct ldb_attrib_handler *h; + const char *attribute; + int reverse; + int result; +}; + +struct sort_context { + struct ldb_module *module; + void *up_context; + int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *); + + char *attributeName; + char *orderingRule; + int reverse; + + struct ldb_request *req; + struct ldb_message **msgs; + char **referrals; + struct ldb_control **controls; + int num_msgs; + int num_refs; + + const struct ldb_schema_attribute *a; + int sort_result; +}; + +static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +{ + struct sort_context *ac; + struct ldb_handle *h; + + h = talloc_zero(mem_ctx, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc_zero(h, struct sort_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->module = module; + ac->up_context = context; + ac->up_callback = callback; + + return h; +} + +static int build_response(void *mem_ctx, struct ldb_control ***ctrls, int result, const char *desc) +{ + struct ldb_control **controls; + struct ldb_sort_resp_control *resp; + int i; + + if (*ctrls) { + controls = *ctrls; + for (i = 0; controls[i]; i++); + controls = talloc_realloc(mem_ctx, controls, struct ldb_control *, i + 2); + } else { + i = 0; + controls = talloc_array(mem_ctx, struct ldb_control *, 2); + } + if (! controls ) + return LDB_ERR_OPERATIONS_ERROR; + + *ctrls = controls; + + controls[i+1] = NULL; + controls[i] = talloc(controls, struct ldb_control); + if (! controls[i] ) + return LDB_ERR_OPERATIONS_ERROR; + + controls[i]->oid = LDB_CONTROL_SORT_RESP_OID; + controls[i]->critical = 0; + + resp = talloc(controls[i], struct ldb_sort_resp_control); + if (! resp ) + return LDB_ERR_OPERATIONS_ERROR; + + resp->result = result; + resp->attr_desc = talloc_strdup(resp, desc); + + if (! resp->attr_desc ) + return LDB_ERR_OPERATIONS_ERROR; + + controls[i]->data = resp; + + return LDB_SUCCESS; +} + +static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque) +{ + struct sort_context *ac = talloc_get_type(opaque, struct sort_context); + struct ldb_message_element *el1, *el2; + + if (ac->sort_result != 0) { + /* an error occurred previously, + * let's exit the sorting by returning always 0 */ + return 0; + } + + el1 = ldb_msg_find_element(*msg1, ac->attributeName); + el2 = ldb_msg_find_element(*msg2, ac->attributeName); + + if (!el1 || !el2) { + /* the attribute was not found return and + * set an error */ + ac->sort_result = 53; + return 0; + } + + if (ac->reverse) + return ac->a->syntax->comparison_fn(ac->module->ldb, ac, &el2->values[0], &el1->values[0]); + + return ac->a->syntax->comparison_fn(ac->module->ldb, ac, &el1->values[0], &el2->values[0]); +} + +static int server_sort_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct sort_context *ac = NULL; + + if (!context || !ares) { + ldb_set_errstring(ldb, "NULL Context or Result in callback"); + goto error; + } + + ac = talloc_get_type(context, struct sort_context); + + if (ares->type == LDB_REPLY_ENTRY) { + ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2); + if (! ac->msgs) { + goto error; + } + + ac->msgs[ac->num_msgs + 1] = NULL; + + ac->msgs[ac->num_msgs] = talloc_move(ac->msgs, &ares->message); + ac->num_msgs++; + } + + if (ares->type == LDB_REPLY_REFERRAL) { + ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2); + if (! ac->referrals) { + goto error; + } + + ac->referrals[ac->num_refs + 1] = NULL; + ac->referrals[ac->num_refs] = talloc_move(ac->referrals, &ares->referral); + + ac->num_refs++; + } + + if (ares->type == LDB_REPLY_DONE) { + ac->controls = talloc_move(ac, &ares->controls); + } + + talloc_free(ares); + return LDB_SUCCESS; + +error: + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; +} + +static int server_sort_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_control *control; + struct ldb_server_sort_control **sort_ctrls; + struct ldb_control **saved_controls; + struct sort_context *ac; + struct ldb_handle *h; + int ret; + + /* check if there's a paged request control */ + control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID); + if (control == NULL) { + /* not found go on */ + return ldb_next_request(module, req); + } + + req->handle = NULL; + + if (!req->callback || !req->context) { + ldb_set_errstring(module->ldb, + "Async interface called with NULL callback function or NULL context"); + return LDB_ERR_OPERATIONS_ERROR; + } + + h = init_handle(req, module, req->context, req->callback); + if (!h) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac = talloc_get_type(h->private_data, struct sort_context); + + sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *); + if (!sort_ctrls) { + return LDB_ERR_PROTOCOL_ERROR; + } + + /* FIXME: we do not support more than one attribute for sorting right now */ + /* FIXME: we need to check if the attribute type exist or return an error */ + + if (sort_ctrls[1] != NULL) { + if (control->critical) { + struct ldb_reply *ares; + + ares = talloc_zero(req, struct ldb_reply); + if (!ares) + return LDB_ERR_OPERATIONS_ERROR; + + /* 53 = unwilling to perform */ + ares->type = LDB_REPLY_DONE; + if ((ret = build_response(ares, &ares->controls, 53, "sort control is not complete yet")) != LDB_SUCCESS) { + return ret; + } + + h->status = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + h->state = LDB_ASYNC_DONE; + ret = ac->up_callback(module->ldb, ac->up_context, ares); + + return ret; + } else { + /* just pass the call down and don't do any sorting */ + ldb_next_request(module, req); + } + } + + ac->attributeName = sort_ctrls[0]->attributeName; + ac->orderingRule = sort_ctrls[0]->orderingRule; + ac->reverse = sort_ctrls[0]->reverse; + + ac->req = talloc(req, struct ldb_request); + if (!ac->req) + return LDB_ERR_OPERATIONS_ERROR; + + ac->req->operation = req->operation; + ac->req->op.search.base = req->op.search.base; + ac->req->op.search.scope = req->op.search.scope; + ac->req->op.search.tree = req->op.search.tree; + ac->req->op.search.attrs = req->op.search.attrs; + ac->req->controls = req->controls; + + /* save it locally and remove it from the list */ + /* we do not need to replace them later as we + * are keeping the original req intact */ + if (!save_controls(control, ac->req, &saved_controls)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->req->context = ac; + ac->req->callback = server_sort_search_callback; + ldb_set_timeout_from_prev_req(module->ldb, req, ac->req); + + req->handle = h; + + return ldb_next_request(module, ac->req); +} + +static int server_sort_results(struct ldb_handle *handle) +{ + struct sort_context *ac; + struct ldb_reply *ares; + int i, ret; + + ac = talloc_get_type(handle->private_data, struct sort_context); + + ac->a = ldb_schema_attribute_by_name(ac->module->ldb, ac->attributeName); + ac->sort_result = 0; + + ldb_qsort(ac->msgs, ac->num_msgs, + sizeof(struct ldb_message *), + ac, (ldb_qsort_cmp_fn_t)sort_compare); + + for (i = 0; i < ac->num_msgs; i++) { + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; + } + + ares->type = LDB_REPLY_ENTRY; + ares->message = talloc_move(ares, &ac->msgs[i]); + + handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares); + if (handle->status != LDB_SUCCESS) { + return handle->status; + } + } + + for (i = 0; i < ac->num_refs; i++) { + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; + } + + ares->type = LDB_REPLY_REFERRAL; + ares->referral = talloc_move(ares, &ac->referrals[i]); + + handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares); + if (handle->status != LDB_SUCCESS) { + return handle->status; + } + } + + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; + } + + ares->type = LDB_REPLY_DONE; + ares->controls = talloc_move(ares, &ac->controls); + + handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares); + if (handle->status != LDB_SUCCESS) { + return handle->status; + } + + if ((ret = build_response(ac, &ac->controls, ac->sort_result, "sort control is not complete yet")) != LDB_SUCCESS) { + return ret; + } + + return LDB_SUCCESS; +} + +static int server_sort_wait_once(struct ldb_handle *handle) +{ + struct sort_context *ac; + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac = talloc_get_type(handle->private_data, struct sort_context); + + ret = ldb_wait(ac->req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + return ret; + } + + handle->state = ac->req->handle->state; + handle->status = ac->req->handle->status; + + if (handle->status != LDB_SUCCESS) { + return handle->status; + } + + if (handle->state == LDB_ASYNC_DONE) { + ret = server_sort_results(handle); + } + + return ret; +} + +static int server_sort_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + int ret; + + if (!handle || !handle->private_data) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (type == LDB_WAIT_ALL) { + while (handle->state != LDB_ASYNC_DONE) { + ret = server_sort_wait_once(handle); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return handle->status; + } + + return server_sort_wait_once(handle); +} + +static int server_sort_init(struct ldb_module *module) +{ + struct ldb_request *req; + int ret; + + req = talloc(module, struct ldb_request); + if (req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_REQ_REGISTER_CONTROL; + req->op.reg_control.oid = LDB_CONTROL_SERVER_SORT_OID; + req->controls = NULL; + + ret = ldb_request(module->ldb, req); + if (ret != LDB_SUCCESS) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "server_sort: Unable to register control with rootdse!\n"); + } + + talloc_free(req); + return ldb_next_init(module); +} + +const struct ldb_module_ops ldb_server_sort_module_ops = { + .name = "server_sort", + .search = server_sort_search, + .wait = server_sort_wait, + .init_context = server_sort_init +}; diff --git a/ldb/nssldb/README.txt b/ldb/nssldb/README.txt new file mode 100644 index 000000000..ddba62b38 --- /dev/null +++ b/ldb/nssldb/README.txt @@ -0,0 +1,34 @@ + +This test code requires a tdb that is configured for to use the asq module. +You can do that adding the following record to a tdb: + +dn: @MODULES +@LIST: asq + +Other modules can be used as well (like rdn_name for example) + +The uidNumber 0 and the gidNumber 0 are considered invalid. + +The user records should contain the followin attributes: +uid (required) the user name +userPassword (optional) the user password (if not present "LDB" is + returned in the password field) +uidNumber (required) the user uid +gidNumber (required) the user primary gid +gecos (optional) the GECOS +homeDirectory (required) the home directory +loginShell (required) the login shell +memberOf (required) all the groups the user is member of should + be reported here using their DNs. The + primary group as well. + +The group accounts should contain the following attributes: +cn (required) the group name +uesrPassword (optional) the group password (if not present "LDB" is + returned in the password field) +gidNumber (required) the group gid +member (optional) the DNs of the member users, also the ones + that have this group as primary + + +SSS diff --git a/ldb/nssldb/ldb-grp.c b/ldb/nssldb/ldb-grp.c new file mode 100644 index 000000000..71e27a916 --- /dev/null +++ b/ldb/nssldb/ldb-grp.c @@ -0,0 +1,425 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "ldb-nss.h" + +extern struct _ldb_nss_context *_ldb_nss_ctx; + +const char *_ldb_nss_gr_attrs[] = { + "cn", + "userPassword", + "gidNumber", + NULL +}; + +const char *_ldb_nss_mem_attrs[] = { + "uid", + NULL +}; + +#define _NSS_LDB_ENOMEM(amem) \ + do { \ + if ( ! amem) { \ + errno = ENOMEM; \ + talloc_free(memctx); \ + return NSS_STATUS_UNAVAIL; \ + } \ + } while(0) + +/* This setgrent, getgrent, endgrent is not very efficient */ + +NSS_STATUS _nss_ldb_setgrent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->gr_cur = 0; + if (_ldb_nss_ctx->gr_res != NULL) { + talloc_free(_ldb_nss_ctx->gr_res); + _ldb_nss_ctx->gr_res = NULL; + } + + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + _LDB_NSS_GRENT_FILTER, + _ldb_nss_gr_attrs, + &_ldb_nss_ctx->gr_res); + if (ret != LDB_SUCCESS) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_endgrent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->gr_cur = 0; + if (_ldb_nss_ctx->gr_res) { + talloc_free(_ldb_nss_ctx->gr_res); + _ldb_nss_ctx->gr_res = NULL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getgrent_r(struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + struct ldb_result *res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + *errnop = 0; + + if (_ldb_nss_ctx->gr_cur >= _ldb_nss_ctx->gr_res->count) { + /* already returned all entries */ + return NSS_STATUS_NOTFOUND; + } + + res = talloc_zero(_ldb_nss_ctx->gr_res, struct ldb_result); + if ( ! res) { + errno = *errnop = ENOMEM; + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + return NSS_STATUS_UNAVAIL; + } + + ret = _ldb_nss_group_request(&res, + _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + talloc_free(res); + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + return ret; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur], + res); + + talloc_free(res); + + if (ret != NSS_STATUS_SUCCESS) { + if (ret != NSS_STATUS_TRYAGAIN) { + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + } + return ret; + } + + /* this entry is ok, increment counter to nex entry */ + _ldb_nss_ctx->gr_cur++; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getgrnam_r(const char *name, struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + TALLOC_CTX *ctx; + struct ldb_result *gr_res; + struct ldb_result *mem_res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + ctx = talloc_new(_ldb_nss_ctx->ldb); + if ( ! ctx) { + *errnop = errno = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(ctx, _LDB_NSS_GRNAM_FILTER, name); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_gr_attrs, + &gr_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(ctx, gr_res); + + /* if none found return */ + if (gr_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (gr_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + mem_res = talloc_zero(ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + gr_res->msgs[0]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + gr_res->msgs[0], + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; +done: + talloc_free(ctx); + return ret; +} + +NSS_STATUS _nss_ldb_getgrgid_r(gid_t gid, struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + TALLOC_CTX *ctx; + struct ldb_result *gr_res; + struct ldb_result *mem_res; + + if (gid == 0) { /* we don't serve root gid by policy */ + *errnop = errno = ENOENT; + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + ctx = talloc_new(_ldb_nss_ctx->ldb); + if ( ! ctx) { + *errnop = errno = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(ctx, _LDB_NSS_GRGID_FILTER, gid); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_gr_attrs, + &gr_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(ctx, gr_res); + + /* if none found return */ + if (gr_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (gr_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + mem_res = talloc_zero(ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + gr_res->msgs[0]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + gr_res->msgs[0], + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; +done: + talloc_free(ctx); + return ret; +} + +NSS_STATUS _nss_ldb_initgroups_dyn(const char *user, gid_t group, long int *start, long int *size, gid_t **groups, long int limit, int *errnop) +{ + int ret; + char *filter; + const char * attrs[] = { "uidNumber", "gidNumber", NULL }; + struct ldb_result *uid_res; + struct ldb_result *mem_res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + mem_res = talloc_zero(_ldb_nss_ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this name */ + filter = talloc_asprintf(mem_res, _LDB_NSS_PWNAM_FILTER, user); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + attrs, + &uid_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(mem_res, uid_res); + + /* if none found return */ + if (uid_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (uid_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + uid_res->msgs[0]->dn, + attrs, + "memberOf"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_initgr(group, + limit, + start, + size, + groups, + errnop, + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; + +done: + talloc_free(mem_res); + return ret; +} diff --git a/ldb/nssldb/ldb-nss.c b/ldb/nssldb/ldb-nss.c new file mode 100644 index 000000000..8f7321031 --- /dev/null +++ b/ldb/nssldb/ldb-nss.c @@ -0,0 +1,395 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "ldb-nss.h" + +struct _ldb_nss_context *_ldb_nss_ctx = NULL; + +NSS_STATUS _ldb_nss_init(void) +{ + int ret; + + pid_t mypid = getpid(); + + if (_ldb_nss_ctx != NULL) { + if (_ldb_nss_ctx->pid == mypid) { + /* already initialized */ + return NSS_STATUS_SUCCESS; + } else { + /* we are in a forked child now, reinitialize */ + talloc_free(_ldb_nss_ctx); + _ldb_nss_ctx = NULL; + } + } + + _ldb_nss_ctx = talloc_named(NULL, 0, "_ldb_nss_ctx(%u)", mypid); + if (_ldb_nss_ctx == NULL) { + return NSS_STATUS_UNAVAIL; + } + + _ldb_nss_ctx->pid = mypid; + + _ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx, NULL); + if (_ldb_nss_ctx->ldb == NULL) { + goto failed; + } + + ret = ldb_connect(_ldb_nss_ctx->ldb, _LDB_NSS_URL, LDB_FLG_RDONLY, NULL); + if (ret != LDB_SUCCESS) { + goto failed; + } + + _ldb_nss_ctx->base = ldb_dn_new(_ldb_nss_ctx, _ldb_nss_ctx->ldb, _LDB_NSS_BASEDN); + if ( ! ldb_dn_validate(_ldb_nss_ctx->base)) { + goto failed; + } + + _ldb_nss_ctx->pw_cur = 0; + _ldb_nss_ctx->pw_res = NULL; + _ldb_nss_ctx->gr_cur = 0; + _ldb_nss_ctx->gr_res = NULL; + + return NSS_STATUS_SUCCESS; + +failed: + /* talloc_free(_ldb_nss_ctx); */ + _ldb_nss_ctx = NULL; + return NSS_STATUS_UNAVAIL; +} + +NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *msg) +{ + int len; + int bufpos; + const char *tmp; + + bufpos = 0; + + /* get username */ + tmp = ldb_msg_find_attr_as_string(msg, "uid", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_name = &buffer[bufpos]; + bufpos += len; + + /* get userPassword */ + tmp = ldb_msg_find_attr_as_string(msg, "userPassword", NULL); + if (tmp == NULL) { + tmp = "LDB"; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_passwd = &buffer[bufpos]; + bufpos += len; + + /* this backend never serves an uid 0 user */ + result->pw_uid = ldb_msg_find_attr_as_int(msg, "uidNumber", 0); + if (result->pw_uid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + result->pw_gid = ldb_msg_find_attr_as_int(msg, "gidNumber", 0); + if (result->pw_gid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + /* get gecos */ + tmp = ldb_msg_find_attr_as_string(msg, "gecos", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_gecos = &buffer[bufpos]; + bufpos += len; + + /* get homeDirectory */ + tmp = ldb_msg_find_attr_as_string(msg, "homeDirectory", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_dir = &buffer[bufpos]; + bufpos += len; + + /* get shell */ + tmp = ldb_msg_find_attr_as_string(msg, "loginShell", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_shell = &buffer[bufpos]; + bufpos += len; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _ldb_nss_fill_group(struct group *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *group, + struct ldb_result *members) +{ + const char *tmp; + size_t len; + size_t bufpos; + size_t lsize; + int i; + + bufpos = 0; + + /* get group name */ + tmp = ldb_msg_find_attr_as_string(group, "cn", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_name = &buffer[bufpos]; + bufpos += len; + + /* get userPassword */ + tmp = ldb_msg_find_attr_as_string(group, "userPassword", NULL); + if (tmp == NULL) { + tmp = "LDB"; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_passwd = &buffer[bufpos]; + bufpos += len; + + result->gr_gid = ldb_msg_find_attr_as_int(group, "gidNumber", 0); + if (result->gr_gid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + /* check if there is enough memory for the list of pointers */ + lsize = (members->count + 1) * sizeof(char *); + + /* align buffer on pointer boundary */ + bufpos += (sizeof(char*) - ((unsigned long)(buffer) % sizeof(char*))); + if ((buflen - bufpos) < lsize) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + + result->gr_mem = (char **)&buffer[bufpos]; + bufpos += lsize; + + for (i = 0; i < members->count; i++) { + tmp = ldb_msg_find_attr_as_string(members->msgs[i], "uid", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_mem[i] = &buffer[bufpos]; + bufpos += len; + } + + result->gr_mem[i] = NULL; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _ldb_nss_fill_initgr(gid_t group, + long int limit, + long int *start, + long int *size, + gid_t **groups, + int *errnop, + struct ldb_result *grlist) +{ + NSS_STATUS ret; + int i; + + for (i = 0; i < grlist->count; i++) { + + if (limit && (*start > limit)) { + /* TODO: warn no all groups were reported */ + *errnop = 0; + ret = NSS_STATUS_SUCCESS; + goto done; + } + + if (*start == *size) { + /* buffer full, enlarge it */ + long int gs; + gid_t *gm; + + gs = (*size) + 32; + if (limit && (gs > limit)) { + gs = limit; + } + + gm = (gid_t *)realloc((*groups), gs * sizeof(gid_t)); + if ( ! gm) { + *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + *groups = gm; + *size = gs; + } + + (*groups)[*start] = ldb_msg_find_attr_as_int(grlist->msgs[i], "gidNumber", 0); + if ((*groups)[*start] == 0 || (*groups)[*start] == group) { + /* skip root group or primary group */ + continue; + } + (*start)++; + + } + + *errnop = 0; + ret = NSS_STATUS_SUCCESS; +done: + return ret; +} + +#define _LDB_NSS_ALLOC_CHECK(mem) do { if (!mem) { errno = ENOMEM; return NSS_STATUS_UNAVAIL; } } while(0) + +NSS_STATUS _ldb_nss_group_request(struct ldb_result **_res, + struct ldb_dn *group_dn, + const char * const *attrs, + const char *mattr) +{ + struct ldb_control **ctrls; + struct ldb_control *ctrl; + struct ldb_asq_control *asqc; + struct ldb_request *req; + int ret; + struct ldb_result *res = *_res; + + ctrls = talloc_array(res, struct ldb_control *, 2); + _LDB_NSS_ALLOC_CHECK(ctrls); + + ctrl = talloc(ctrls, struct ldb_control); + _LDB_NSS_ALLOC_CHECK(ctrl); + + asqc = talloc(ctrl, struct ldb_asq_control); + _LDB_NSS_ALLOC_CHECK(asqc); + + asqc->source_attribute = talloc_strdup(asqc, mattr); + _LDB_NSS_ALLOC_CHECK(asqc->source_attribute); + + asqc->request = 1; + asqc->src_attr_len = strlen(asqc->source_attribute); + ctrl->oid = LDB_CONTROL_ASQ_OID; + ctrl->critical = 1; + ctrl->data = asqc; + ctrls[0] = ctrl; + ctrls[1] = NULL; + + ret = ldb_build_search_req( + &req, + _ldb_nss_ctx->ldb, + res, + group_dn, + LDB_SCOPE_BASE, + "(objectClass=*)", + attrs, + ctrls, + res, + ldb_search_default_callback); + + if (ret != LDB_SUCCESS) { + errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + ldb_set_timeout(_ldb_nss_ctx->ldb, req, 0); + + ret = ldb_request(_ldb_nss_ctx->ldb, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } else { + talloc_free(req); + return NSS_STATUS_UNAVAIL; + } + + talloc_free(req); + return NSS_STATUS_SUCCESS; +} + diff --git a/ldb/nssldb/ldb-nss.h b/ldb/nssldb/ldb-nss.h new file mode 100644 index 000000000..583876fea --- /dev/null +++ b/ldb/nssldb/ldb-nss.h @@ -0,0 +1,84 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef _LDB_NSS +#define _LDB_NSS + +#include "includes.h" +#include "ldb/include/includes.h" + +#include +#include +#include + +#define _LDB_NSS_URL "etc/users.ldb" +#define _LDB_NSS_BASEDN "CN=Users,CN=System" +#define _LDB_NSS_PWENT_FILTER "(&(objectClass=posixAccount)(!(uidNumber=0))(!(gidNumber=0)))" +#define _LDB_NSS_PWUID_FILTER "(&(objectClass=posixAccount)(uidNumber=%d)(!(gidNumber=0)))" +#define _LDB_NSS_PWNAM_FILTER "(&(objectClass=posixAccount)(uid=%s)(!(uidNumber=0))(!(gidNumber=0)))" + +#define _LDB_NSS_GRENT_FILTER "(&(objectClass=posixGroup)(!(gidNumber=0)))" +#define _LDB_NSS_GRGID_FILTER "(&(objectClass=posixGroup)(gidNumber=%d)))" +#define _LDB_NSS_GRNAM_FILTER "(&(objectClass=posixGroup)(cn=%s)(!(gidNumber=0)))" + +typedef enum nss_status NSS_STATUS; + +struct _ldb_nss_context { + + pid_t pid; + + struct ldb_context *ldb; + struct ldb_dn *base; + + int pw_cur; + struct ldb_result *pw_res; + + int gr_cur; + struct ldb_result *gr_res; +}; + +NSS_STATUS _ldb_nss_init(void); + +NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *msg); + +NSS_STATUS _ldb_nss_fill_group(struct group *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *group, + struct ldb_result *members); + +NSS_STATUS _ldb_nss_fill_initgr(gid_t group, + long int limit, + long int *start, + long int *size, + gid_t **groups, + int *errnop, + struct ldb_result *grlist); + +NSS_STATUS _ldb_nss_group_request(struct ldb_result **res, + struct ldb_dn *group_dn, + const char * const *attrs, + const char *mattr); + +#endif /* _LDB_NSS */ diff --git a/ldb/nssldb/ldb-pwd.c b/ldb/nssldb/ldb-pwd.c new file mode 100644 index 000000000..44b0ab21e --- /dev/null +++ b/ldb/nssldb/ldb-pwd.c @@ -0,0 +1,239 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "ldb-nss.h" + +extern struct _ldb_nss_context *_ldb_nss_ctx; + +const char *_ldb_nss_pw_attrs[] = { + "uid", + "userPassword", + "uidNumber", + "gidNumber", + "gecos", + "homeDirectory", + "loginShell", + NULL +}; + +NSS_STATUS _nss_ldb_setpwent(void) +{ + int ret; + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur = 0; + if (_ldb_nss_ctx->pw_res != NULL) { + talloc_free(_ldb_nss_ctx->pw_res); + _ldb_nss_ctx->pw_res = NULL; + } + + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + _LDB_NSS_PWENT_FILTER, + _ldb_nss_pw_attrs, + &_ldb_nss_ctx->pw_res); + if (ret != LDB_SUCCESS) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_endpwent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur = 0; + if (_ldb_nss_ctx->pw_res) { + talloc_free(_ldb_nss_ctx->pw_res); + _ldb_nss_ctx->pw_res = NULL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getpwent_r(struct passwd *result_buf, + char *buffer, + int buflen, + int *errnop) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + *errnop = 0; + + if (_ldb_nss_ctx->pw_cur >= _ldb_nss_ctx->pw_res->count) { + /* already returned all entries */ + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + _ldb_nss_ctx->pw_res->msgs[_ldb_nss_ctx->pw_cur]); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur++; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getpwuid_r(uid_t uid, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + struct ldb_result *res; + + if (uid == 0) { /* we don't serve root uid by policy */ + *errnop = errno = ENOENT; + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWUID_FILTER, uid); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_pw_attrs, + &res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* if none found return */ + if (res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* fill in the passwd struct */ + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + res->msgs[0]); + +done: + talloc_free(filter); + talloc_free(res); + return ret; +} + +NSS_STATUS _nss_ldb_getpwnam_r(const char *name, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + struct ldb_result *res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + /* build the filter for this name */ + filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWNAM_FILTER, name); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_pw_attrs, + &res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* if none found return */ + if (res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* fill in the passwd struct */ + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + res->msgs[0]); + +done: + talloc_free(filter); + talloc_free(res); + return ret; +} + diff --git a/ldb/python.mk b/ldb/python.mk new file mode 100644 index 000000000..45f4f044b --- /dev/null +++ b/ldb/python.mk @@ -0,0 +1,10 @@ +[PYTHON::swig_ldb] +LIBRARY_REALNAME = _ldb.$(SHLIBEXT) +PUBLIC_DEPENDENCIES = LIBLDB LIBEVENTS + +swig_ldb_OBJ_FILES = $(ldbsrcdir)/ldb_wrap.o +$(swig_ldb_OBJ_FILES): CFLAGS+=-I$(ldbsrcdir)/include + +$(eval $(call python_py_module_template,ldb.py,$(ldbsrcdir)/ldb.py)) + +$(swig_ldb_OBJ_FILES): CFLAGS+=$(CFLAG_NO_UNUSED_MACROS) $(CFLAG_NO_CAST_QUAL) diff --git a/ldb/rules.mk b/ldb/rules.mk new file mode 100644 index 000000000..ff5dc0274 --- /dev/null +++ b/ldb/rules.mk @@ -0,0 +1,30 @@ +etags: + etags `find $(srcdir) -name "*.[ch]"` + +ctags: + ctags `find $(srcdir) -name "*.[ch]"` + +.SUFFIXES: _wrap.c .i + +.i_wrap.c: + [ "$(SWIG)" = "no" ] || $(SWIG) -O -Wall -python -keyword $< + +.SUFFIXES: .1 .1.xml .3 .3.xml .xml .html .c .o + +.c.o: + @echo Compiling $*.c + @mkdir -p `dirname $@` + @$(CC) $(CFLAGS) $(PICFLAG) -c $< -o $@ + +.c.po: + @echo Compiling $*.c + @mkdir -p `dirname $@` + @$(CC) -fPIC $(CFLAGS) -c $< -o $@ + +showflags:: + @echo 'ldb will be compiled with flags:' + @echo ' CFLAGS = $(CFLAGS)' + @echo ' LIBS = $(LIBS)' + +distclean:: + rm -f *~ */*~ diff --git a/ldb/sqlite3.m4 b/ldb/sqlite3.m4 new file mode 100644 index 000000000..d0a74ee53 --- /dev/null +++ b/ldb/sqlite3.m4 @@ -0,0 +1,62 @@ +######################################################## +# Compile with SQLITE3 support? + +SQLITE3_LIBS="" +with_sqlite3_support=no +AC_MSG_CHECKING([for SQLITE3 support]) + +AC_ARG_WITH(sqlite3, +AS_HELP_STRING([--with-sqlite3],[SQLITE3 backend support (default=no)]), +[ case "$withval" in + yes|no|auto) + with_sqlite3_support=$withval + ;; + esac ]) + +AC_MSG_RESULT($with_sqlite3_support) + +if test x"$with_sqlite3_support" != x"no"; then + ################################################################## + # first test for sqlite3.h + AC_CHECK_HEADERS(sqlite3.h) + + if test x"$ac_cv_header_sqlite3_h" != x"yes"; then + if test x"$with_sqlite3_support" = x"yes"; then + AC_MSG_ERROR(sqlite3.h is needed for SQLITE3 support) + else + AC_MSG_WARN(sqlite3.h is needed for SQLITE3 support) + fi + + with_sqlite3_support=no + fi +fi + +if test x"$with_sqlite3_support" != x"no"; then + ac_save_LIBS=$LIBS + + ######################################################## + # now see if we can find the sqlite3 libs in standard paths + AC_CHECK_LIB_EXT(sqlite3, SQLITE3_LIBS, sqlite3_open) + + if test x"$ac_cv_lib_ext_sqlite3_sqlite3_open" = x"yes"; then + AC_DEFINE(HAVE_SQLITE3,1,[Whether sqlite3 is available]) + AC_DEFINE(HAVE_LDB_SQLITE3,1,[Whether ldb_sqlite3 is available]) + AC_MSG_CHECKING(whether SQLITE3 support is used) + AC_MSG_RESULT(yes) + with_sqlite3_support=yes + SMB_ENABLE(SQLITE3,YES) + else + if test x"$with_sqlite3_support" = x"yes"; then + AC_MSG_ERROR(libsqlite3 is needed for SQLITE3 support) + else + AC_MSG_WARN(libsqlite3 is needed for SQLITE3 support) + fi + + SQLITE3_LIBS="" + with_sqlite3_support=no + fi + + LIBS=$ac_save_LIBS; +fi + +SMB_EXT_LIB(SQLITE3,[${SQLITE3_LIBS}],[${SQLITE3_CFLAGS}],[${SQLITE3_CPPFLAGS}],[${SQLITE3_LDFLAGS}]) diff --git a/ldb/standalone.sh b/ldb/standalone.sh new file mode 100755 index 000000000..8ab081e0f --- /dev/null +++ b/ldb/standalone.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +cd ../replace +make clean + +cd ../talloc +make clean + +cd ../tdb +make clean + +cd ../events +make clean + +cd ../ldb +make clean + +./autogen.sh + +rm -fr build +mkdir build +cd build + +../configure $* +make dirs +make all + +cd .. diff --git a/ldb/tests/init.ldif b/ldb/tests/init.ldif new file mode 100644 index 000000000..2e0b83c76 --- /dev/null +++ b/ldb/tests/init.ldif @@ -0,0 +1,40 @@ +dn: o=University of Michigan,c=TEST +objectclass: organization +objectclass: domainRelatedObject +l: Ann Arbor, Michigan +st: Michigan +o: University of Michigan +o: UMICH +o: UM +o: U-M +o: U of M +description: The University of Michigan at Ann Arbor +seeAlso: +postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481 + 09 $ US +telephonenumber: +1 313 764-1817 +associateddomain: example.com + +dn: ou=People,o=University of Michigan,c=TEST +objectclass: organizationalUnit +objectclass: extensibleObject +ou: People +uidNumber: 0 +gidNumber: 0 + +dn: ou=Ldb Test,ou=People,o=University of Michigan,c=TEST +objectclass: organizationalUnit +objectclass: extensibleObject +ou: People +ou: Ldb Test +uidNumber: 0 +gidNumber: 0 + +dn: ou=LdbTspace,ou=People,o=University of Michigan,c=TEST +objectclass: organizationalUnit +objectclass: extensibleObject +ou: People +ou: LdbTspace +description: test white space removal in comparisons +uidNumber: 0 +gidNumber: 0 diff --git a/ldb/tests/init_slapd.sh b/ldb/tests/init_slapd.sh new file mode 100755 index 000000000..cf06acd08 --- /dev/null +++ b/ldb/tests/init_slapd.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +if [ -z "$LDBDIR" ]; then + LDBDIR=`dirname $0`/.. + export LDBDIR +fi + +rm -rf tests/tmp/db +mkdir -p tests/tmp/db + +if [ -f tests/tmp/slapd.pid ]; then + kill `cat tests/tmp/slapd.pid` + sleep 1 +fi +if [ -f tests/tmp/slapd.pid ]; then + kill -9 `cat tests/tmp/slapd.pid` + rm -f tests/tmp/slapd.pid +fi + +# we don't consider a slapadd failure as a test suite failure, as it +# has nothing to do with ldb + +MODCONF=tests/tmp/modules.conf +rm -f $MODCONF +touch $MODCONF || exit 1 + +slaptest -u -f $LDBDIR/tests/slapd.conf > /dev/null 2>&1 || { + echo "enabling sladp modules" +cat > $MODCONF < + +import sys +import unittest + +# Required for the standalone LDB build +sys.path.append("swig") +sys.path.append("build/lib.linux-i686-2.4") + +import ldb + +class NoContextTests(unittest.TestCase): + def test_valid_attr_name(self): + self.assertTrue(ldb.valid_attr_name("foo")) + self.assertFalse(ldb.valid_attr_name("24foo")) + + def test_timestring(self): + self.assertEquals("19700101000000.0Z", ldb.timestring(0)) + self.assertEquals("20071119191012.0Z", ldb.timestring(1195499412)) + + def test_string_to_time(self): + self.assertEquals(0, ldb.string_to_time("19700101000000.0Z")) + self.assertEquals(1195499412, ldb.string_to_time("20071119191012.0Z")) + + +class SimpleLdb(unittest.TestCase): + def test_connect(self): + ldb.Ldb("foo.tdb") + + def test_connect_none(self): + ldb.Ldb() + + def test_connect_later(self): + x = ldb.Ldb() + x.connect("foo.tdb") + + def test_repr(self): + x = ldb.Ldb() + self.assertTrue(repr(x).startswith("") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) +parser.add_option_group(options.VersionOptions(parser)) +# use command line creds if available +credopts = options.CredentialsOptions(parser) +parser.add_option_group(credopts) +opts, args = parser.parse_args() + +if len(args) < 1: + parser.print_usage() + sys.exit(1) + +host = args[0] + +lp = sambaopts.get_loadparm() +creds = credopts.get_credentials(lp) + +class BasicTests(unittest.TestCase): + def delete_force(self, ldb, dn): + try: + ldb.delete(dn) + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_NO_SUCH_OBJECT) + + def find_basedn(self, ldb): + res = ldb.search(base="", expression="", scope=SCOPE_BASE, + attrs=["defaultNamingContext"]) + self.assertEquals(len(res), 1) + return res[0]["defaultNamingContext"][0] + + def find_configurationdn(self, ldb): + res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["configurationNamingContext"]) + self.assertEquals(len(res), 1) + return res[0]["configurationNamingContext"][0] + + def find_schemadn(self, ldb): + res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"]) + self.assertEquals(len(res), 1) + return res[0]["schemaNamingContext"][0] + + def setUp(self): + self.ldb = ldb + self.gc_ldb = gc_ldb + self.base_dn = self.find_basedn(ldb) + self.configuration_dn = self.find_configurationdn(ldb) + self.schema_dn = self.find_schemadn(ldb) + + print "baseDN: %s\n" % self.base_dn + + self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) + self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) + + def test_group_add_invalid_member(self): + """Testing group add with invalid member""" + try: + self.ldb.add({ + "dn": "cn=ldaptestgroup,cn=uSers," + self.base_dn, + "objectclass": "group", + "member": "cn=ldaptestuser,cn=useRs," + self.base_dn}) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_NO_SUCH_OBJECT) + + def test_all(self): + """Basic tests""" + + self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) + + print "Testing user add" + ldb.add({ + "dn": "cn=ldaptestuser,cn=uSers," + self.base_dn, + "objectclass": ["user", "person"], + "cN": "LDAPtestUSER", + "givenname": "ldap", + "sn": "testy"}) + + ldb.add({ + "dn": "cn=ldaptestgroup,cn=uSers," + self.base_dn, + "objectclass": "group", + "member": "cn=ldaptestuser,cn=useRs," + self.base_dn}) + + self.delete_force(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) + ldb.add({ + "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn, + "objectclass": "computer", + "cN": "LDAPtestCOMPUTER"}) + + self.delete_force(self.ldb, "cn=ldaptest2computer,cn=computers," + self.base_dn) + ldb.add({"dn": "cn=ldaptest2computer,cn=computers," + self.base_dn, + "objectClass": "computer", + "cn": "LDAPtest2COMPUTER", + "userAccountControl": "4096", + "displayname": "ldap testy"}) + + self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn) + try: + ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn, + "objectClass": "computer", + "cn": "LDAPtest2COMPUTER" + }) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_INVALID_DN_SYNTAX) + + self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn) + try: + ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn, + "objectClass": "computer", + "cn": "ldaptestcomputer3", + "sAMAccountType": "805306368" + }) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_UNWILLING_TO_PERFORM) + + self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn) + try: + ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn, + "objectClass": "computer", + "cn": "ldaptestcomputer3", + "userAccountControl": "0" + }) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_UNWILLING_TO_PERFORM) + + self.delete_force(self.ldb, "cn=ldaptestuser7,cn=users," + self.base_dn) + try: + ldb.add({"dn": "cn=ldaptestuser7,cn=users," + self.base_dn, + "objectClass": "user", + "cn": "LDAPtestuser7", + "userAccountControl": "0" + }) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_UNWILLING_TO_PERFORM) + + self.delete_force(self.ldb, "cn=ldaptestuser7,cn=users," + self.base_dn) + + ldb.add({"dn": "cn=ldaptestuser7,cn=users," + self.base_dn, + "objectClass": "user", + "cn": "LDAPtestuser7", + "userAccountControl": "2" + }) + + self.delete_force(self.ldb, "cn=ldaptestuser7,cn=users," + self.base_dn) + + self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn) + ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn, + "objectClass": "computer", + "cn": "LDAPtestCOMPUTER3" + }) + + print "Testing ldb.search for (&(cn=ldaptestcomputer3)(objectClass=user))"; + res = ldb.search(self.base_dn, expression="(&(cn=ldaptestcomputer3)(objectClass=user))"); + self.assertEquals(len(res), 1, "Found only %d for (&(cn=ldaptestcomputer3)(objectClass=user))" % len(res)) + + self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer3,CN=Computers," + self.base_dn)); + self.assertEquals(res[0]["cn"][0], "ldaptestcomputer3"); + self.assertEquals(res[0]["name"][0], "ldaptestcomputer3"); + self.assertEquals(res[0]["objectClass"][0], "top"); + self.assertEquals(res[0]["objectClass"][1], "person"); + self.assertEquals(res[0]["objectClass"][2], "organizationalPerson"); + self.assertEquals(res[0]["objectClass"][3], "user"); + self.assertEquals(res[0]["objectClass"][4], "computer"); + self.assertTrue("objectGUID" in res[0]) + self.assertTrue("whenCreated" in res[0]) + self.assertEquals(res[0]["objectCategory"][0], ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn)); + self.assertEquals(int(res[0]["primaryGroupID"][0]), 513); + self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306368); + self.assertEquals(int(res[0]["userAccountControl"][0]), 546); + + self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn) + + print "Testing attribute or value exists behaviour" + try: + ldb.modify_ldif(""" +dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """ +changetype: modify +replace: servicePrincipalName +servicePrincipalName: host/ldaptest2computer +servicePrincipalName: host/ldaptest2computer +servicePrincipalName: cifs/ldaptest2computer +""") + self.fail() + except LdbError, (num, msg): + self.assertEquals(num, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) + + ldb.modify_ldif(""" +dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """ +changetype: modify +replace: servicePrincipalName +servicePrincipalName: host/ldaptest2computer +servicePrincipalName: cifs/ldaptest2computer +""") + try: + ldb.modify_ldif(""" +dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """ +changetype: modify +add: servicePrincipalName +servicePrincipalName: host/ldaptest2computer +""") + self.fail() + except LdbError, (num, msg): + self.assertEquals(num, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) + + print "Testing ranged results" + ldb.modify_ldif(""" +dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """ +changetype: modify +replace: servicePrincipalName +""") + + ldb.modify_ldif(""" +dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """ +changetype: modify +add: servicePrincipalName +servicePrincipalName: host/ldaptest2computer0 +servicePrincipalName: host/ldaptest2computer1 +servicePrincipalName: host/ldaptest2computer2 +servicePrincipalName: host/ldaptest2computer3 +servicePrincipalName: host/ldaptest2computer4 +servicePrincipalName: host/ldaptest2computer5 +servicePrincipalName: host/ldaptest2computer6 +servicePrincipalName: host/ldaptest2computer7 +servicePrincipalName: host/ldaptest2computer8 +servicePrincipalName: host/ldaptest2computer9 +servicePrincipalName: host/ldaptest2computer10 +servicePrincipalName: host/ldaptest2computer11 +servicePrincipalName: host/ldaptest2computer12 +servicePrincipalName: host/ldaptest2computer13 +servicePrincipalName: host/ldaptest2computer14 +servicePrincipalName: host/ldaptest2computer15 +servicePrincipalName: host/ldaptest2computer16 +servicePrincipalName: host/ldaptest2computer17 +servicePrincipalName: host/ldaptest2computer18 +servicePrincipalName: host/ldaptest2computer19 +servicePrincipalName: host/ldaptest2computer20 +servicePrincipalName: host/ldaptest2computer21 +servicePrincipalName: host/ldaptest2computer22 +servicePrincipalName: host/ldaptest2computer23 +servicePrincipalName: host/ldaptest2computer24 +servicePrincipalName: host/ldaptest2computer25 +servicePrincipalName: host/ldaptest2computer26 +servicePrincipalName: host/ldaptest2computer27 +servicePrincipalName: host/ldaptest2computer28 +servicePrincipalName: host/ldaptest2computer29 +""") + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, + attrs=["servicePrincipalName;range=0-*"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + #print len(res[0]["servicePrincipalName;range=0-*"]) + self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30) + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-19"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + # print res[0]["servicePrincipalName;range=0-19"].length + self.assertEquals(len(res[0]["servicePrincipalName;range=0-19"]), 20) + + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-30"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30) + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-40"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30) + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=30-40"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + self.assertEquals(len(res[0]["servicePrincipalName;range=30-*"]), 0) + + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=10-40"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + self.assertEquals(len(res[0]["servicePrincipalName;range=10-*"]), 20) + # pos_11 = res[0]["servicePrincipalName;range=10-*"][18] + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-40"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + self.assertEquals(len(res[0]["servicePrincipalName;range=11-*"]), 19) + # print res[0]["servicePrincipalName;range=11-*"][18] + # print pos_11 + # self.assertEquals((res[0]["servicePrincipalName;range=11-*"][18]), pos_11) + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-15"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + self.assertEquals(len(res[0]["servicePrincipalName;range=11-15"]), 5) + # self.assertEquals(res[0]["servicePrincipalName;range=11-15"][4], pos_11) + + res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName"]) + self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)") + # print res[0]["servicePrincipalName"][18] + # print pos_11 + self.assertEquals(len(res[0]["servicePrincipalName"]), 30) + # self.assertEquals(res[0]["servicePrincipalName"][18], pos_11) + + self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn) + ldb.add({ + "dn": "cn=ldaptestuser2,cn=useRs," + self.base_dn, + "objectClass": ["person", "user"], + "cn": "LDAPtestUSER2", + "givenname": "testy", + "sn": "ldap user2"}) + + print "Testing Ambigious Name Resolution" + # Testing ldb.search for (&(anr=ldap testy)(objectClass=user)) + res = ldb.search(expression="(&(anr=ldap testy)(objectClass=user))") + self.assertEquals(len(res), 3, "Found only %d of 3 for (&(anr=ldap testy)(objectClass=user))" % len(res)) + + # Testing ldb.search for (&(anr=testy ldap)(objectClass=user)) + res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))") + self.assertEquals(len(res), 2, "Found only %d of 2 for (&(anr=testy ldap)(objectClass=user))" % len(res)) + + # Testing ldb.search for (&(anr=ldap)(objectClass=user)) + res = ldb.search(expression="(&(anr=ldap)(objectClass=user))") + self.assertEquals(len(res), 4, "Found only %d of 4 for (&(anr=ldap)(objectClass=user))" % len(res)) + + # Testing ldb.search for (&(anr==ldap)(objectClass=user)) + res = ldb.search(expression="(&(anr==ldap)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(anr==ldap)(objectClass=user)). Found only %d for (&(anr=ldap)(objectClass=user))" % len(res)) + + self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"][0], "ldaptestuser") + self.assertEquals(res[0]["name"], "ldaptestuser") + + # Testing ldb.search for (&(anr=testy)(objectClass=user)) + res = ldb.search(expression="(&(anr=testy)(objectClass=user))") + self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy)(objectClass=user))" % len(res)) + + # Testing ldb.search for (&(anr=testy ldap)(objectClass=user)) + res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))") + self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy ldap)(objectClass=user))" % len(res)) + + # Testing ldb.search for (&(anr==testy ldap)(objectClass=user)) +# this test disabled for the moment, as anr with == tests are not understood +# res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))") +# self.assertEquals(len(res), 1, "Found only %d for (&(anr==testy ldap)(objectClass=user))" % len(res)) + + self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"][0], "ldaptestuser") + self.assertEquals(res[0]["name"][0], "ldaptestuser") + + # Testing ldb.search for (&(anr==testy ldap)(objectClass=user)) +# res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))") +# self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap)(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"][0], "ldaptestuser") + self.assertEquals(res[0]["name"][0], "ldaptestuser") + + # Testing ldb.search for (&(anr=testy ldap user)(objectClass=user)) + res = ldb.search(expression="(&(anr=testy ldap user)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(anr=testy ldap user)(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestuser2") + self.assertEquals(res[0]["name"], "ldaptestuser2") + + # Testing ldb.search for (&(anr==testy ldap user2)(objectClass=user)) +# res = ldb.search(expression="(&(anr==testy ldap user2)(objectClass=user))") +# self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap user2)(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestuser2") + self.assertEquals(res[0]["name"], "ldaptestuser2") + + # Testing ldb.search for (&(anr==ldap user2)(objectClass=user)) +# res = ldb.search(expression="(&(anr==ldap user2)(objectClass=user))") +# self.assertEquals(len(res), 1, "Could not find (&(anr==ldap user2)(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestuser2") + self.assertEquals(res[0]["name"], "ldaptestuser2") + + # Testing ldb.search for (&(anr==not ldap user2)(objectClass=user)) +# res = ldb.search(expression="(&(anr==not ldap user2)(objectClass=user))") +# self.assertEquals(len(res), 0, "Must not find (&(anr==not ldap user2)(objectClass=user))") + + # Testing ldb.search for (&(anr=not ldap user2)(objectClass=user)) + res = ldb.search(expression="(&(anr=not ldap user2)(objectClass=user))") + self.assertEquals(len(res), 0, "Must not find (&(anr=not ldap user2)(objectClass=user))") + + # Testing ldb.search for (&(anr="testy ldap")(objectClass=user)) (ie, with quotes) +# res = ldb.search(expression="(&(anr==\"testy ldap\")(objectClass=user))") +# self.assertEquals(len(res), 0, "Found (&(anr==\"testy ldap\")(objectClass=user))") + + print "Testing Group Modifies" + ldb.modify_ldif(""" +dn: cn=ldaptestgroup,cn=users,""" + self.base_dn + """ +changetype: modify +add: member +member: cn=ldaptestuser2,cn=users,""" + self.base_dn + """ +member: cn=ldaptestcomputer,cn=computers,""" + self.base_dn + """ +""") + + self.delete_force(ldb, "cn=ldaptestuser3,cn=users," + self.base_dn) + + print "Testing adding non-existent user to a group" + try: + ldb.modify_ldif(""" +dn: cn=ldaptestgroup,cn=users,""" + self.base_dn + """ +changetype: modify +add: member +member: cn=ldaptestuser3,cn=users,""" + self.base_dn + """ +""") + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_NO_SUCH_OBJECT) + + print "Testing Renames" + + ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn) + + ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn) + + ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestUSER3,cn=users," + self.base_dn) + + print "Testing ldb.search for (&(cn=ldaptestuser3)(objectClass=user))" + res = ldb.search(expression="(&(cn=ldaptestuser3)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser3)(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestUSER3") + self.assertEquals(res[0]["name"], "ldaptestUSER3") + + #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))" + res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))") + self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestUSER3") + self.assertEquals(res[0]["name"], "ldaptestUSER3") + + #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))" + res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))") + self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestUSER3") + self.assertEquals(res[0]["name"], "ldaptestUSER3") + + #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))" + res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))") + self.assertEquals(len(res), 0, "(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))") + + # This is a Samba special, and does not exist in real AD + # print "Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")" + # res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")") + # if (res.error != 0 || len(res) != 1) { + # print "Could not find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")" + # self.assertEquals(len(res), 1) + # } + # self.assertEquals(res[0].dn, ("CN=ldaptestUSER3,CN=Users," + self.base_dn)) + # self.assertEquals(res[0].cn, "ldaptestUSER3") + # self.assertEquals(res[0].name, "ldaptestUSER3") + + print "Testing ldb.search for (distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")" + res = ldb.search(expression="(distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")") + self.assertEquals(len(res), 1, "Could not find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")") + self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestUSER3") + self.assertEquals(res[0]["name"], "ldaptestUSER3") + + # ensure we cannot add it again + try: + ldb.add({"dn": "cn=ldaptestuser3,cn=userS," + self.base_dn, + "objectClass": ["person", "user"], + "cn": "LDAPtestUSER3"}) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_ENTRY_ALREADY_EXISTS) + + # rename back + ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn) + + # ensure we cannnot rename it twice + try: + ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, + "cn=ldaptestuser2,cn=users," + self.base_dn) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_NO_SUCH_OBJECT) + + # ensure can now use that name + ldb.add({"dn": "cn=ldaptestuser3,cn=users," + self.base_dn, + "objectClass": ["person", "user"], + "cn": "LDAPtestUSER3"}) + + # ensure we now cannnot rename + try: + ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_ENTRY_ALREADY_EXISTS) + try: + ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=configuration," + self.base_dn) + self.fail() + except LdbError, (num, _): + self.assertTrue(num in (71, 64)) + + ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser5,cn=users," + self.base_dn) + + ldb.delete("cn=ldaptestuser5,cn=users," + self.base_dn) + + self.delete_force(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn) + + ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn, "cn=ldaptestgroup2,cn=users," + self.base_dn) + + print "Testing subtree Renames" + + ldb.add({"dn": "cn=ldaptestcontainer," + self.base_dn, + "objectClass": "container"}) + + self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer," + self.base_dn) + ldb.add({"dn": "CN=ldaptestuser4,CN=ldaptestcontainer," + self.base_dn, + "objectClass": ["person", "user"], + "cn": "LDAPtestUSER4"}) + + ldb.modify_ldif(""" +dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """ +changetype: modify +add: member +member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """ +""") + + print "Testing ldb.rename of cn=ldaptestcontainer," + self.base_dn + " to cn=ldaptestcontainer2," + self.base_dn + ldb.rename("CN=ldaptestcontainer," + self.base_dn, "CN=ldaptestcontainer2," + self.base_dn) + + print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user))" + res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user))") + + print "Testing subtree ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn + try: + ldb.search("cn=ldaptestcontainer," + self.base_dn, + expression="(&(cn=ldaptestuser4)(objectClass=user))", + scope=SCOPE_SUBTREE) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_NO_SUCH_OBJECT) + + print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn + try: + res = ldb.search("cn=ldaptestcontainer," + self.base_dn, + expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_ONELEVEL) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_NO_SUCH_OBJECT) + + print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in renamed container" + res = ldb.search("cn=ldaptestcontainer2," + self.base_dn, expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_SUBTREE) + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user)) under cn=ldaptestcontainer2," + self.base_dn) + + self.assertEquals(str(res[0].dn), ("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn)) + self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper()) + + time.sleep(4) + + print "Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)) to check subtree renames and linked attributes" + res = ldb.search(self.base_dn, expression="(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group))", scope=SCOPE_SUBTREE) + self.assertEquals(len(res), 1, "Could not find (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)), perhaps linked attributes are not conistant with subtree renames?") + + print "Testing ldb.rename (into itself) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn + try: + ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_UNWILLING_TO_PERFORM) + + print "Testing ldb.rename (into non-existent container) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn + try: + ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn) + self.fail() + except LdbError, (num, _): + self.assertTrue(num in (LDB_ERR_UNWILLING_TO_PERFORM, LDB_ERR_OTHER)) + + print "Testing delete (should fail, not a leaf node) of renamed cn=ldaptestcontainer2," + self.base_dn + try: + ldb.delete("cn=ldaptestcontainer2," + self.base_dn) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, LDB_ERR_NOT_ALLOWED_ON_NON_LEAF) + + print "Testing base ldb.search for CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + res = ldb.search(expression="(objectclass=*)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE) + self.assertEquals(len(res), 1) + res = ldb.search(expression="(cn=ldaptestuser40)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE) + self.assertEquals(len(res), 0) + + print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn + res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_ONELEVEL) + # FIXME: self.assertEquals(len(res), 0) + + print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn + res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_SUBTREE) + # FIXME: self.assertEquals(len(res), 0) + + print "Testing delete of subtree renamed "+("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn) + ldb.delete(("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn)) + print "Testing delete of renamed cn=ldaptestcontainer2," + self.base_dn + ldb.delete("cn=ldaptestcontainer2," + self.base_dn) + + self.delete_force(self.ldb, "cn=ldaptestutf8user èùéìòà ,cn=users," + self.base_dn) + ldb.add({"dn": "cn=ldaptestutf8user èùéìòà ,cn=users," + self.base_dn, "objectClass": "user"}) + + self.delete_force(self.ldb, "cn=ldaptestutf8user2 èùéìòà ,cn=users," + self.base_dn) + ldb.add({"dn": "cn=ldaptestutf8user2 èùéìòà ,cn=users," + self.base_dn, "objectClass": "user"}) + + print "Testing ldb.search for (&(cn=ldaptestuser)(objectClass=user))" + res = ldb.search(expression="(&(cn=ldaptestuser)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestuser") + self.assertEquals(res[0]["name"], "ldaptestuser") + self.assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user"]) + self.assertTrue("objectGUID" in res[0]) + self.assertTrue("whenCreated" in res[0]) + self.assertEquals(res[0]["objectCategory"], ("CN=Person,CN=Schema,CN=Configuration," + self.base_dn)) + self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306368) + self.assertEquals(int(res[0]["userAccountControl"][0]), 546) + self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper()) + self.assertEquals(len(res[0]["memberOf"]), 1) + + print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))" + res2 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))") + self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))") + + self.assertEquals(res[0].dn, res2[0].dn) + + print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon))" + res3 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))") + self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)): matched %d" % len(res3)) + + self.assertEquals(res[0].dn, res3[0].dn) + + if gc_ldb is not None: + print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog" + res3gc = gc_ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))") + self.assertEquals(len(res3gc), 1) + + self.assertEquals(res[0].dn, res3gc[0].dn) + + print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in with 'phantom root' control" + + res3control = gc_ldb.search(self.base_dn, expression="(&(cn=ldaptestuser)(objectCategory=PerSon))", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"]) + self.assertEquals(len(res3control), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog") + + self.assertEquals(res[0].dn, res3control[0].dn) + + ldb.delete(res[0].dn) + + print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectClass=user))" + res = ldb.search(expression="(&(cn=ldaptestcomputer)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))") + + self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer,CN=Computers," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestcomputer") + self.assertEquals(res[0]["name"], "ldaptestcomputer") + self.assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user", "computer"]) + self.assertTrue("objectGUID" in res[0]) + self.assertTrue("whenCreated" in res[0]) + self.assertEquals(res[0]["objectCategory"], ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn)) + self.assertEquals(int(res[0]["primaryGroupID"][0]), 513) + self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306368) + self.assertEquals(int(res[0]["userAccountControl"][0]), 546) + self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper()) + self.assertEquals(len(res[0]["memberOf"]), 1) + + print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))" + res2 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))") + self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))") + + self.assertEquals(res[0].dn, res2[0].dn) + + if gc_ldb is not None: + print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + ")) in Global Catlog" + res2gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))") + self.assertEquals(len(res2gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + ")) in Global Catlog") + + self.assertEquals(res[0].dn, res2gc[0].dn) + + print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER))" + res3 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))") + self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER))") + + self.assertEquals(res[0].dn, res3[0].dn) + + if gc_ldb is not None: + print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog" + res3gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))") + self.assertEquals(len(res3gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog") + + self.assertEquals(res[0].dn, res3gc[0].dn) + + print "Testing ldb.search for (&(cn=ldaptestcomp*r)(objectCategory=compuTER))" + res4 = ldb.search(expression="(&(cn=ldaptestcomp*r)(objectCategory=compuTER))") + self.assertEquals(len(res4), 1, "Could not find (&(cn=ldaptestcomp*r)(objectCategory=compuTER))") + + self.assertEquals(res[0].dn, res4[0].dn) + + print "Testing ldb.search for (&(cn=ldaptestcomput*)(objectCategory=compuTER))" + res5 = ldb.search(expression="(&(cn=ldaptestcomput*)(objectCategory=compuTER))") + self.assertEquals(len(res5), 1, "Could not find (&(cn=ldaptestcomput*)(objectCategory=compuTER))") + + self.assertEquals(res[0].dn, res5[0].dn) + + print "Testing ldb.search for (&(cn=*daptestcomputer)(objectCategory=compuTER))" + res6 = ldb.search(expression="(&(cn=*daptestcomputer)(objectCategory=compuTER))") + self.assertEquals(len(res6), 1, "Could not find (&(cn=*daptestcomputer)(objectCategory=compuTER))") + + self.assertEquals(res[0].dn, res6[0].dn) + + ldb.delete(res[0].dn) + + print "Testing ldb.search for (&(cn=ldaptest2computer)(objectClass=user))" + res = ldb.search(expression="(&(cn=ldaptest2computer)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptest2computer)(objectClass=user))") + + self.assertEquals(res[0].dn, ("CN=ldaptest2computer,CN=Computers," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptest2computer") + self.assertEquals(res[0]["name"], "ldaptest2computer") + self.assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user", "computer"]) + self.assertTrue("objectGUID" in res[0]) + self.assertTrue("whenCreated" in res[0]) + self.assertEquals(res[0]["objectCategory"][0], "CN=Computer,CN=Schema,CN=Configuration," + self.base_dn) + self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306369) + self.assertEquals(int(res[0]["userAccountControl"][0]), 4096) + + ldb.delete(res[0].dn) + + attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "memberOf"] + print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))" + res = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs) + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))") + + self.assertEquals(res[0].dn, ("CN=ldaptestuser2,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestuser2") + self.assertEquals(res[0]["name"], "ldaptestuser2") + self.assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user"]) + self.assertTrue("objectGUID" in res[0]) + self.assertTrue("whenCreated" in res[0]) + self.assertTrue("nTSecurityDescriptor" in res[0]) + self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper()) + + attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"] + print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group))" + res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs) + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))") + + self.assertEquals(res[0].dn, ("CN=ldaptestgroup2,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestgroup2") + self.assertEquals(res[0]["name"], "ldaptestgroup2") + self.assertEquals(res[0]["objectClass"], ["top", "group"]) + self.assertTrue("objectGuid" not in res[0]) + self.assertTrue("whenCreated" in res[0]) + self.assertTrue("nTSecurityDescriptor" in res[0]) + self.assertEquals(res[0]["member"][0].upper(), ("CN=ldaptestuser2,CN=Users," + self.base_dn).upper()) + + ldb.modify_ldif(""" +dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """ +changetype: modify +replace: member +member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """ +member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """ +""") + + print "Testing Linked attribute behaviours" + ldb.modify_ldif(""" +dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """ +changetype: modify +delete: member +""") + + ldb.modify_ldif(""" +dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """ +changetype: modify +add: member +member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """ +member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """ +""") + + ldb.modify_ldif(""" +dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """ +changetype: modify +replace: member +""") + + ldb.modify_ldif(""" +dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """ +changetype: modify +add: member +member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """ +member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """ +""") + + ldb.modify_ldif(""" +dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """ +changetype: modify +delete: member +member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """ +""") + + res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs) + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))") + + self.assertEquals(res[0].dn, ("CN=ldaptestgroup2,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["member"][0], ("CN=ldaptestuser2,CN=Users," + self.base_dn)) + self.assertEquals(len(res[0]["member"]), 1) + + ldb.delete(("CN=ldaptestuser2,CN=Users," + self.base_dn)) + + time.sleep(4) + + attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"] + print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete" + res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs) + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete") + + self.assertEquals(res[0].dn, ("CN=ldaptestgroup2,CN=Users," + self.base_dn)) + self.assertTrue("member" not in res[0]) + + print "Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))" + res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))") + + self.assertEquals(res[0].dn, ("CN=ldaptestutf8user èùéìòà,CN=Users," + self.base_dn)) + self.assertEquals(res[0]["cn"], "ldaptestutf8user èùéìòà") + self.assertEquals(res[0]["name"], "ldaptestutf8user èùéìòà") + self.assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user"]) + self.assertTrue("objectGUID" in res[0]) + self.assertTrue("whenCreated" in res[0]) + + ldb.delete(res[0].dn) + + print "Testing ldb.search for (&(cn=ldaptestutf8user2*)(objectClass=user))" + res = ldb.search(expression="(&(cn=ldaptestutf8user2*)(objectClass=user))") + self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user2*)(objectClass=user))") + + ldb.delete(res[0].dn) + + ldb.delete(("CN=ldaptestgroup2,CN=Users," + self.base_dn)) + + print "Testing ldb.search for (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))" + res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))") + + #FIXME: self.assert len(res) == 1, "Could not find (expect space collapse, win2k3 fails) (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))" + + print "Testing that we can't get at the configuration DN from the main search base" + res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertEquals(len(res), 0) + + print "Testing that we can get at the configuration DN from the main search base on the LDAP port with the 'phantom root' search_options control" + res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"]) + self.assertTrue(len(res) > 0) + + if gc_ldb is not None: + print "Testing that we can get at the configuration DN from the main search base on the GC port with the search_options control == 0" + + res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:0"]) + self.assertTrue(len(res) > 0) + + print "Testing that we do find configuration elements in the global catlog" + res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0) + + print "Testing that we do find configuration elements and user elements at the same time" + res = gc_ldb.search(self.base_dn, expression="(|(objectClass=crossRef)(objectClass=person))", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0) + + print "Testing that we do find configuration elements in the global catlog, with the configuration basedn" + res = gc_ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0) + + print "Testing that we can get at the configuration DN on the main LDAP port" + res = ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0) + + print "Testing objectCategory canonacolisation" + res = ldb.search(self.configuration_dn, expression="objectCategory=ntDsDSA", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=ntDsDSA") + self.assertTrue(len(res) != 0) + + res = ldb.search(self.configuration_dn, expression="objectCategory=CN=ntDs-DSA," + self.schema_dn, scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=CN=ntDs-DSA," + self.schema_dn) + self.assertTrue(len(res) != 0) + + print "Testing objectClass attribute order on "+ self.base_dn + res = ldb.search(expression="objectClass=domain", base=self.base_dn, + scope=SCOPE_BASE, attrs=["objectClass"]) + self.assertEquals(len(res), 1) + + self.assertEquals(res[0]["objectClass"], ["top", "domain", "domainDNS"]) + + # check enumeration + + print "Testing ldb.search for objectCategory=person" + res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0) + + print "Testing ldb.search for objectCategory=person with domain scope control" + res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"]) + self.assertTrue(len(res) > 0) + + print "Testing ldb.search for objectCategory=user" + res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0) + + print "Testing ldb.search for objectCategory=user with domain scope control" + res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"]) + self.assertTrue(len(res) > 0) + + print "Testing ldb.search for objectCategory=group" + res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"]) + self.assertTrue(len(res) > 0) + + print "Testing ldb.search for objectCategory=group with domain scope control" + res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"]) + self.assertTrue(len(res) > 0) + + +class BaseDnTests(unittest.TestCase): + def setUp(self): + self.ldb = ldb + + def test_rootdse_attrs(self): + """Testing for all rootDSE attributes""" + res = self.ldb.search(scope=SCOPE_BASE, attrs=[]) + self.assertEquals(len(res), 1) + + def test_highestcommittedusn(self): + """Testing for highestCommittedUSN""" + res = self.ldb.search("", scope=SCOPE_BASE, attrs=["highestCommittedUSN"]) + self.assertEquals(len(res), 1) + self.assertTrue(int(res[0]["highestCommittedUSN"][0]) != 0) + + def test_netlogon(self): + """Testing for netlogon via LDAP""" + res = self.ldb.search("", scope=SCOPE_BASE, attrs=["netlogon"]) + self.assertEquals(len(res), 0) + + def test_netlogon_highestcommitted_usn(self): + """Testing for netlogon and highestCommittedUSN via LDAP""" + res = self.ldb.search("", scope=SCOPE_BASE, + attrs=["netlogon", "highestCommittedUSN"]) + self.assertEquals(len(res), 0) + +class SchemaTests(unittest.TestCase): + def find_schemadn(self, ldb): + res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"]) + self.assertEquals(len(res), 1) + return res[0]["schemaNamingContext"][0] + + def setUp(self): + self.ldb = ldb + self.schema_dn = self.find_schemadn(ldb) + + def test_generated_schema(self): + """Testing we can read the generated schema via LDAP""" + res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE, + attrs=["objectClasses", "attributeTypes", "dITContentRules"]) + self.assertEquals(len(res), 1) + self.assertTrue("dITContentRules" in res[0]) + self.assertTrue("objectClasses" in res[0]) + self.assertTrue("attributeTypes" in res[0]) + + def test_generated_schema_is_operational(self): + """Testing we don't get the generated schema via LDAP by default""" + res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE, + attrs=["*"]) + self.assertEquals(len(res), 1) + self.assertFalse("dITContentRules" in res[0]) + self.assertFalse("objectClasses" in res[0]) + self.assertFalse("attributeTypes" in res[0]) + +if not "://" in host: + host = "ldap://%s" % host + +ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp) +gc_ldb = Ldb("%s:3268" % host, credentials=creds, + session_info=system_session(), lp=lp) + +runner = SubunitTestRunner() +rc = 0 +if not runner.run(unittest.makeSuite(BaseDnTests)).wasSuccessful(): + rc = 1 +if not runner.run(unittest.makeSuite(BasicTests)).wasSuccessful(): + rc = 1 +if not runner.run(unittest.makeSuite(SchemaTests)).wasSuccessful(): + rc = 1 +sys.exit(rc) diff --git a/ldb/tests/samba4.png b/ldb/tests/samba4.png new file mode 100644 index 000000000..c8096889a Binary files /dev/null and b/ldb/tests/samba4.png differ diff --git a/ldb/tests/sample_module.c b/ldb/tests/sample_module.c new file mode 100644 index 000000000..1a9e72c90 --- /dev/null +++ b/ldb/tests/sample_module.c @@ -0,0 +1,38 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij 2007 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +#include "ldb_includes.h" +#include "ldb.h" +#include "ldb_errors.h" + +int sample_add(struct ldb_module *mod, struct ldb_request *req) +{ + ldb_msg_add_fmt(req->op.add.message, "touchedBy", "sample"); + + return ldb_next_request(mod, req); +} + +const struct ldb_module_ops ldb_sample_module_ops = { + .name = "sample", + .add = sample_add, +}; diff --git a/ldb/tests/schema-tests/schema-add-test.ldif b/ldb/tests/schema-tests/schema-add-test.ldif new file mode 100644 index 000000000..472ab48fa --- /dev/null +++ b/ldb/tests/schema-tests/schema-add-test.ldif @@ -0,0 +1,66 @@ +dn: CN=Users,DC=schema,DC=test +objectClass: top +objectClass: container +cn: Users +description: Default container for upgraded user accounts +instanceType: 4 +whenCreated: 20050116175504.0Z +whenChanged: 20050116175504.0Z +uSNCreated: 1 +uSNChanged: 1 +showInAdvancedViewOnly: FALSE +name: Users +objectGUID: b847056a-9934-d87b-8a1a-99fabe0863c8 +systemFlags: 0x8c000000 +objectCategory: CN=Container,CN=Schema,CN=Configuration,DC=schema,DC=test +isCriticalSystemObject: TRUE +nTSecurityDescriptor: foo + +dn: CN=Administrator,CN=Users,DC=schema,DC=test +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: user +cn: Administrator +description: Built-in account for administering the computer/domain +instanceType: 4 +whenCreated: 20050116175504.0Z +whenChanged: 20050116175504.0Z +uSNCreated: 1 +memberOf: CN=Group Policy Creator Owners,CN=Users,DC=schema,DC=test +memberOf: CN=Domain Admins,CN=Users,DC=schema,DC=test +memberOf: CN=Enterprise Admins,CN=Users,DC=schema,DC=test +memberOf: CN=Schema Admins,CN=Users,DC=schema,DC=test +memberOf: CN=Administrators,CN=Builtin,DC=schema,DC=test +uSNChanged: 1 +name: Administrator +objectGUID: 6c02f98c-46c6-aa38-5f13-a510cac04e6c +userAccountControl: 0x10200 +badPwdCount: 0 +codePage: 0 +countryCode: 0 +badPasswordTime: 0 +lastLogoff: 0 +lastLogon: 0 +pwdLastSet: 0 +primaryGroupID: 513 +objectSid: S-1-5-21-43662522-77495566-38969261-500 +adminCount: 1 +accountExpires: 9223372036854775807 +logonCount: 0 +sAMAccountName: Administrator +sAMAccountType: 0x30000000 +objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=schema,DC=test +isCriticalSystemObject: TRUE +unicodePwd: samba +nTSecurityDescriptor: foo + +dn: CN=Test,CN=Users,DC=schema,DC=test +objectClass: top +objectClass: test +cn: Test +description: This is a test +objectCategory: CN=Test,CN=Schema,CN=Configuration,DC=schema,DC=test +nTSecurityDescriptor: foo +instanceType: 4 + diff --git a/ldb/tests/schema-tests/schema-mod-test-1.ldif b/ldb/tests/schema-tests/schema-mod-test-1.ldif new file mode 100644 index 000000000..b97672448 --- /dev/null +++ b/ldb/tests/schema-tests/schema-mod-test-1.ldif @@ -0,0 +1,5 @@ +dn: CN=Test,CN=Users,DC=schema,DC=test +changetype: modify +replace: description +description: this test must not fail + diff --git a/ldb/tests/schema-tests/schema-mod-test-2.ldif b/ldb/tests/schema-tests/schema-mod-test-2.ldif new file mode 100644 index 000000000..fa193af68 --- /dev/null +++ b/ldb/tests/schema-tests/schema-mod-test-2.ldif @@ -0,0 +1,5 @@ +dn: CN=Test,CN=Users,DC=schema,DC=test +changetype: modify +delete: description +# this test must not fail + diff --git a/ldb/tests/schema-tests/schema-mod-test-3.ldif b/ldb/tests/schema-tests/schema-mod-test-3.ldif new file mode 100644 index 000000000..8ab7798f9 --- /dev/null +++ b/ldb/tests/schema-tests/schema-mod-test-3.ldif @@ -0,0 +1,5 @@ +dn: CN=Test,CN=Users,DC=schema,DC=test +changetype: modify +add: description +description: this test must not fail + diff --git a/ldb/tests/schema-tests/schema-mod-test-4.ldif b/ldb/tests/schema-tests/schema-mod-test-4.ldif new file mode 100644 index 000000000..cbf0e60bb --- /dev/null +++ b/ldb/tests/schema-tests/schema-mod-test-4.ldif @@ -0,0 +1,5 @@ +dn: CN=Test,CN=Users,DC=schema,DC=test +changetype: modify +add: foo +foo: this test must fail + diff --git a/ldb/tests/schema-tests/schema-mod-test-5.ldif b/ldb/tests/schema-tests/schema-mod-test-5.ldif new file mode 100644 index 000000000..bc64e9edb --- /dev/null +++ b/ldb/tests/schema-tests/schema-mod-test-5.ldif @@ -0,0 +1,5 @@ +dn: CN=Test,CN=Users,DC=schema,DC=test +changetype: modify +delete: nTSecurityDescriptor +# this test must fail + diff --git a/ldb/tests/schema-tests/schema.ldif b/ldb/tests/schema-tests/schema.ldif new file mode 100644 index 000000000..4ab193283 --- /dev/null +++ b/ldb/tests/schema-tests/schema.ldif @@ -0,0 +1,100 @@ +dn: @INDEXLIST +@IDXATTR: name +@IDXATTR: sAMAccountName +@IDXATTR: objectSid +@IDXATTR: objectClass +@IDXATTR: member +@IDXATTR: uidNumber +@IDXATTR: gidNumber +@IDXATTR: unixName +@IDXATTR: privilege +@IDXATTR: lDAPDisplayName + +dn: @ATTRIBUTES +realm: CASE_INSENSITIVE +userPrincipalName: CASE_INSENSITIVE +servicePrincipalName: CASE_INSENSITIVE +name: CASE_INSENSITIVE +dn: CASE_INSENSITIVE +sAMAccountName: CASE_INSENSITIVE +objectClass: CASE_INSENSITIVE +unicodePwd: HIDDEN +ntPwdHash: HIDDEN +ntPwdHistory: HIDDEN +lmPwdHash: HIDDEN +lmPwdHistory: HIDDEN +createTimestamp: HIDDEN +modifyTimestamp: HIDDEN + +dn: @MODULES +@LIST: timestamps,schema + +dn: CN=Top,CN=Schema,CN=Configuration,DC=schema,DC=test +objectClass: top +objectClass: classSchema +lDAPDisplayName: top +cn: Top +uSNCreated: 1 +uSNChanged: 1 +subClassOf: top +systemMustContain: objectClass +systemMayContain: structuralObjectClass +systemMayContain: createTimeStamp +systemMayContain: modifyTimeStamp +systemMayContain: creatorsName +systemMayContain: modifiersName +systemMayContain: hasSubordinates +systemMayContain: subschemaSubentry +systemMayContain: collectiveSubentry +systemMayContain: entryUUID +systemMayContain: entryCSN +systemMayContain: namingCSN +systemMayContain: superiorUUID +systemMayContain: contextCSN +systemMayContain: whenCreated +systemMayContain: whenChanged +systemMayContain: uSNCreated +systemMayContain: uSNChanged +systemMayContain: distinguishedName +systemMayContain: name +systemMayContain: cn +systemMayContain: userPassword +systemMayContain: labeledURI + +dn: CN=Class-Schema,CN=Schema,CN=Configuration,DC=schema,DC=test +objectClass: top +objectClass: classSchema +lDAPDisplayName: classSchema +cn: Class-Schema +uSNCreated: 2 +uSNChanged: 2 +lDAPDisplayName: classSchema +subClassOf: top +systemMustContain: cn +systemMustContain: subClassOf +systemMayContain: systemPossSuperiors +systemMayContain: systemOnly +systemMayContain: systemMustContain +systemMayContain: systemMayContain +systemMayContain: systemAuxiliaryClass +systemMayContain: possSuperiors +systemMayContain: mustContain +systemMayContain: mayContain +systemMayContain: lDAPDisplayName +systemMayContain: auxiliaryClass + +dn: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=schema,DC=test +objectClass: top +objectClass: classSchema +cn: Attribute-Schema +uSNCreated: 3 +uSNChanged: 3 +lDAPDisplayName: attributeSchema +subClassOf: top +systemMustContain: oMSyntax +systemMustContain: lDAPDisplayName +systemMustContain: isSingleValued +systemMustContain: cn +systemMustContain: attributeSyntax +systemMustContain: attributeID + diff --git a/ldb/tests/slapd.conf b/ldb/tests/slapd.conf new file mode 100644 index 000000000..fa2789d8c --- /dev/null +++ b/ldb/tests/slapd.conf @@ -0,0 +1,26 @@ +loglevel 0 + +include tests/schema/core.schema +include tests/schema/cosine.schema +include tests/schema/inetorgperson.schema +include tests/schema/openldap.schema +include tests/schema/nis.schema + + +pidfile tests/tmp/slapd.pid +argsfile tests/tmp/slapd.args + +access to * by * write + +allow update_anon bind_anon_dn + +include tests/tmp/modules.conf + +defaultsearchbase "o=University of Michigan,c=TEST" + +backend bdb +database bdb +suffix "o=University of Michigan,c=TEST" +directory tests/tmp/db +index objectClass eq +index uid eq diff --git a/ldb/tests/start_slapd.sh b/ldb/tests/start_slapd.sh new file mode 100755 index 000000000..11679d47a --- /dev/null +++ b/ldb/tests/start_slapd.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ -z "$LDBDIR" ]; then + LDBDIR=`dirname $0`/.. + export LDBDIR +fi + +mkdir -p $LDBDIR/tests/tmp/db + +# running slapd in the background (with &) means it stays in the same process group, so it can be +# killed by timelimit +slapd -d0 -f $LDBDIR/tests/slapd.conf -h "`$LDBDIR/tests/ldapi_url.sh`" $* & + +sleep 2 diff --git a/ldb/tests/test-attribs.ldif b/ldb/tests/test-attribs.ldif new file mode 100644 index 000000000..79508c4b7 --- /dev/null +++ b/ldb/tests/test-attribs.ldif @@ -0,0 +1,6 @@ +dn: @ATTRIBUTES +uid: CASE_INSENSITIVE +cn: CASE_INSENSITIVE +ou: CASE_INSENSITIVE +dn: CASE_INSENSITIVE + diff --git a/ldb/tests/test-config.ldif b/ldb/tests/test-config.ldif new file mode 100644 index 000000000..7926a9e3c --- /dev/null +++ b/ldb/tests/test-config.ldif @@ -0,0 +1,67 @@ +############################## +# global configuration options +dn: cn=Global,cn=Config,cn=Samba +objectclass: globalconfig +LocalConfigCn: cn=%U,cn=Config,cn=Samba +LocalConfigCn;1: cn=%U,cn=Config,cn=Samba +LocalConfigCn;2: cn=%I,cn=Config,cn=Samba +LocalConfigCn;3: cn=%M,cn=Config,cn=Samba + +############# +dn: cn=Protocol,cn=Global,cn=Config,cn=Samba +maxXmit: 7000 + +################################ +dn: cn=Volker,cn=Config,cn=Samba +Workgroup: VNET3 +UnixCharset: UTF8 +Security: user +Interfaces: vmnet* eth* +NetbiosName: blu +GuestAccount: tridge + +################################# +dn: cn=Volker,cn=Config,cn=Samba +Workgroup: VNET3 +UnixCharset: UTF8 +Security: user +Interfaces: vmnet* eth* +NetbiosName: blu +GuestAccount: tridge +Include: cn=%U,cn=MyConfig,cn=Config,cn=Samba + +#### ((objectClass=fileshare)(cn=test)) +############################## +# [test] share +dn: cn=test,cn=Shares,cn=Config,cn=Samba +objectclass: fileshare +cn: test +Comment: a test share +Path: /home/tridge/samba4/prefix/test +ReadOnly: no + +##################################### +# [msdn] a remote proxy share, stored +# on \\msdn\test +dn: cn=msdn,cn=Shares,cn=Config,cn=Samba +objectclass: fileshare +cn: msdn +NtvfsHandler: cifs +ReadOnly: no +_CifsServer: msdn +_CifsUser: administrator +_CifsPassword: penguin +_CifsDomain: winxp +_CifsShare: test + + +############################## +# [VisualC] share +dn: cn=visualc,cn=Shares,cn=Config,cn=Samba +objectclass: fileshare +cn: VisualC +Comment: VisualC development +Path: /home/tridge/VisualC +ReadOnly: no +NtvfsHandler: simple + diff --git a/ldb/tests/test-default-config.ldif b/ldb/tests/test-default-config.ldif new file mode 100644 index 000000000..87b7bcd3c --- /dev/null +++ b/ldb/tests/test-default-config.ldif @@ -0,0 +1,17 @@ +############################## +# global configuration options +dn: cn=Global,cn=DefaultConfig,cn=Samba +objectclass: globalconfig +Workgroup: WORKGROUP +UnixCharset: UTF8 +Security: user +NetbiosName: blu +GuestAccount: nobody + +############################## +# [_default_] share +dn: cn=_default_,cn=Shares,cn=DefaultConfig,cn=Samba +objectclass: fileshare +cn: _default_ +Path: /tmp +ReadOnly: yes diff --git a/ldb/tests/test-extended.sh b/ldb/tests/test-extended.sh new file mode 100755 index 000000000..a84e3b78a --- /dev/null +++ b/ldb/tests/test-extended.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +echo "Running extended search tests" + +mv $LDB_URL $LDB_URL.1 + +cat < /dev/null && { + echo "Should have failed to add again - gave $?" + exit 1 +} + +echo "Modifying elements" +$VALGRIND ldbmodify $LDBDIR/tests/test-modify.ldif || exit 1 + +echo "Showing modified record" +$VALGRIND ldbsearch '(uid=uham)' || exit 1 + +echo "Rename entry" +OLDDN="cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST" +NEWDN="cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST" +$VALGRIND ldbrename "$OLDDN" "$NEWDN" || exit 1 + +echo "Showing renamed record" +$VALGRIND ldbsearch '(uid=uham)' || exit 1 + +echo "Starting ldbtest" +$VALGRIND ldbtest --num-records 100 --num-searches 10 || exit 1 + +if [ $LDB_SPECIALS = 1 ]; then + echo "Adding index" + $VALGRIND ldbadd $LDBDIR/tests/test-index.ldif || exit 1 +fi + +echo "Adding bad attributes - should fail" +$VALGRIND ldbadd $LDBDIR/tests/test-wrong_attributes.ldif && { + echo "Should fhave failed - gave $?" + exit 1 +} + +echo "testing indexed search" +$VALGRIND ldbsearch '(uid=uham)' || exit 1 +$VALGRIND ldbsearch '(&(objectclass=person)(objectclass=person)(objectclass=top))' || exit 1 +$VALGRIND ldbsearch '(&(uid=uham)(uid=uham))' || exit 1 +$VALGRIND ldbsearch '(|(uid=uham)(uid=uham))' || exit 1 +$VALGRIND ldbsearch '(|(uid=uham)(uid=uham)(objectclass=OpenLDAPperson))' || exit 1 +$VALGRIND ldbsearch '(&(uid=uham)(uid=uham)(!(objectclass=xxx)))' || exit 1 +$VALGRIND ldbsearch '(&(objectclass=person)(uid=uham)(!(uid=uhamxx)))' uid \* \+ dn || exit 1 +$VALGRIND ldbsearch '(&(uid=uham)(uid=uha*)(title=*))' uid || exit 1 + +# note that the "((" is treated as an attribute not an expression +# this matches the openldap ldapsearch behaviour of looking for a '=' +# to see if the first argument is an expression or not +$VALGRIND ldbsearch '((' uid || exit 1 +$VALGRIND ldbsearch '(objectclass=)' uid || exit 1 +$VALGRIND ldbsearch -b 'cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' -s base "" sn || exit 1 + +echo "Test wildcard match" +$VALGRIND ldbadd $LDBDIR/tests/test-wildcard.ldif || exit 1 +$VALGRIND ldbsearch '(cn=test*multi)' || exit 1 +$VALGRIND ldbsearch '(cn=*test*multi*)' || exit 1 +$VALGRIND ldbsearch '(cn=*test_multi)' || exit 1 +$VALGRIND ldbsearch '(cn=test_multi*)' || exit 1 +$VALGRIND ldbsearch '(cn=test*multi*test*multi)' || exit 1 +$VALGRIND ldbsearch '(cn=test*multi*test*multi*multi_*)' || exit 1 + +echo "Starting ldbtest indexed" +$VALGRIND ldbtest --num-records 100 --num-searches 500 || exit 1 + +echo "Testing one level search" +count=`$VALGRIND ldbsearch -b 'ou=Groups,o=University of Michigan,c=TEST' -s one 'objectclass=*' none |grep '^dn' | wc -l` +if [ $count != 3 ]; then + echo returned $count records - expected 3 + exit 1 +fi + +echo "Testing binary file attribute value" +mkdir -p tests/tmp +cp $LDBDIR/tests/samba4.png tests/tmp/samba4.png +$VALGRIND ldbmodify $LDBDIR/tests/photo.ldif || exit 1 +count=`$VALGRIND ldbsearch '(cn=Hampster Ursula)' jpegPhoto | grep '^dn' | wc -l` +if [ $count != 1 ]; then + echo returned $count records - expected 1 + exit 1 +fi +rm -f tests/tmp/samba4.png + +echo "*TODO* Testing UTF8 upper lower case searches !!" + +echo "Testing compare" +count=`$VALGRIND ldbsearch '(cn>=t)' cn | grep '^dn' | wc -l` +if [ $count != 2 ]; then + echo returned $count records - expected 2 + echo "this fails on openLdap ..." +fi + +count=`$VALGRIND ldbsearch '(cn<=t)' cn | grep '^dn' | wc -l` +if [ $count != 13 ]; then + echo returned $count records - expected 13 + echo "this fails on opsnLdap ..." +fi + +checkcount() { + count=$1 + scope=$2 + basedn=$3 + expression="$4" + n=`bin/ldbsearch -s "$scope" -b "$basedn" "$expression" | grep '^dn' | wc -l` + if [ $n != $count ]; then + echo "Got $n but expected $count for $expression" + bin/ldbsearch "$expression" + exit 1 + fi + echo "OK: $count $expression" +} + +checkcount 0 'base' '' '(uid=uham)' +checkcount 0 'one' '' '(uid=uham)' + +checkcount 1 'base' 'cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' '(uid=uham)' +checkcount 1 'one' 'ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' '(uid=uham)' +checkcount 1 'one' 'ou=People,o=University of Michigan,c=TEST' '(ou=ldb test)' diff --git a/ldb/tests/test-index.ldif b/ldb/tests/test-index.ldif new file mode 100644 index 000000000..268173641 --- /dev/null +++ b/ldb/tests/test-index.ldif @@ -0,0 +1,7 @@ +dn: @INDEXLIST +@IDXATTR: uid +@IDXATTR: objectclass + +dn: @ATTRIBUTES +uid: CASE_INSENSITIVE + diff --git a/ldb/tests/test-ldap.sh b/ldb/tests/test-ldap.sh new file mode 100755 index 000000000..14cfb5f97 --- /dev/null +++ b/ldb/tests/test-ldap.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +PATH=/usr/local/sbin:/usr/sbin:/sbin:$PATH +export PATH +SCHEMA_NEEDED="core nis cosine inetorgperson openldap" + +# setup needed schema files +for f in $SCHEMA_NEEDED; do + if [ ! -r tests/schema/$f.schema ]; then + mkdir -p tests/schema + if [ -r /etc/ldap/schema/$f.schema ]; then + ln -s /etc/ldap/schema/$f.schema tests/schema/$f.schema + continue; + fi + if [ -r /etc/openldap/schema/$f.schema ]; then + ln -s /etc/openldap/schema/$f.schema tests/schema/$f.schema + continue; + fi + + echo "SKIPPING TESTS: you need the following OpenLDAP schema files" + for f in $SCHEMA_NEEDED; do + echo " $f.schema" + done + exit 0 + fi +done + +if [ -z "$LDBDIR" ]; then + LDBDIR=`dirname $0`/.. + export LDBDIR +fi + +LDB_URL=`$LDBDIR/tests/ldapi_url.sh` +export LDB_URL + +PATH=bin:$PATH +export PATH + +LDB_SPECIALS=0 +export LDB_SPECIALS + +if $LDBDIR/tests/init_slapd.sh && + $LDBDIR/tests/start_slapd.sh && + $LDBDIR/tests/test-generic.sh; then + echo "ldap tests passed"; + ret=0 +else + echo "ldap tests failed"; + ret=$? +fi + +#$LDBDIR/tests/kill_slapd.sh + +exit $ret diff --git a/ldb/tests/test-modify.ldif b/ldb/tests/test-modify.ldif new file mode 100644 index 000000000..e5b9ca408 --- /dev/null +++ b/ldb/tests/test-modify.ldif @@ -0,0 +1,23 @@ +dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga + n,c=TEST +changetype: modify +add: drink +drink: mango lassi +- +add: drink +drink: lemonade +- +delete: pager +- +replace: telephonenumber +telephonenumber: +61 2 6260 6012 +telephonenumber: +61 412 666 929 +- +delete: telephonenumber +telephonenumber: +61 2 6260 6012 +- +delete: telephonenumber +telephonenumber: +61 412 666 929 +- +add: telephonenumber +telephonenumber: +61 412 666 929 diff --git a/ldb/tests/test-schema.sh b/ldb/tests/test-schema.sh new file mode 100755 index 000000000..2f10fb45e --- /dev/null +++ b/ldb/tests/test-schema.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +LDB_URL="tdb://schema.ldb" +export LDB_URL + +rm -f schema.ldb + +echo "LDB_URL: $LDB_URL" + +echo "Adding schema" +$VALGRIND bin/ldbadd $LDBDIR/tests/schema-tests/schema.ldif || exit 1 + +echo "Adding few test elements (no failure expected here)" +$VALGRIND bin/ldbadd $LDBDIR/tests/schema-tests/schema-add-test.ldif || exit 1 + +echo "Modifying elements (2 failures expected here)" + +$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-1.ldif || exit 1 +$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-2.ldif || exit 1 +$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-3.ldif || exit 1 +$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-4.ldif +if [ "$?" == "0" ]; then + echo "test failed!" + exit 1 +fi +$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-5.ldif +if [ "$?" == "0" ]; then + echo "test failed!" + exit 1 +fi + +echo "Showing modified record" +$VALGRIND bin/ldbsearch '(cn=Test)' || exit 1 + diff --git a/ldb/tests/test-soloading.sh b/ldb/tests/test-soloading.sh new file mode 100755 index 000000000..da6d57541 --- /dev/null +++ b/ldb/tests/test-soloading.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +if [ -n "$TEST_DATA_PREFIX" ]; then + LDB_URL="$TEST_DATA_PREFIX/tdbtest.ldb" +else + LDB_URL="tdbtest.ldb" +fi +export LDB_URL + +PATH=bin:$PATH +export PATH + +rm -f $LDB_URL* + +if [ -z "$LDBDIR" ]; then + LDBDIR=`dirname $0`/.. + export LDBDIR +fi + +cat <. +*/ + +#include "ldb_includes.h" +#include "tools/cmdline.h" + +#if (_SAMBA_BUILD_ >= 4) +#include "includes.h" +#include "lib/cmdline/popt_common.h" +#include "lib/ldb-samba/ldif_handlers.h" +#include "auth/gensec/gensec.h" +#include "auth/auth.h" +#include "ldb_wrap.h" +#include "param/param.h" +#endif + + + +/** + process command line options +*/ +struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, + int argc, const char **argv, + void (*usage)(void)) +{ + static struct ldb_cmdline options; /* needs to be static for older compilers */ + struct ldb_cmdline *ret=NULL; + poptContext pc; +#if (_SAMBA_BUILD_ >= 4) + int r; +#endif + int num_options = 0; + int opt; + int flags = 0; + + struct poptOption popt_options[] = { + POPT_AUTOHELP + { "url", 'H', POPT_ARG_STRING, &options.url, 0, "database URL", "URL" }, + { "basedn", 'b', POPT_ARG_STRING, &options.basedn, 0, "base DN", "DN" }, + { "editor", 'e', POPT_ARG_STRING, &options.editor, 0, "external editor", "PROGRAM" }, + { "scope", 's', POPT_ARG_STRING, NULL, 's', "search scope", "SCOPE" }, + { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "increase verbosity", NULL }, + { "interactive", 'i', POPT_ARG_NONE, &options.interactive, 0, "input from stdin", NULL }, + { "recursive", 'r', POPT_ARG_NONE, &options.recursive, 0, "recursive delete", NULL }, + { "modules-path", 0, POPT_ARG_STRING, &options.modules_path, 0, "modules path", "PATH" }, + { "num-searches", 0, POPT_ARG_INT, &options.num_searches, 0, "number of test searches", NULL }, + { "num-records", 0, POPT_ARG_INT, &options.num_records, 0, "number of test records", NULL }, + { "all", 'a', POPT_ARG_NONE, &options.all_records, 0, "(|(objectClass=*)(distinguishedName=*))", NULL }, + { "nosync", 0, POPT_ARG_NONE, &options.nosync, 0, "non-synchronous transactions", NULL }, + { "sorted", 'S', POPT_ARG_NONE, &options.sorted, 0, "sort attributes", NULL }, + { "input", 'I', POPT_ARG_STRING, &options.input, 0, "Input File", "Input" }, + { "output", 'O', POPT_ARG_STRING, &options.output, 0, "Output File", "Output" }, + { NULL, 'o', POPT_ARG_STRING, NULL, 'o', "ldb_connect option", "OPTION" }, + { "controls", 0, POPT_ARG_STRING, NULL, 'c', "controls", NULL }, +#if (_SAMBA_BUILD_ >= 4) + POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS + POPT_COMMON_CONNECTION + POPT_COMMON_VERSION +#endif + { NULL } + }; + +#if (_SAMBA_BUILD_ >= 4) + r = ldb_register_samba_handlers(ldb); + if (r != 0) { + goto failed; + } + +#endif + + ret = talloc_zero(ldb, struct ldb_cmdline); + if (ret == NULL) { + ldb_oom(ldb); + goto failed; + } + + options = *ret; + + /* pull in URL */ + options.url = getenv("LDB_URL"); + + /* and editor (used by ldbedit) */ + options.editor = getenv("VISUAL"); + if (!options.editor) { + options.editor = getenv("EDITOR"); + } + if (!options.editor) { + options.editor = "vi"; + } + + options.scope = LDB_SCOPE_DEFAULT; + + pc = poptGetContext(argv[0], argc, argv, popt_options, + POPT_CONTEXT_KEEP_FIRST); + + while((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case 's': { + const char *arg = poptGetOptArg(pc); + if (strcmp(arg, "base") == 0) { + options.scope = LDB_SCOPE_BASE; + } else if (strcmp(arg, "sub") == 0) { + options.scope = LDB_SCOPE_SUBTREE; + } else if (strcmp(arg, "one") == 0) { + options.scope = LDB_SCOPE_ONELEVEL; + } else { + fprintf(stderr, "Invalid scope '%s'\n", arg); + goto failed; + } + break; + } + + case 'v': + options.verbose++; + break; + + case 'o': + options.options = talloc_realloc(ret, options.options, + const char *, num_options+3); + if (options.options == NULL) { + ldb_oom(ldb); + goto failed; + } + options.options[num_options] = poptGetOptArg(pc); + options.options[num_options+1] = NULL; + num_options++; + break; + + case 'c': { + const char *cs = poptGetOptArg(pc); + const char *p, *q; + int cc; + + for (p = cs, cc = 1; (q = strchr(p, ',')); cc++, p = q + 1) ; + + options.controls = talloc_array(ret, char *, cc + 1); + if (options.controls == NULL) { + ldb_oom(ldb); + goto failed; + } + for (p = cs, cc = 0; p != NULL; cc++) { + const char *t; + + t = strchr(p, ','); + if (t == NULL) { + options.controls[cc] = talloc_strdup(options.controls, p); + p = NULL; + } else { + options.controls[cc] = talloc_strndup(options.controls, p, t-p); + p = t + 1; + } + } + options.controls[cc] = NULL; + + break; + } + default: + fprintf(stderr, "Invalid option %s: %s\n", + poptBadOption(pc, 0), poptStrerror(opt)); + if (usage) usage(); + goto failed; + } + } + + /* setup the remaining options for the main program to use */ + options.argv = poptGetArgs(pc); + if (options.argv) { + options.argv++; + while (options.argv[options.argc]) options.argc++; + } + + *ret = options; + + /* all utils need some option */ + if (ret->url == NULL) { + fprintf(stderr, "You must supply a url with -H or with $LDB_URL\n"); + if (usage) usage(); + goto failed; + } + + if (strcmp(ret->url, "NONE") == 0) { + return ret; + } + + if (options.nosync) { + flags |= LDB_FLG_NOSYNC; + } + +#if (_SAMBA_BUILD_ >= 4) + /* Must be after we have processed command line options */ + gensec_init(cmdline_lp_ctx); + + if (ldb_set_opaque(ldb, "sessionInfo", system_session(ldb, cmdline_lp_ctx))) { + goto failed; + } + if (ldb_set_opaque(ldb, "credentials", cmdline_credentials)) { + goto failed; + } + if (ldb_set_opaque(ldb, "loadparm", cmdline_lp_ctx)) { + goto failed; + } + + ldb_set_utf8_fns(ldb, NULL, wrap_casefold); +#endif + + if (options.modules_path != NULL) { + ldb_set_modules_dir(ldb, options.modules_path); + } else if (getenv("LDB_MODULES_PATH") != NULL) { + ldb_set_modules_dir(ldb, getenv("LDB_MODULES_PATH")); + } + + /* now connect to the ldb */ + if (ldb_connect(ldb, ret->url, flags, ret->options) != 0) { + fprintf(stderr, "Failed to connect to %s - %s\n", + ret->url, ldb_errstring(ldb)); + goto failed; + } + + return ret; + +failed: + talloc_free(ret); + exit(1); + return NULL; +} + +/* this function check controls reply and determines if more + * processing is needed setting up the request controls correctly + * + * returns: + * -1 error + * 0 all ok + * 1 all ok, more processing required + */ +int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request) +{ + int i, j; + int ret = 0; + + if (reply == NULL || request == NULL) return -1; + + for (i = 0; reply[i]; i++) { + if (strcmp(LDB_CONTROL_VLV_RESP_OID, reply[i]->oid) == 0) { + struct ldb_vlv_resp_control *rep_control; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_vlv_resp_control); + + /* check we have a matching control in the request */ + for (j = 0; request[j]; j++) { + if (strcmp(LDB_CONTROL_VLV_REQ_OID, request[j]->oid) == 0) + break; + } + if (! request[j]) { + fprintf(stderr, "Warning VLV reply received but no request have been made\n"); + continue; + } + + /* check the result */ + if (rep_control->vlv_result != 0) { + fprintf(stderr, "Warning: VLV not performed with error: %d\n", rep_control->vlv_result); + } else { + fprintf(stderr, "VLV Info: target position = %d, content count = %d\n", rep_control->targetPosition, rep_control->contentCount); + } + + continue; + } + + if (strcmp(LDB_CONTROL_ASQ_OID, reply[i]->oid) == 0) { + struct ldb_asq_control *rep_control; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_asq_control); + + /* check the result */ + if (rep_control->result != 0) { + fprintf(stderr, "Warning: ASQ not performed with error: %d\n", rep_control->result); + } + + continue; + } + + if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, reply[i]->oid) == 0) { + struct ldb_paged_control *rep_control, *req_control; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_paged_control); + if (rep_control->cookie_len == 0) /* we are done */ + break; + + /* more processing required */ + /* let's fill in the request control with the new cookie */ + + for (j = 0; request[j]; j++) { + if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, request[j]->oid) == 0) + break; + } + /* if there's a reply control we must find a request + * control matching it */ + if (! request[j]) return -1; + + req_control = talloc_get_type(request[j]->data, struct ldb_paged_control); + + if (req_control->cookie) + talloc_free(req_control->cookie); + req_control->cookie = (char *)talloc_memdup( + req_control, rep_control->cookie, + rep_control->cookie_len); + req_control->cookie_len = rep_control->cookie_len; + + ret = 1; + + continue; + } + + if (strcmp(LDB_CONTROL_SORT_RESP_OID, reply[i]->oid) == 0) { + struct ldb_sort_resp_control *rep_control; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_sort_resp_control); + + /* check we have a matching control in the request */ + for (j = 0; request[j]; j++) { + if (strcmp(LDB_CONTROL_SERVER_SORT_OID, request[j]->oid) == 0) + break; + } + if (! request[j]) { + fprintf(stderr, "Warning Server Sort reply received but no request found\n"); + continue; + } + + /* check the result */ + if (rep_control->result != 0) { + fprintf(stderr, "Warning: Sorting not performed with error: %d\n", rep_control->result); + } + + continue; + } + + if (strcmp(LDB_CONTROL_DIRSYNC_OID, reply[i]->oid) == 0) { + struct ldb_dirsync_control *rep_control, *req_control; + char *cookie; + + rep_control = talloc_get_type(reply[i]->data, struct ldb_dirsync_control); + if (rep_control->cookie_len == 0) /* we are done */ + break; + + /* more processing required */ + /* let's fill in the request control with the new cookie */ + + for (j = 0; request[j]; j++) { + if (strcmp(LDB_CONTROL_DIRSYNC_OID, request[j]->oid) == 0) + break; + } + /* if there's a reply control we must find a request + * control matching it */ + if (! request[j]) return -1; + + req_control = talloc_get_type(request[j]->data, struct ldb_dirsync_control); + + if (req_control->cookie) + talloc_free(req_control->cookie); + req_control->cookie = (char *)talloc_memdup( + req_control, rep_control->cookie, + rep_control->cookie_len); + req_control->cookie_len = rep_control->cookie_len; + + cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len); + printf("# DIRSYNC cookie returned was:\n# %s\n", cookie); + + continue; + } + + /* no controls matched, throw a warning */ + fprintf(stderr, "Unknown reply control oid: %s\n", reply[i]->oid); + } + + return ret; +} + diff --git a/ldb/tools/cmdline.h b/ldb/tools/cmdline.h new file mode 100644 index 000000000..3473d62a1 --- /dev/null +++ b/ldb/tools/cmdline.h @@ -0,0 +1,54 @@ +/* + ldb database library - command line handling for ldb tools + + Copyright (C) Andrew Tridgell 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +#include + +struct ldb_cmdline { + const char *url; + enum ldb_scope scope; + const char *basedn; + const char *modules_path; + int interactive; + int sorted; + const char *editor; + int verbose; + int recursive; + int all_records; + int nosync; + const char **options; + int argc; + const char **argv; + int num_records; + int num_searches; + const char *sasl_mechanism; + const char *input; + const char *output; + char **controls; +}; + +struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, int argc, const char **argv, + void (*usage)(void)); + + +struct ldb_control **parse_controls(void *mem_ctx, char **control_strings); +int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request); diff --git a/ldb/tools/config.mk b/ldb/tools/config.mk new file mode 100644 index 000000000..6b57929df --- /dev/null +++ b/ldb/tools/config.mk @@ -0,0 +1,90 @@ +################################################ +# Start SUBSYSTEM LIBLDB_CMDLINE +[SUBSYSTEM::LIBLDB_CMDLINE] +CFLAGS = -I$(ldbsrcdir) -I$(ldbsrcdir)/include +PUBLIC_DEPENDENCIES = LIBLDB LIBPOPT +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL POPT_SAMBA POPT_CREDENTIALS gensec +# End SUBSYSTEM LIBLDB_CMDLINE +################################################ + +LIBLDB_CMDLINE_OBJ_FILES = $(ldbsrcdir)/tools/cmdline.o + +################################################ +# Start BINARY ldbadd +[BINARY::ldbadd] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE LIBCLI_RESOLVE +# End BINARY ldbadd +################################################ + + +ldbadd_OBJ_FILES = $(ldbsrcdir)/tools/ldbadd.o + +MANPAGES += $(ldbsrcdir)/man/ldbadd.1 + +################################################ +# Start BINARY ldbdel +[BINARY::ldbdel] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbdel +################################################ + +ldbdel_OBJ_FILES = $(ldbsrcdir)/tools/ldbdel.o + +MANPAGES += $(ldbsrcdir)/man/ldbdel.1 + +################################################ +# Start BINARY ldbmodify +[BINARY::ldbmodify] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbmodify +################################################ + +ldbmodify_OBJ_FILES = $(ldbsrcdir)/tools/ldbmodify.o +MANPAGES += $(ldbsrcdir)/man/ldbmodify.1 + +################################################ +# Start BINARY ldbsearch +[BINARY::ldbsearch] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbsearch +################################################ + +ldbsearch_OBJ_FILES = $(ldbsrcdir)/tools/ldbsearch.o + +MANPAGES += $(ldbsrcdir)/man/ldbsearch.1 + +################################################ +# Start BINARY ldbedit +[BINARY::ldbedit] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbedit +################################################ + +ldbedit_OBJ_FILES = $(ldbsrcdir)/tools/ldbedit.o + +MANPAGES += $(ldbsrcdir)/man/ldbedit.1 + +################################################ +# Start BINARY ldbrename +[BINARY::ldbrename] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBLDB_CMDLINE +# End BINARY ldbrename +################################################ + +ldbrename_OBJ_FILES = $(ldbsrcdir)/tools/ldbrename.o + +MANPAGES += $(ldbsrcdir)/man/ldbrename.1 + + diff --git a/ldb/tools/ldbadd.c b/ldb/tools/ldbadd.c new file mode 100644 index 000000000..15376e734 --- /dev/null +++ b/ldb/tools/ldbadd.c @@ -0,0 +1,116 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldbadd + * + * Description: utility to add records - modelled on ldapadd + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" +#include "tools/cmdline.h" + +static int failures; + +static void usage(void) +{ + printf("Usage: ldbadd \n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Adds records to a ldb, reading ldif the specified list of files\n\n"); + exit(1); +} + + +/* + add records from an opened file +*/ +static int process_file(struct ldb_context *ldb, FILE *f, int *count) +{ + struct ldb_ldif *ldif; + int ret = LDB_SUCCESS; + + while ((ldif = ldb_ldif_read_file(ldb, f))) { + if (ldif->changetype != LDB_CHANGETYPE_ADD && + ldif->changetype != LDB_CHANGETYPE_NONE) { + fprintf(stderr, "Only CHANGETYPE_ADD records allowed\n"); + break; + } + + ldif->msg = ldb_msg_canonicalize(ldb, ldif->msg); + + ret = ldb_add(ldb, ldif->msg); + if (ret != LDB_SUCCESS) { + fprintf(stderr, "ERR: \"%s\" on DN %s\n", + ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn)); + failures++; + } else { + (*count)++; + } + ldb_ldif_read_free(ldb, ldif); + } + + return ret; +} + + + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int i, ret=0, count=0; + struct ldb_cmdline *options; + + ldb = ldb_init(NULL, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc == 0) { + ret = process_file(ldb, stdin, &count); + } else { + for (i=0;iargc;i++) { + const char *fname = options->argv[i]; + FILE *f; + f = fopen(fname, "r"); + if (!f) { + perror(fname); + exit(1); + } + ret = process_file(ldb, f, &count); + fclose(f); + } + } + + talloc_free(ldb); + + printf("Added %d records with %d failures\n", count, failures); + + return ret; +} diff --git a/ldb/tools/ldbdel.c b/ldb/tools/ldbdel.c new file mode 100644 index 000000000..e66d4fb97 --- /dev/null +++ b/ldb/tools/ldbdel.c @@ -0,0 +1,115 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldbdel + * + * Description: utility to delete records - modelled on ldapdelete + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" +#include "tools/cmdline.h" + +static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn) +{ + int ret, i, total=0; + const char *attrs[] = { NULL }; + struct ldb_result *res; + + ret = ldb_search(ldb, dn, LDB_SCOPE_SUBTREE, "distinguishedName=*", attrs, &res); + if (ret != LDB_SUCCESS) return -1; + + for (i = 0; i < res->count; i++) { + if (ldb_delete(ldb, res->msgs[i]->dn) == 0) { + total++; + } + } + + talloc_free(res); + + if (total == 0) { + return -1; + } + printf("Deleted %d records\n", total); + return 0; +} + +static void usage(void) +{ + printf("Usage: ldbdel \n"); + printf("Options:\n"); + printf(" -r recursively delete the given subtree\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Deletes records from a ldb\n\n"); + exit(1); +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int ret = 0, i; + struct ldb_cmdline *options; + + ldb = ldb_init(NULL, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc < 1) { + usage(); + exit(1); + } + + for (i=0;iargc;i++) { + struct ldb_dn *dn; + + dn = ldb_dn_new(ldb, ldb, options->argv[i]); + if ( ! ldb_dn_validate(dn)) { + printf("Invalid DN format\n"); + exit(1); + } + if (options->recursive) { + ret = ldb_delete_recursive(ldb, dn); + } else { + ret = ldb_delete(ldb, dn); + if (ret == 0) { + printf("Deleted 1 record\n"); + } + } + if (ret != 0) { + printf("delete of '%s' failed - %s\n", + ldb_dn_get_linearized(dn), + ldb_errstring(ldb)); + } + } + + talloc_free(ldb); + + return ret; +} diff --git a/ldb/tools/ldbedit.c b/ldb/tools/ldbedit.c new file mode 100644 index 000000000..e58a5a271 --- /dev/null +++ b/ldb/tools/ldbedit.c @@ -0,0 +1,329 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldbedit + * + * Description: utility for ldb database editing + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" +#include "tools/cmdline.h" + +static struct ldb_cmdline *options; + +/* + debug routine +*/ +static void ldif_write_msg(struct ldb_context *ldb, + FILE *f, + enum ldb_changetype changetype, + struct ldb_message *msg) +{ + struct ldb_ldif ldif; + ldif.changetype = changetype; + ldif.msg = msg; + ldb_ldif_write_file(ldb, f, &ldif); +} + +/* + modify a database record so msg1 becomes msg2 + returns the number of modified elements +*/ +static int modify_record(struct ldb_context *ldb, + struct ldb_message *msg1, + struct ldb_message *msg2) +{ + struct ldb_message *mod; + + mod = ldb_msg_diff(ldb, msg1, msg2); + if (mod == NULL) { + fprintf(stderr, "Failed to calculate message differences\n"); + return -1; + } + + if (mod->num_elements == 0) { + return 0; + } + + if (options->verbose > 0) { + ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_MODIFY, mod); + } + + if (ldb_modify(ldb, mod) != 0) { + fprintf(stderr, "failed to modify %s - %s\n", + ldb_dn_get_linearized(msg1->dn), ldb_errstring(ldb)); + return -1; + } + + return mod->num_elements; +} + +/* + find dn in msgs[] +*/ +static struct ldb_message *msg_find(struct ldb_context *ldb, + struct ldb_message **msgs, + int count, + struct ldb_dn *dn) +{ + int i; + for (i=0;idn) == 0) { + return msgs[i]; + } + } + return NULL; +} + +/* + merge the changes in msgs2 into the messages from msgs1 +*/ +static int merge_edits(struct ldb_context *ldb, + struct ldb_message **msgs1, int count1, + struct ldb_message **msgs2, int count2) +{ + int i; + struct ldb_message *msg; + int ret = 0; + int adds=0, modifies=0, deletes=0; + + /* do the adds and modifies */ + for (i=0;idn); + if (!msg) { + if (options->verbose > 0) { + ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_ADD, msgs2[i]); + } + if (ldb_add(ldb, msgs2[i]) != 0) { + fprintf(stderr, "failed to add %s - %s\n", + ldb_dn_get_linearized(msgs2[i]->dn), + ldb_errstring(ldb)); + return -1; + } + adds++; + } else { + if (modify_record(ldb, msg, msgs2[i]) > 0) { + modifies++; + } + } + } + + /* do the deletes */ + for (i=0;idn); + if (!msg) { + if (options->verbose > 0) { + ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_DELETE, msgs1[i]); + } + if (ldb_delete(ldb, msgs1[i]->dn) != 0) { + fprintf(stderr, "failed to delete %s - %s\n", + ldb_dn_get_linearized(msgs1[i]->dn), + ldb_errstring(ldb)); + return -1; + } + deletes++; + } + } + + printf("# %d adds %d modifies %d deletes\n", adds, modifies, deletes); + + return ret; +} + +/* + save a set of messages as ldif to a file +*/ +static int save_ldif(struct ldb_context *ldb, + FILE *f, struct ldb_message **msgs, int count) +{ + int i; + + fprintf(f, "# editing %d records\n", count); + + for (i=0;imsg; + } + + fclose(f); + unlink(file_template); + + return merge_edits(ldb, msgs1, count1, msgs2, count2); +} + +static void usage(void) +{ + printf("Usage: ldbedit \n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -s base|sub|one choose search scope\n"); + printf(" -b basedn choose baseDN\n"); + printf(" -a edit all records (expression 'objectclass=*')\n"); + printf(" -e editor choose editor (or $VISUAL or $EDITOR)\n"); + printf(" -v verbose mode\n"); + exit(1); +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + struct ldb_result *result = NULL; + struct ldb_dn *basedn = NULL; + int ret; + const char *expression = "(|(objectClass=*)(distinguishedName=*))"; + const char * const * attrs = NULL; + + ldb = ldb_init(NULL, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + /* the check for '=' is for compatibility with ldapsearch */ + if (options->argc > 0 && + strchr(options->argv[0], '=')) { + expression = options->argv[0]; + options->argv++; + options->argc--; + } + + if (options->argc > 0) { + attrs = (const char * const *)(options->argv); + } + + if (options->basedn != NULL) { + basedn = ldb_dn_new(ldb, ldb, options->basedn); + if ( ! ldb_dn_validate(basedn)) { + printf("Invalid Base DN format\n"); + exit(1); + } + } + + ret = ldb_search(ldb, basedn, options->scope, expression, attrs, &result); + if (ret != LDB_SUCCESS) { + printf("search failed - %s\n", ldb_errstring(ldb)); + exit(1); + } + + if (result->count == 0) { + printf("no matching records - cannot edit\n"); + return 0; + } + + do_edit(ldb, result->msgs, result->count, options->editor); + + if (result) { + ret = talloc_free(result); + if (ret == -1) { + fprintf(stderr, "talloc_free failed\n"); + exit(1); + } + } + + talloc_free(ldb); + return 0; +} diff --git a/ldb/tools/ldbmodify.c b/ldb/tools/ldbmodify.c new file mode 100644 index 000000000..6e355a10c --- /dev/null +++ b/ldb/tools/ldbmodify.c @@ -0,0 +1,116 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldbmodify + * + * Description: utility to modify records - modelled on ldapmodify + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" +#include "tools/cmdline.h" + +static int failures; + +static void usage(void) +{ + printf("Usage: ldbmodify \n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Modifies a ldb based upon ldif change records\n\n"); + exit(1); +} + +/* + process modifies for one file +*/ +static int process_file(struct ldb_context *ldb, FILE *f, int *count) +{ + struct ldb_ldif *ldif; + int ret = LDB_SUCCESS; + + while ((ldif = ldb_ldif_read_file(ldb, f))) { + switch (ldif->changetype) { + case LDB_CHANGETYPE_NONE: + case LDB_CHANGETYPE_ADD: + ret = ldb_add(ldb, ldif->msg); + break; + case LDB_CHANGETYPE_DELETE: + ret = ldb_delete(ldb, ldif->msg->dn); + break; + case LDB_CHANGETYPE_MODIFY: + ret = ldb_modify(ldb, ldif->msg); + break; + } + if (ret != LDB_SUCCESS) { + fprintf(stderr, "ERR: \"%s\" on DN %s\n", + ldb_errstring(ldb), ldb_dn_get_linearized(ldif->msg->dn)); + failures++; + } else { + (*count)++; + } + ldb_ldif_read_free(ldb, ldif); + } + + return ret; +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int count=0; + int i, ret=LDB_SUCCESS; + struct ldb_cmdline *options; + + ldb = ldb_init(NULL, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc == 0) { + ret = process_file(ldb, stdin, &count); + } else { + for (i=0;iargc;i++) { + const char *fname = options->argv[i]; + FILE *f; + f = fopen(fname, "r"); + if (!f) { + perror(fname); + exit(1); + } + ret = process_file(ldb, f, &count); + } + } + + talloc_free(ldb); + + printf("Modified %d records with %d failures\n", count, failures); + + return ret; +} diff --git a/ldb/tools/ldbrename.c b/ldb/tools/ldbrename.c new file mode 100644 index 000000000..a5feb7a09 --- /dev/null +++ b/ldb/tools/ldbrename.c @@ -0,0 +1,90 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldbrename + * + * Description: utility to rename records - modelled on ldapmodrdn + * + * Author: Andrew Tridgell + * Author: Stefan Metzmacher + */ + +#include "ldb_includes.h" +#include "tools/cmdline.h" + +static void usage(void) +{ + printf("Usage: ldbrename [] \n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + printf("\n"); + printf("Renames records in a ldb\n\n"); + exit(1); +} + + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + int ret; + struct ldb_cmdline *options; + struct ldb_dn *dn1, *dn2; + + ldb = ldb_init(NULL, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + if (options->argc < 2) { + usage(); + } + + dn1 = ldb_dn_new(ldb, ldb, options->argv[0]); + dn2 = ldb_dn_new(ldb, ldb, options->argv[1]); + + if ( ! ldb_dn_validate(dn1)) { + printf("Invalid DN1: %s\n", options->argv[0]); + return -1; + } + if ( ! ldb_dn_validate(dn2)) { + printf("Invalid DN2: %s\n", options->argv[1]); + return -1; + } + + ret = ldb_rename(ldb, dn1, dn2); + if (ret == 0) { + printf("Renamed 1 record\n"); + } else { + printf("rename of '%s' to '%s' failed - %s\n", + options->argv[0], options->argv[1], ldb_errstring(ldb)); + } + + talloc_free(ldb); + + return ret; +} diff --git a/ldb/tools/ldbsearch.c b/ldb/tools/ldbsearch.c new file mode 100644 index 000000000..b3d1f934a --- /dev/null +++ b/ldb/tools/ldbsearch.c @@ -0,0 +1,320 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldbsearch + * + * Description: utility for ldb search - modelled on ldapsearch + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" +#include "tools/cmdline.h" + +static void usage(void) +{ + printf("Usage: ldbsearch \n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" -s base|sub|one choose search scope\n"); + printf(" -b basedn choose baseDN\n"); + printf(" -i read search expressions from stdin\n"); + printf(" -S sort returned attributes\n"); + printf(" -o options pass options like modules to activate\n"); + printf(" e.g: -o modules:timestamps\n"); + exit(1); +} + +static int do_compare_msg(struct ldb_message **el1, + struct ldb_message **el2, + void *opaque) +{ + return ldb_dn_compare((*el1)->dn, (*el2)->dn); +} + +struct search_context { + struct ldb_control **req_ctrls; + + int sort; + int num_stored; + struct ldb_message **store; + int refs_stored; + char **refs_store; + + int entries; + int refs; + + int pending; + int status; +}; + +static int store_message(struct ldb_message *msg, struct search_context *sctx) { + + sctx->store = talloc_realloc(sctx, sctx->store, struct ldb_message *, sctx->num_stored + 2); + if (!sctx->store) { + fprintf(stderr, "talloc_realloc failed while storing messages\n"); + return -1; + } + + sctx->store[sctx->num_stored] = talloc_move(sctx->store, &msg); + sctx->num_stored++; + sctx->store[sctx->num_stored] = NULL; + + return 0; +} + +static int store_referral(char *referral, struct search_context *sctx) { + + sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs_stored + 2); + if (!sctx->refs_store) { + fprintf(stderr, "talloc_realloc failed while storing referrals\n"); + return -1; + } + + sctx->refs_store[sctx->refs_stored] = talloc_move(sctx->refs_store, &referral); + sctx->refs_stored++; + sctx->refs_store[sctx->refs_stored] = NULL; + + return 0; +} + +static int display_message(struct ldb_context *ldb, struct ldb_message *msg, struct search_context *sctx) { + struct ldb_ldif ldif; + + sctx->entries++; + printf("# record %d\n", sctx->entries); + + ldif.changetype = LDB_CHANGETYPE_NONE; + ldif.msg = msg; + + if (sctx->sort) { + /* + * Ensure attributes are always returned in the same + * order. For testing, this makes comparison of old + * vs. new much easier. + */ + ldb_msg_sort_elements(ldif.msg); + } + + ldb_ldif_write_file(ldb, stdout, &ldif); + + return 0; +} + +static int display_referral(char *referral, struct search_context *sctx) +{ + + sctx->refs++; + printf("# Referral\nref: %s\n\n", referral); + + return 0; +} + +static int search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct search_context *sctx = talloc_get_type(context, struct search_context); + int ret; + + switch (ares->type) { + + case LDB_REPLY_ENTRY: + if (sctx->sort) { + ret = store_message(ares->message, sctx); + } else { + ret = display_message(ldb, ares->message, sctx); + } + break; + + case LDB_REPLY_REFERRAL: + if (sctx->sort) { + ret = store_referral(ares->referral, sctx); + } else { + ret = display_referral(ares->referral, sctx); + } + break; + + case LDB_REPLY_DONE: + if (ares->controls) { + if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1) + sctx->pending = 1; + } + ret = 0; + break; + + default: + fprintf(stderr, "unknown Reply Type\n"); + return LDB_ERR_OTHER; + } + + if (talloc_free(ares) == -1) { + fprintf(stderr, "talloc_free failed\n"); + sctx->pending = 0; + return LDB_ERR_OPERATIONS_ERROR; + } + + if (ret) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; +} + +static int do_search(struct ldb_context *ldb, + struct ldb_dn *basedn, + struct ldb_cmdline *options, + const char *expression, + const char * const *attrs) +{ + struct ldb_request *req; + struct search_context *sctx; + int ret; + + req = talloc(ldb, struct ldb_request); + if (!req) return -1; + + sctx = talloc(req, struct search_context); + if (!sctx) return -1; + + sctx->sort = options->sorted; + sctx->num_stored = 0; + sctx->refs_stored = 0; + sctx->store = NULL; + sctx->req_ctrls = ldb_parse_control_strings(ldb, sctx, (const char **)options->controls); + if (options->controls != NULL && sctx->req_ctrls== NULL) { + printf("parsing controls failed: %s\n", ldb_errstring(ldb)); + return -1; + } + sctx->entries = 0; + sctx->refs = 0; + + if (basedn == NULL) { + basedn = ldb_get_default_basedn(ldb); + } + + req->operation = LDB_SEARCH; + req->op.search.base = basedn; + req->op.search.scope = options->scope; + req->op.search.tree = ldb_parse_tree(req, expression); + if (req->op.search.tree == NULL) return -1; + req->op.search.attrs = attrs; + req->controls = sctx->req_ctrls; + req->context = sctx; + req->callback = &search_callback; + ldb_set_timeout(ldb, req, 0); /* TODO: make this settable by command line */ + +again: + sctx->pending = 0; + + ret = ldb_request(ldb, req); + if (ret != LDB_SUCCESS) { + printf("search failed - %s\n", ldb_errstring(ldb)); + return -1; + } + + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + if (ret != LDB_SUCCESS) { + printf("search error - %s\n", ldb_errstring(ldb)); + return -1; + } + + if (sctx->pending) + goto again; + + if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) { + int i; + + if (sctx->num_stored) { + ldb_qsort(sctx->store, sctx->num_stored, sizeof(struct ldb_message *), + ldb, (ldb_qsort_cmp_fn_t)do_compare_msg); + } + for (i = 0; i < sctx->num_stored; i++) { + display_message(ldb, sctx->store[i], sctx); + } + + for (i = 0; i < sctx->refs_stored; i++) { + display_referral(sctx->refs_store[i], sctx); + } + } + + printf("# returned %d records\n# %d entries\n# %d referrals\n", + sctx->entries + sctx->refs, sctx->entries, sctx->refs); + + talloc_free(req); + + return 0; +} + +int main(int argc, const char **argv) +{ + struct ldb_context *ldb; + struct ldb_dn *basedn = NULL; + const char * const * attrs = NULL; + struct ldb_cmdline *options; + int ret = -1; + const char *expression = "(|(objectClass=*)(distinguishedName=*))"; + + ldb = ldb_init(NULL, NULL); + if (ldb == NULL) { + return -1; + } + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + /* the check for '=' is for compatibility with ldapsearch */ + if (!options->interactive && + options->argc > 0 && + strchr(options->argv[0], '=')) { + expression = options->argv[0]; + options->argv++; + options->argc--; + } + + if (options->argc > 0) { + attrs = (const char * const *)(options->argv); + } + + if (options->basedn != NULL) { + basedn = ldb_dn_new(ldb, ldb, options->basedn); + if ( ! ldb_dn_validate(basedn)) { + fprintf(stderr, "Invalid Base DN format\n"); + exit(1); + } + } + + if (options->interactive) { + char line[1024]; + while (fgets(line, sizeof(line), stdin)) { + if (do_search(ldb, basedn, options, line, attrs) == -1) { + ret = -1; + } + } + } else { + ret = do_search(ldb, basedn, options, expression, attrs); + } + + talloc_free(ldb); + return ret; +} diff --git a/ldb/tools/ldbtest.c b/ldb/tools/ldbtest.c new file mode 100644 index 000000000..169ff02da --- /dev/null +++ b/ldb/tools/ldbtest.c @@ -0,0 +1,418 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** 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 . +*/ + +/* + * Name: ldb + * + * Component: ldbtest + * + * Description: utility to test ldb + * + * Author: Andrew Tridgell + */ + +#include "ldb_includes.h" +#include "tools/cmdline.h" + +static struct timeval tp1,tp2; +static struct ldb_cmdline *options; + +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 add_records(struct ldb_context *ldb, + struct ldb_dn *basedn, + int count) +{ + struct ldb_message msg; + int i; + +#if 0 + if (ldb_lock(ldb, "transaction") != 0) { + printf("transaction lock failed\n"); + exit(1); + } +#endif + for (i=0;icount != 1)) { + printf("Failed to find %s - %s\n", expr, ldb_errstring(ldb)); + exit(1); + } + + if (uid >= nrecords && res->count > 0) { + printf("Found %s !? - %d\n", expr, ret); + exit(1); + } + + printf("testing uid %d/%d - %d \r", i, uid, res->count); + fflush(stdout); + + talloc_free(res); + talloc_free(expr); + } + + printf("\n"); +} + +static void start_test(struct ldb_context *ldb, int nrecords, int nsearches) +{ + struct ldb_dn *basedn; + + basedn = ldb_dn_new(ldb, ldb, options->basedn); + if ( ! ldb_dn_validate(basedn)) { + printf("Invalid base DN\n"); + exit(1); + } + + printf("Adding %d records\n", nrecords); + add_records(ldb, basedn, nrecords); + + printf("Starting search on uid\n"); + _start_timer(); + search_uid(ldb, basedn, nrecords, nsearches); + printf("uid search took %.2f seconds\n", _end_timer()); + + printf("Modifying records\n"); + modify_records(ldb, basedn, nrecords); + + printf("Deleting records\n"); + delete_records(ldb, basedn, nrecords); +} + + +/* + 2) Store an @indexlist record + + 3) Store a record that contains fields that should be index according +to @index + + 4) disconnection from database + + 5) connect to same database + + 6) search for record added in step 3 using a search key that should +be indexed +*/ +static void start_test_index(struct ldb_context **ldb) +{ + struct ldb_message *msg; + struct ldb_result *res = NULL; + struct ldb_dn *indexlist; + struct ldb_dn *basedn; + int ret; + int flags = 0; + const char *specials; + + specials = getenv("LDB_SPECIALS"); + if (specials && atoi(specials) == 0) { + printf("LDB_SPECIALS disabled - skipping index test\n"); + return; + } + + if (options->nosync) { + flags |= LDB_FLG_NOSYNC; + } + + printf("Starting index test\n"); + + indexlist = ldb_dn_new(*ldb, *ldb, "@INDEXLIST"); + + ldb_delete(*ldb, indexlist); + + msg = ldb_msg_new(NULL); + + msg->dn = indexlist; + ldb_msg_add_string(msg, "@IDXATTR", strdup("uid")); + + if (ldb_add(*ldb, msg) != 0) { + printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb)); + exit(1); + } + + basedn = ldb_dn_new(*ldb, *ldb, options->basedn); + + memset(msg, 0, sizeof(*msg)); + msg->dn = ldb_dn_copy(msg, basedn); + ldb_dn_add_child_fmt(msg->dn, "cn=test"); + ldb_msg_add_string(msg, "cn", strdup("test")); + ldb_msg_add_string(msg, "sn", strdup("test")); + ldb_msg_add_string(msg, "uid", strdup("test")); + ldb_msg_add_string(msg, "objectClass", strdup("OpenLDAPperson")); + + if (ldb_add(*ldb, msg) != 0) { + printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb)); + exit(1); + } + + if (talloc_free(*ldb) != 0) { + printf("failed to free/close ldb database"); + exit(1); + } + + (*ldb) = ldb_init(options, NULL); + + ret = ldb_connect(*ldb, options->url, flags, NULL); + if (ret != 0) { + printf("failed to connect to %s\n", options->url); + exit(1); + } + + basedn = ldb_dn_new(*ldb, *ldb, options->basedn); + + ret = ldb_search(*ldb, basedn, LDB_SCOPE_SUBTREE, "uid=test", NULL, &res); + if (ret != LDB_SUCCESS) { + printf("Search with (uid=test) filter failed!\n"); + exit(1); + } + if(res->count != 1) { + printf("Should have found 1 record - found %d\n", res->count); + exit(1); + } + + indexlist = ldb_dn_new(*ldb, *ldb, "@INDEXLIST"); + + if (ldb_delete(*ldb, msg->dn) != 0 || + ldb_delete(*ldb, indexlist) != 0) { + printf("cleanup failed - %s\n", ldb_errstring(*ldb)); + exit(1); + } + + printf("Finished index test\n"); +} + + +static void usage(void) +{ + printf("Usage: ldbtest \n"); + printf("Options:\n"); + printf(" -H ldb_url choose the database (or $LDB_URL)\n"); + printf(" --num-records nrecords database size to use\n"); + printf(" --num-searches nsearches number of searches to do\n"); + printf("\n"); + printf("tests ldb API\n\n"); + exit(1); +} + +int main(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct ldb_context *ldb; + + ldb = ldb_init(mem_ctx, NULL); + + options = ldb_cmdline_process(ldb, argc, argv, usage); + + talloc_steal(mem_ctx, options); + + if (options->basedn == NULL) { + options->basedn = "ou=Ldb Test,ou=People,o=University of Michigan,c=TEST"; + } + + srandom(1); + + printf("Testing with num-records=%d and num-searches=%d\n", + options->num_records, options->num_searches); + + start_test(ldb, options->num_records, options->num_searches); + + start_test_index(&ldb); + + talloc_free(mem_ctx); + + return 0; +} diff --git a/ldb/web/index.html b/ldb/web/index.html new file mode 100644 index 000000000..26dd34452 --- /dev/null +++ b/ldb/web/index.html @@ -0,0 +1,86 @@ + + + +ldb + + + +

ldb

+ +ldb is a LDAP-like embedded database. It is not at all +LDAP +standards compliant, so if you want a standards compliant database then please +see the excellent OpenLDAP +project.

+ +What ldb does is provide a fast database with an LDAP-like API +designed to be used within an application. In some ways it can be seen +as a intermediate solution between key-value pair databases and a real +LDAP database.

+ +ldb is the database engine used in Samba4. + +

Features

+ +The main features that separate ldb from other solutions are: + +
    +
  • Safe multi-reader, multi-writer, using byte range locking +
  • LDAP-like API +
  • fast operation +
  • choice of local tdb or remote LDAP backends +
  • integration with talloc +
  • schema-less operation, for trivial setup +
  • modules for extensions (such as schema support) +
  • easy setup of indexes and attribute properties +
  • LDIF for import/export +
  • ldbedit tool for database (via LDIF) editing (reminiscent of 'vipw') +
+ +

Documentation

+ +Currently ldb is completely lacking in programmer or user +documentation. This is your opportunity to make a contribution! Start +with the public functions declared in ldb.h +and the example code in the tools +directory. Documentation in the same docbook format used by Samba +would be preferred. + +

Discussion and bug reports

+ +ldb does not currently have its own mailing list or bug tracking +system. For now, please use the samba-technical +mailing list or the ldb +mailing list, and the Samba bugzilla bug tracking system. + +

Download

+ +You can download the latest release either via rsync or thtough git.
+
+To fetch via git see the following guide:
+Using Git for Samba Development
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/ldb directory.
+
+To fetch via rsync use these commands: + +
+  rsync -Pavz samba.org::ftp/unpacked/ldb .
+  rsync -Pavz samba.org::ftp/unpacked/tdb .
+  rsync -Pavz samba.org::ftp/unpacked/talloc .
+  rsync -Pavz samba.org::ftp/unpacked/libreplace .
+
+ +and build in ldb. It will find the other libraries in the directory +above automatically. + +
+ +Andrew Tridgell
+ldb AT tridgell.net +
+ + + diff --git a/replace/.checker_innocent b/replace/.checker_innocent new file mode 100644 index 000000000..e61917654 --- /dev/null +++ b/replace/.checker_innocent @@ -0,0 +1,4 @@ +>>>MISTAKE21_create_files_6a9e68ada99a97cb +>>>MISTAKE21_os2_delete_9b2bfa7f38711d09 +>>>MISTAKE21_os2_delete_2fcc29aaa99a97cb +>>>SECURITY2_os2_delete_9b2bfa7f1c9396ca diff --git a/replace/Makefile.in b/replace/Makefile.in new file mode 100644 index 000000000..008d1830b --- /dev/null +++ b/replace/Makefile.in @@ -0,0 +1,70 @@ +#!gmake +# +CC = @CC@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +includedir = @includedir@ +libdir = @libdir@ +VPATH = @libreplacedir@ +srcdir = @srcdir@ +builddir = @builddir@ +buildinstdir = @buildinstdir@ +INSTALL = @INSTALL@ +LIBS = @LIBS@ + +.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)' + @echo ' LIBS = $(LIBS)' + +install: all + mkdir -p $(libdir) + $(INSTALL) libreplace.a $(libdir) + +build-install: all + mkdir -p $(buildinstdir)/include + $(INSTALL) replace.h $(buildinstdir)/include + mkdir -p $(buildinstdir)/lib + $(INSTALL) libreplace.a $(buildinstdir)/lib + +libreplace.a: $(OBJS) + ar -rcsv $@ $(OBJS) + +test: all + ./testsuite + +installcheck: install test + +TEST_OBJS = test/testsuite.o test/os2_delete.o test/strptime.o test/getifaddrs.o + +testsuite: libreplace.a $(TEST_OBJS) + $(CC) -o testsuite $(TEST_OBJS) -L. -lreplace $(LDFLAGS) $(LIBS) + +.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 diff --git a/replace/README b/replace/README new file mode 100644 index 000000000..4d94317c4 --- /dev/null +++ b/replace/README @@ -0,0 +1,113 @@ +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 +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 +inet_aton +strtoll +strtoull +socketpair +strptime +getaddrinfo +freeaddrinfo +getnameinfo +gai_strerror +getifaddrs +freeifaddrs +utime +utimes + +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) diff --git a/replace/aclocal.m4 b/replace/aclocal.m4 new file mode 100644 index 000000000..5605e476b --- /dev/null +++ b/replace/aclocal.m4 @@ -0,0 +1 @@ +m4_include(libreplace.m4) diff --git a/replace/autoconf-2.60.m4 b/replace/autoconf-2.60.m4 new file mode 100644 index 000000000..acdcd38ef --- /dev/null +++ b/replace/autoconf-2.60.m4 @@ -0,0 +1,210 @@ +# 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 +#include +#include +#include +#include + +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. +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]) +]) diff --git a/replace/autogen.sh b/replace/autogen.sh new file mode 100755 index 000000000..d46a4279f --- /dev/null +++ b/replace/autogen.sh @@ -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 + diff --git a/replace/build_macros.m4 b/replace/build_macros.m4 new file mode 100644 index 000000000..bc3ec729d --- /dev/null +++ b/replace/build_macros.m4 @@ -0,0 +1,14 @@ +AC_DEFUN(BUILD_WITH_BUILD_INST_DIR, + [ AC_ARG_WITH([build-install-dir], + [AC_HELP_STRING([--with-build-install-dir=DIR], + [temporary build directory where libraries are installed [$srcdir/buildinst]])]) + + buildinstdir="$srcdir/buildinst" + if test x"$with_build_install_dir" != x; then + buildinstdir=$with_build_install_dir + CFLAGS="$CFLAGS -I$with_build_install_dir/include" + LDFLAGS="$LDFLAGS -L$with_build_install_dir/lib" + fi + AC_SUBST(buildinstdir) + ]) + diff --git a/replace/config.guess b/replace/config.guess new file mode 100755 index 000000000..354dbe175 --- /dev/null +++ b/replace/config.guess @@ -0,0 +1,1464 @@ +#! /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 Free Software Foundation, Inc. + +timestamp='2005-08-03' + +# 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 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 . +# +# 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 . +# Please send patches to . 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 ." + +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 +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 -q "$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@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 ;; + *) 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 ;; + macppc:MirBSD:*:*) + echo powerppc-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@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 ;; + 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.*:*) + echo i386-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 /* 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 + + 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:*:[45]) + 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 + #include + + 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 + 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:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*: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 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [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:*:*) + 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 | grep ^CPU=` + 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 | grep ^CPU=` + 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 ;; + 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 ;; + x86_64:Linux:*:*) + echo x86_64-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 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + 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 + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + 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' /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 i386. + echo i386-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; } ;; + 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 + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@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 ;; + 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 ;; + 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 + *86) UNAME_PROCESSOR=i686 ;; + 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 ;; +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 < +# include +#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 + 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 +# 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 < 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: diff --git a/replace/config.sub b/replace/config.sub new file mode 100755 index 000000000..23cd6fd75 --- /dev/null +++ b/replace/config.sub @@ -0,0 +1,1577 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-08' + +# 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 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 . +# +# 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 . 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 ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +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-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-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 + ;; + -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/'` + ;; + -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 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + 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) + ;; + + # 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-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | 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[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # 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 + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + 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 + ;; + cr16c) + basic_machine=cr16c-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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + 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 + ;; + 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 + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + 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 + ;; + 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 + ;; + 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[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + 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* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -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* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -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*) + # 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 + ;; + -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 + *-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 + ;; + 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: diff --git a/replace/configure.ac b/replace/configure.ac new file mode 100644 index 000000000..20a7582b5 --- /dev/null +++ b/replace/configure.ac @@ -0,0 +1,33 @@ +AC_PREREQ(2.50) +AC_INIT(replace.c) +AC_CONFIG_SRCDIR([replace.c]) +AC_CONFIG_HEADER(config.h) + +CFLAGS="$CFLAGS -I$srcdir" + +AC_LIBREPLACE_ALL_CHECKS +AC_LIBREPLACE_NETWORK_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 + +m4_include(build_macros.m4) +BUILD_WITH_BUILD_INST_DIR + +LIBS="${LIBREPLACE_NETWORK_LIBS}" +AC_SUBST(LIBS) + +AC_SUBST(LDFLAGS) + +AC_OUTPUT(Makefile) diff --git a/replace/dlfcn.c b/replace/dlfcn.c new file mode 100644 index 000000000..3b109d7e4 --- /dev/null +++ b/replace/dlfcn.c @@ -0,0 +1,75 @@ +/* + 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 . +*/ + +#include "replace.h" +#ifdef HAVE_DL_H +#include +#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 + if (name == NULL) + return PROG_HANDLE; + 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 diff --git a/replace/dlfcn.m4 b/replace/dlfcn.m4 new file mode 100644 index 000000000..42f56f26b --- /dev/null +++ b/replace/dlfcn.m4 @@ -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 + ]) + +if test x"${libreplace_cv_dlfcn}" = x"yes";then + LIBREPLACEOBJ="${LIBREPLACEOBJ} dlfcn.o" +fi + +LIBDL="$LIBS" +AC_SUBST(LIBDL) +LIBS="$save_LIBS" diff --git a/replace/getaddrinfo.c b/replace/getaddrinfo.c new file mode 100644 index 000000000..c5cd52be9 --- /dev/null +++ b/replace/getaddrinfo.c @@ -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; +} diff --git a/replace/getaddrinfo.h b/replace/getaddrinfo.h new file mode 100644 index 000000000..dddd699b6 --- /dev/null +++ b/replace/getaddrinfo.h @@ -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 */ diff --git a/replace/getifaddrs.c b/replace/getifaddrs.c new file mode 100644 index 000000000..f6f0ec080 --- /dev/null +++ b/replace/getifaddrs.c @@ -0,0 +1,361 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Jeremy Allison 2007 + Copyright (C) Jelmer Vernooij 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 . +*/ + +#define SOCKET_WRAPPER_NOT_REPLACE + +#include "replace.h" +#include "system/network.h" + +#include +#include +#include + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifndef SIOCGIFCONF +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#endif + +#ifdef HAVE_IFACE_GETIFADDRS +#define _FOUND_IFACE_ANY +#else + +void rep_freeifaddrs(struct ifaddrs *ifp) +{ + if (ifp != NULL) { + free(ifp->ifa_name); + free(ifp->ifa_addr); + free(ifp->ifa_netmask); + free(ifp->ifa_dstaddr); + 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; + struct in_addr ipaddr; + struct in_addr nmask; + char *iname; + struct ifaddrs *curif; + struct ifaddrs *lastif = NULL; + + *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; i--) { + if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) { + freeifaddrs(*ifap); + return -1; + } + + curif = calloc(1, sizeof(struct ifaddrs)); + curif->ifa_name = strdup(ifr[i].ifr_name); + curif->ifa_flags = ifr[i].ifr_flags; + curif->ifa_dstaddr = NULL; + curif->ifa_data = NULL; + curif->ifa_next = NULL; + + curif->ifa_addr = NULL; + if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) { + curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr); + } + + curif->ifa_netmask = NULL; + if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) { + curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr); + } + + if (lastif == NULL) { + *ifap = curif; + } else { + lastif->ifa_next = curif; + } + lastif = curif; + } + + close(fd); + + return 0; +} + +#define _FOUND_IFACE_ANY +#endif /* HAVE_IFACE_IFCONF */ +#ifdef HAVE_IFACE_IFREQ + +#ifndef I_STR +#include +#endif + +/**************************************************************************** +this should cover most of the streams based systems +Thanks to Andrej.Borsenkow@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; + struct in_addr ipaddr; + struct in_addr nmask; + char *iname; + struct ifaddrs *curif; + struct ifaddrs *lastif = NULL; + + *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; iifa_next = curif; + } + + 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; + struct ifaddrs *curif; + struct ifaddrs *lastif = NULL; + + *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 = curif; + } + + 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@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 diff --git a/replace/getpass.c b/replace/getpass.c new file mode 100644 index 000000000..73333b902 --- /dev/null +++ b/replace/getpass.c @@ -0,0 +1,225 @@ +/* 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 . */ + +/* 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); + if (fgets(buf, bufsize, in) == NULL) { + buf[0] = 0; + if (in && in != stdin) { + fclose(in); + } + return buf; + } + } + 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("Interupted by signal.\n"); + fflush(stdout); + exit(1); + } + return buf; +} diff --git a/replace/getpass.ho b/replace/getpass.ho new file mode 100644 index 000000000..d73c0b21e Binary files /dev/null and b/replace/getpass.ho differ diff --git a/replace/getpass.m4 b/replace/getpass.m4 new file mode 100644 index 000000000..b93817f9d --- /dev/null +++ b/replace/getpass.m4 @@ -0,0 +1,24 @@ +AC_CHECK_FUNC(getpass, libreplace_cv_HAVE_GETPASS=yes) +AC_CHECK_FUNC(getpassphrase, libreplace_cv_HAVE_GETPASSPHRASE=yes) +if test x"$libreplace_cv_HAVE_GETPASS" = x"yes" -a x"$libreplace_cv_HAVE_GETPASSPHRASE" = x"yes"; then + AC_DEFINE(REPLACE_GETPASS_BY_GETPASSPHRASE, 1, [getpass returns <9 chars where getpassphrase returns <265 chars]) + AC_DEFINE(REPLACE_GETPASS,1,[Whether getpass should be replaced]) + LIBREPLACEOBJ="${LIBREPLACEOBJ} getpass.o" +else + +AC_CACHE_CHECK([whether getpass should be replaced],libreplace_cv_REPLACE_GETPASS,[ +SAVE_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -I$libreplacedir/" +AC_TRY_COMPILE([ +#include "confdefs.h" +#define NO_CONFIG_H +#include "$libreplacedir/getpass.c" +],[],libreplace_cv_REPLACE_GETPASS=yes,libreplace_cv_REPLACE_GETPASS=no) +CPPFLAGS="$SAVE_CPPFLAGS" +]) +if test x"$libreplace_cv_REPLACE_GETPASS" = x"yes"; then + AC_DEFINE(REPLACE_GETPASS,1,[Whether getpass should be replaced]) + LIBREPLACEOBJ="${LIBREPLACEOBJ} getpass.o" +fi + +fi diff --git a/replace/inet_aton.c b/replace/inet_aton.c new file mode 100644 index 000000000..c6b3bb11a --- /dev/null +++ b/replace/inet_aton.c @@ -0,0 +1,33 @@ +/* + * Unix SMB/CIFS implementation. + * replacement functions + * Copyright (C) Michael Adam 2008 + * + * ** 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 . + */ + +#include "replace.h" +#include "system/network.h" + +/** + * We know that we have inet_pton from earlier libreplace checks. + */ +int rep_inet_aton(const char *src, struct in_addr *dst) +{ + return (inet_pton(AF_INET, src, dst) > 0) ? 1 : 0; +} diff --git a/replace/inet_ntoa.c b/replace/inet_ntoa.c new file mode 100644 index 000000000..e3b80ebef --- /dev/null +++ b/replace/inet_ntoa.c @@ -0,0 +1,39 @@ +/* + * Unix SMB/CIFS implementation. + * replacement routines for broken systems + * Copyright (C) Andrew Tridgell 2003 + * Copyright (C) Michael Adam 2008 + * + * ** 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 . + */ + +#include "replace.h" +#include "system/network.h" + +/** + * NOTE: this is not thread safe, but it can't be, either + * since it returns a pointer to static memory. + */ +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; +} diff --git a/replace/inet_ntop.c b/replace/inet_ntop.c new file mode 100644 index 000000000..fb3d8e90c --- /dev/null +++ b/replace/inet_ntop.c @@ -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 */ diff --git a/replace/inet_pton.c b/replace/inet_pton.c new file mode 100644 index 000000000..80e4865ef --- /dev/null +++ b/replace/inet_pton.c @@ -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 diff --git a/replace/install-sh b/replace/install-sh new file mode 100755 index 000000000..58719246f --- /dev/null +++ b/replace/install-sh @@ -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 diff --git a/replace/libreplace.m4 b/replace/libreplace.m4 new file mode 100644 index 000000000..71fa04167 --- /dev/null +++ b/replace/libreplace.m4 @@ -0,0 +1,303 @@ +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 +#endif] +) + +AC_CHECK_TYPE(_Bool, +[AC_DEFINE(HAVE__Bool, 1, [Whether the _Bool type is available])],, +[ +AC_INCLUDES_DEFAULT +#ifdef HAVE_STDBOOL_H +#include +#endif] +) + +AC_CACHE_CHECK([for working mmap],libreplace_cv_HAVE_MMAP,[ +AC_TRY_RUN([#include "$libreplacedir/test/shared_mmap.c"], + libreplace_cv_HAVE_MMAP=yes,libreplace_cv_HAVE_MMAP=no,libreplace_cv_HAVE_MMAP=cross)]) +if test x"$libreplace_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/mount.h mntent.h) +AC_CHECK_HEADERS(stropts.h) + +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) +AC_CHECK_FUNCS(isatty) +AC_HAVE_DECL(setresuid, [#include ]) +AC_HAVE_DECL(setresgid, [#include ]) +AC_HAVE_DECL(errno, [#include ]) + +AC_CACHE_CHECK([for secure mkstemp],libreplace_cv_HAVE_SECURE_MKSTEMP,[ +AC_TRY_RUN([#include +#include +#include +#include +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); +}], +libreplace_cv_HAVE_SECURE_MKSTEMP=yes, +libreplace_cv_HAVE_SECURE_MKSTEMP=no, +libreplace_cv_HAVE_SECURE_MKSTEMP=cross)]) +if test x"$libreplace_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],libreplace_cv_HAVE_C99_VSNPRINTF,[ +AC_TRY_RUN([ +#include +#include +#include +#include +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"); } +], +libreplace_cv_HAVE_C99_VSNPRINTF=yes,libreplace_cv_HAVE_C99_VSNPRINTF=no,libreplace_cv_HAVE_C99_VSNPRINTF=cross)]) +if test x"$libreplace_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],libreplace_cv_HAVE_VA_COPY,[ +AC_TRY_LINK([#include +va_list ap1,ap2;], [va_copy(ap1,ap2);], +libreplace_cv_HAVE_VA_COPY=yes,libreplace_cv_HAVE_VA_COPY=no)]) +if test x"$libreplace_cv_HAVE_VA_COPY" = x"yes"; then + AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available]) +fi + +if test x"$libreplace_cv_HAVE_VA_COPY" != x"yes"; then +AC_CACHE_CHECK([for __va_copy],libreplace_cv_HAVE___VA_COPY,[ +AC_TRY_LINK([#include +va_list ap1,ap2;], [__va_copy(ap1,ap2);], +libreplace_cv_HAVE___VA_COPY=yes,libreplace_cv_HAVE___VA_COPY=no)]) +if test x"$libreplace_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],libreplace_cv_HAVE_FUNCTION_MACRO,[ +AC_TRY_COMPILE([#include ], [printf("%s\n", __FUNCTION__);], +libreplace_cv_HAVE_FUNCTION_MACRO=yes,libreplace_cv_HAVE_FUNCTION_MACRO=no)]) +if test x"$libreplace_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],libreplace_cv_HAVE_func_MACRO,[ + AC_TRY_COMPILE([#include ], [printf("%s\n", __func__);], + libreplace_cv_HAVE_func_MACRO=yes,libreplace_cv_HAVE_func_MACRO=no)]) + if test x"$libreplace_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 ]) +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],libreplace_cv_sig_atomic_t, [ + AC_TRY_COMPILE([ +#include +#if STDC_HEADERS +#include +#include +#endif +#include ],[sig_atomic_t i = 0], + libreplace_cv_sig_atomic_t=yes,libreplace_cv_sig_atomic_t=no)]) +if test x"$libreplace_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)],libreplace_cv_HAVE_OPEN_O_DIRECT,[ +AC_TRY_COMPILE([ +#include +#ifdef HAVE_FCNTL_H +#include +#endif], +[int fd = open("/dev/null", O_DIRECT);], +libreplace_cv_HAVE_OPEN_O_DIRECT=yes,libreplace_cv_HAVE_OPEN_O_DIRECT=no)]) +if test x"$libreplace_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],libreplace_cv_volatile, [ + AC_TRY_COMPILE([#include ],[volatile int i = 0], + libreplace_cv_volatile=yes,libreplace_cv_volatile=no)]) +if test x"$libreplace_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(repdir.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_network.m4) +m4_include(libreplace_macros.m4) + +m4_ifndef([AC_USE_SYSTEM_EXTENSIONS],[m4_include(autoconf-2.60.m4)]) diff --git a/replace/libreplace_cc.m4 b/replace/libreplace_cc.m4 new file mode 100644 index 000000000..0ce0958a9 --- /dev/null +++ b/replace/libreplace_cc.m4 @@ -0,0 +1,172 @@ + +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() + ;; + *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, long long) +AC_CHECK_TYPE(uintptr_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 + ],[ + 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 diff --git a/replace/libreplace_ld.m4 b/replace/libreplace_ld.m4 new file mode 100644 index 000000000..81bde4621 --- /dev/null +++ b/replace/libreplace_ld.m4 @@ -0,0 +1,319 @@ +# +# 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="-Wl,-expect_unresolved,\"*\"" + ;; + *darwin*) + LD_SHLIB_ALLOW_UNDEF_FLAG="-undefined dynamic_lookup" + ;; + *aix*) + LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,-bnoentry" + ;; + 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 + ;; + *netbsd*) + 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) +]) diff --git a/replace/libreplace_macros.m4 b/replace/libreplace_macros.m4 new file mode 100644 index 000000000..1856eacf6 --- /dev/null +++ b/replace/libreplace_macros.m4 @@ -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 ], + [ 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 ], + [ 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 ], + [ 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 ], + [ 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 ], + [ 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 +]) diff --git a/replace/libreplace_network.m4 b/replace/libreplace_network.m4 new file mode 100644 index 000000000..4edb55c03 --- /dev/null +++ b/replace/libreplace_network.m4 @@ -0,0 +1,377 @@ +AC_DEFUN_ONCE(AC_LIBREPLACE_NETWORK_CHECKS, +[ +echo "LIBREPLACE_NETWORK_CHECKS: START" + +AC_DEFINE(LIBREPLACE_NETWORK_CHECKS, 1, [LIBREPLACE_NETWORK_CHECKS were used]) +LIBREPLACE_NETWORK_OBJS="" +LIBREPLACE_NETWORK_LIBS="" + +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) + +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 + #endif + #include + 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_HAVE_TYPE([socklen_t],[#include ]) +AC_HAVE_TYPE([sa_family_t],[#include ]) +AC_HAVE_TYPE([struct addrinfo], [#include ]) +AC_HAVE_TYPE([struct sockaddr], [#include ]) +AC_HAVE_TYPE([struct sockaddr_storage], [ +#include +#include +#include +]) +AC_HAVE_TYPE([struct sockaddr_in6], [ +#include +#include +#include +]) + +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 +#include +#include + ]) + +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 +#include +#include + ]) +fi +fi + +AC_CACHE_CHECK([for sin_len in sock],libreplace_cv_HAVE_SOCK_SIN_LEN,[ + AC_TRY_COMPILE( + [ +#include +#include +#include + ],[ +struct sockaddr_in sock; sock.sin_len = sizeof(sock); + ],[ + libreplace_cv_HAVE_SOCK_SIN_LEN=yes + ],[ + libreplace_cv_HAVE_SOCK_SIN_LEN=no + ]) +]) +if test x"$libreplace_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 + +############################################ +# check for unix domain sockets +AC_CACHE_CHECK([for unix domain sockets],libreplace_cv_HAVE_UNIXSOCKET,[ + AC_TRY_COMPILE([ +#include +#include +#include +#include +#include + ],[ +struct sockaddr_un sunaddr; +sunaddr.sun_family = AF_UNIX; + ],[ + libreplace_cv_HAVE_UNIXSOCKET=yes + ],[ + libreplace_cv_HAVE_UNIXSOCKET=no + ]) +]) +if test x"$libreplace_cv_HAVE_UNIXSOCKET" = x"yes"; then + AC_DEFINE(HAVE_UNIXSOCKET,1,[If we need to build with unixscoket support]) +fi + +dnl The following test is roughl taken from the cvs sources. +dnl +dnl If we can't find connect, try looking in -lsocket, -lnsl, and -linet. +dnl The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has +dnl libsocket.so which has a bad implementation of gethostbyname (it +dnl only looks in /etc/hosts), so we only look for -lsocket if we need +dnl it. +AC_CHECK_FUNCS(connect) +if test x"$ac_cv_func_connect" = x"no"; then + AC_CHECK_LIB_EXT(nsl_s, LIBREPLACE_NETWORK_LIBS, connect) + AC_CHECK_LIB_EXT(nsl, LIBREPLACE_NETWORK_LIBS, connect) + AC_CHECK_LIB_EXT(socket, LIBREPLACE_NETWORK_LIBS, connect) + AC_CHECK_LIB_EXT(inet, LIBREPLACE_NETWORK_LIBS, connect) + dnl We can't just call AC_CHECK_FUNCS(connect) here, + dnl because the value has been cached. + if test x"$ac_cv_lib_ext_nsl_s_connect" = x"yes" || + test x"$ac_cv_lib_ext_nsl_connect" = x"yes" || + test x"$ac_cv_lib_ext_socket_connect" = x"yes" || + test x"$ac_cv_lib_ext_inet_connect" = x"yes" + then + AC_DEFINE(HAVE_CONNECT,1,[Whether the system has connect()]) + fi +fi + +AC_CHECK_FUNCS(gethostbyname) +if test x"$ac_cv_func_gethostbyname" = x"no"; then + AC_CHECK_LIB_EXT(nsl_s, LIBREPLACE_NETWORK_LIBS, gethostbyname) + AC_CHECK_LIB_EXT(nsl, LIBREPLACE_NETWORK_LIBS, gethostbyname) + AC_CHECK_LIB_EXT(socket, LIBREPLACE_NETWORK_LIBS, gethostbyname) + dnl We can't just call AC_CHECK_FUNCS(gethostbyname) here, + dnl because the value has been cached. + if test x"$ac_cv_lib_ext_nsl_s_gethostbyname" = x"yes" || + test x"$ac_cv_lib_ext_nsl_gethostbyname" = x"yes" || + test x"$ac_cv_lib_ext_socket_gethostbyname" = x"yes" + then + AC_DEFINE(HAVE_GETHOSTBYNAME,1, + [Whether the system has gethostbyname()]) + fi +fi + +dnl HP-UX has if_nametoindex in -lipv6 +AC_CHECK_FUNCS(if_nametoindex) +if test x"$ac_cv_func_if_nametoindex" = x"no"; then + AC_CHECK_LIB_EXT(ipv6, LIBREPLACE_NETWORK_LIBS, if_nametoindex) + dnl We can't just call AC_CHECK_FUNCS(if_nametoindex) here, + dnl because the value has been cached. + if test x"$ac_cv_lib_ext_ipv6_if_nametoindex" = x"yes" + then + AC_DEFINE(HAVE_IF_NAMETOINDEX, 1, + [Whether the system has if_nametoindex()]) + fi +fi + +# The following tests need LIBS="${LIBREPLACE_NETWORK_LIBS}" +old_LIBS=$LIBS +LIBS="${LIBREPLACE_NETWORK_LIBS}" +SAVE_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -I$libreplacedir" + +AC_CHECK_FUNCS(socketpair,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} socketpair.o"]) + +AC_CACHE_CHECK([for broken inet_ntoa],libreplace_cv_REPLACE_INET_NTOA,[ +AC_TRY_RUN([ +#include +#include +#include +#include +#ifdef HAVE_ARPA_INET_H +#include +#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);}], + libreplace_cv_REPLACE_INET_NTOA=yes,libreplace_cv_REPLACE_INET_NTOA=no,libreplace_cv_REPLACE_INET_NTOA=cross)]) + +AC_CHECK_FUNCS(inet_ntoa,[],[libreplace_cv_REPLACE_INET_NTOA=yes]) +if test x"$libreplace_cv_REPLACE_INET_NTOA" = x"yes"; then + AC_DEFINE(REPLACE_INET_NTOA,1,[Whether inet_ntoa should be replaced]) + LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} inet_ntoa.o" +fi + +AC_CHECK_FUNCS(inet_aton,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} inet_aton.o"]) + +AC_CHECK_FUNCS(inet_ntop,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} inet_ntop.o"]) + +AC_CHECK_FUNCS(inet_pton,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} inet_pton.o"]) + +dnl test for getaddrinfo/getnameinfo +AC_CACHE_CHECK([for getaddrinfo],libreplace_cv_HAVE_GETADDRINFO,[ +AC_TRY_LINK([ +#include +#if STDC_HEADERS +#include +#include +#endif +#include +#include ], +[ +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 + LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} getaddrinfo.o" +fi + +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 ]) + +dnl test for getifaddrs and freeifaddrs +AC_CACHE_CHECK([for getifaddrs and freeifaddrs],libreplace_cv_HAVE_GETIFADDRS,[ +AC_TRY_COMPILE([ +#include +#if STDC_HEADERS +#include +#include +#endif +#include +#include +#include +#include +#include ], +[ +struct ifaddrs *ifp = NULL; +int ret = getifaddrs (&ifp); +freeifaddrs(ifp); +], +libreplace_cv_HAVE_GETIFADDRS=yes,libreplace_cv_HAVE_GETIFADDRS=no)]) +if test x"$libreplace_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 +iface=no; +AC_CACHE_CHECK([for iface getifaddrs],libreplace_cv_HAVE_IFACE_GETIFADDRS,[ +AC_TRY_RUN([ +#define HAVE_IFACE_GETIFADDRS 1 +#define NO_CONFIG_H 1 +#define AUTOCONF_TEST 1 +#define SOCKET_WRAPPER_NOT_REPLACE +#include "$libreplacedir/replace.c" +#include "$libreplacedir/inet_ntop.c" +#include "$libreplacedir/snprintf.c" +#include "$libreplacedir/getifaddrs.c" +#define getifaddrs_test main +#include "$libreplacedir/test/getifaddrs.c"], + libreplace_cv_HAVE_IFACE_GETIFADDRS=yes,libreplace_cv_HAVE_IFACE_GETIFADDRS=no,libreplace_cv_HAVE_IFACE_GETIFADDRS=cross)]) +if test x"$libreplace_cv_HAVE_IFACE_GETIFADDRS" = x"yes"; then + iface=yes;AC_DEFINE(HAVE_IFACE_GETIFADDRS,1,[Whether iface getifaddrs is available]) +else + LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} getifaddrs.o" +fi + + +if test $iface = no; then +AC_CACHE_CHECK([for iface AIX],libreplace_cv_HAVE_IFACE_AIX,[ +AC_TRY_RUN([ +#define HAVE_IFACE_AIX 1 +#define NO_CONFIG_H 1 +#define AUTOCONF_TEST 1 +#undef _XOPEN_SOURCE_EXTENDED +#define SOCKET_WRAPPER_NOT_REPLACE +#include "$libreplacedir/replace.c" +#include "$libreplacedir/inet_ntop.c" +#include "$libreplacedir/snprintf.c" +#include "$libreplacedir/getifaddrs.c" +#define getifaddrs_test main +#include "$libreplacedir/test/getifaddrs.c"], + libreplace_cv_HAVE_IFACE_AIX=yes,libreplace_cv_HAVE_IFACE_AIX=no,libreplace_cv_HAVE_IFACE_AIX=cross)]) +if test x"$libreplace_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],libreplace_cv_HAVE_IFACE_IFCONF,[ +AC_TRY_RUN([ +#define HAVE_IFACE_IFCONF 1 +#define NO_CONFIG_H 1 +#define AUTOCONF_TEST 1 +#define SOCKET_WRAPPER_NOT_REPLACE +#include "$libreplacedir/replace.c" +#include "$libreplacedir/inet_ntop.c" +#include "$libreplacedir/snprintf.c" +#include "$libreplacedir/getifaddrs.c" +#define getifaddrs_test main +#include "$libreplacedir/test/getifaddrs.c"], + libreplace_cv_HAVE_IFACE_IFCONF=yes,libreplace_cv_HAVE_IFACE_IFCONF=no,libreplace_cv_HAVE_IFACE_IFCONF=cross)]) +if test x"$libreplace_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],libreplace_cv_HAVE_IFACE_IFREQ,[ +AC_TRY_RUN([ +#define HAVE_IFACE_IFREQ 1 +#define NO_CONFIG_H 1 +#define AUTOCONF_TEST 1 +#define SOCKET_WRAPPER_NOT_REPLACE +#include "$libreplacedir/replace.c" +#include "$libreplacedir/inet_ntop.c" +#include "$libreplacedir/snprintf.c" +#include "$libreplacedir/getifaddrs.c" +#define getifaddrs_test main +#include "$libreplacedir/test/getifaddrs.c"], + libreplace_cv_HAVE_IFACE_IFREQ=yes,libreplace_cv_HAVE_IFACE_IFREQ=no,libreplace_cv_HAVE_IFACE_IFREQ=cross)]) +if test x"$libreplace_cv_HAVE_IFACE_IFREQ" = x"yes"; then + iface=yes;AC_DEFINE(HAVE_IFACE_IFREQ,1,[Whether iface ifreq is available]) +fi +fi + +dnl test for ipv6 +AC_CACHE_CHECK([for ipv6 support],libreplace_cv_HAVE_IPV6,[ + AC_TRY_LINK([ +#include /* for NULL */ +#include +#include +#include + ], + [ +struct sockaddr_storage sa_store; +struct addrinfo *ai = NULL; +struct in6_addr in6addr; +int idx = if_nametoindex("iface1"); +int s = socket(AF_INET6, SOCK_STREAM, 0); +int ret = getaddrinfo(NULL, NULL, NULL, &ai); +if (ret != 0) { + const char *es = gai_strerror(ret); +} +freeaddrinfo(ai); + ],[ + libreplace_cv_HAVE_IPV6=yes + ],[ + libreplace_cv_HAVE_IPV6=no + ]) +]) +if test x"$libreplace_cv_HAVE_IPV6" = x"yes"; then + AC_DEFINE(HAVE_IPV6,1,[Whether the system has IPv6 support]) +fi + +LIBS=$old_LIBS +CPPFLAGS="$SAVE_CPPFLAGS" + +LIBREPLACEOBJ="${LIBREPLACEOBJ} ${LIBREPLACE_NETWORK_OBJS}" + +echo "LIBREPLACE_NETWORK_CHECKS: END" +]) dnl end AC_LIBREPLACE_NETWORK_CHECKS diff --git a/replace/repdir.m4 b/replace/repdir.m4 new file mode 100644 index 000000000..f53a4c297 --- /dev/null +++ b/replace/repdir.m4 @@ -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/test/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 + ]) + +AC_VERIFY_C_PROTOTYPE([int seekdir(DIR *dir, long ofs)], + [ + return 0; + ],[ + AC_DEFINE(SEEKDIR_RETURNS_INT, 1, [Whether seekdir returns an int]) + ],[],[ + #include + ]) +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/test/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/test/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 diff --git a/replace/repdir_getdents.c b/replace/repdir_getdents.c new file mode 100644 index 000000000..afc634a79 --- /dev/null +++ b/replace/repdir_getdents.c @@ -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 . +*/ +/* + 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 +#include +#include +#include +#include +#include +#include + +#define DIR_BUF_BITS 9 +#define DIR_BUF_SIZE (1<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 diff --git a/replace/repdir_getdirentries.c b/replace/repdir_getdirentries.c new file mode 100644 index 000000000..197e5931f --- /dev/null +++ b/replace/repdir_getdirentries.c @@ -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 . +*/ +/* + 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 +#include +#include +#include +#include +#include +#include + +#define DIR_BUF_BITS 9 +#define DIR_BUF_SIZE (1<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 + + diff --git a/replace/replace.c b/replace/replace.c new file mode 100644 index 000000000..106c9dfe6 --- /dev/null +++ b/replace/replace.c @@ -0,0 +1,616 @@ +/* + 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 . +*/ + +#include "replace.h" + +#include "system/filesys.h" +#include "system/time.h" +#include "system/passwd.h" +#include "system/syslog.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) { + if (bufsize < (len1+1)) { + return ret; + } + 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 +Corrections by richard.kettlewell@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 + + 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 its 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= 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 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 *)((uintptr_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 +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#if STDC_HEADERS +#include +#include +#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_UTIME +#define utime rep_utime +/* prototype is in "system/time.h" */ +#endif + +#ifndef HAVE_UTIMES +#define utimes rep_utimes +/* 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 +/* prototype is in system/network.h */ +#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 +#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 + +#if !defined(HAVE_INET_NTOA) || defined(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_INET_ATON +#define inet_aton rep_inet_aton +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_CONNECT +#define connect rep_connect +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_GETHOSTBYNAME +#define gethostbyname rep_gethostbyname +/* 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 +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#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 +#endif + +#if !defined(HAVE_BOOL) +#ifdef HAVE__Bool +#define bool _Bool +#else +typedef int bool; +#endif +#endif + +/* + * to prevent 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 *)((uintptr_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 + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#ifndef MAX_DNS_NAME_LENGTH +#define MAX_DNS_NAME_LENGTH 256 /* Actually 255 but +1 for terminating null. */ +#endif + +#endif /* _LIBREPLACE_REPLACE_H */ diff --git a/replace/replace.ho b/replace/replace.ho new file mode 100644 index 000000000..78700b550 Binary files /dev/null and b/replace/replace.ho differ diff --git a/replace/samba.m4 b/replace/samba.m4 new file mode 100644 index 000000000..07c4d3888 --- /dev/null +++ b/replace/samba.m4 @@ -0,0 +1,35 @@ +AC_LIBREPLACE_BROKEN_CHECKS +AC_LIBREPLACE_NETWORK_CHECKS + +SMB_EXT_LIB(LIBREPLACE_EXT, [${LIBDL}]) +SMB_ENABLE(LIBREPLACE_EXT) + +SMB_EXT_LIB(LIBREPLACE_NETWORK, [${LIBREPLACE_NETWORK_LIBS}]) +SMB_ENABLE(LIBREPLACE_NETWORK) + +# 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 LIBREPLACE_NETWORK], + [-Ilib/replace]) + +LIBREPLACE_HOSTCC_OBJS=`echo ${LIBREPLACE_OBJS} |sed -e 's/\.o/\.ho/g'` + +SMB_SUBSYSTEM(LIBREPLACE_HOSTCC, + [${LIBREPLACE_HOSTCC_OBJS}], + [], + [-Ilib/replace]) diff --git a/replace/snprintf.c b/replace/snprintf.c new file mode 100644 index 000000000..a174dcffe --- /dev/null +++ b/replace/snprintf.c @@ -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@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 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 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 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins 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@samba.org) Oct 1998 + * fixed handling of %.0f + * added test for HAVE_LONG_DOUBLE + * + * tridge@samba.org, idra@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 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@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@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@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@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 +#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 + /* 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 = ""; + } + + 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 */ diff --git a/replace/snprintf.ho b/replace/snprintf.ho new file mode 100644 index 000000000..0119c63bb Binary files /dev/null and b/replace/snprintf.ho differ diff --git a/replace/socket.c b/replace/socket.c new file mode 100644 index 000000000..35e975fce --- /dev/null +++ b/replace/socket.c @@ -0,0 +1,35 @@ +/* + * Unix SMB/CIFS implementation. + * + * Dummy replacements for socket functions. + * + * Copyright (C) Michael Adam 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 . + */ + +#include "replace.h" +#include "system/network.h" + +int rep_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) +{ + errno = ENOSYS; + return -1; +} + +struct hostent *rep_gethostbyname(const char *name) +{ + errno = ENOSYS; + return NULL; +} diff --git a/replace/socketpair.c b/replace/socketpair.c new file mode 100644 index 000000000..c77573095 --- /dev/null +++ b/replace/socketpair.c @@ -0,0 +1,46 @@ +/* + * Unix SMB/CIFS implementation. + * replacement routines for broken systems + * Copyright (C) Jelmer Vernooij 2006 + * Copyright (C) Michael Adam 2008 + * + * ** 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 . + */ + +#include "replace.h" +#include "system/network.h" + +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); +} diff --git a/replace/strptime.c b/replace/strptime.c new file mode 100644 index 000000000..0e40f7561 --- /dev/null +++ b/replace/strptime.c @@ -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 , 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 . */ + +/* 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); +} diff --git a/replace/strptime.m4 b/replace/strptime.m4 new file mode 100644 index 000000000..da22fc5a9 --- /dev/null +++ b/replace/strptime.m4 @@ -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 diff --git a/replace/system/README b/replace/system/README new file mode 100644 index 000000000..69a2b80b5 --- /dev/null +++ b/replace/system/README @@ -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. diff --git a/replace/system/aio.h b/replace/system/aio.h new file mode 100644 index 000000000..784d77fa2 --- /dev/null +++ b/replace/system/aio.h @@ -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 . +*/ + +#ifdef HAVE_LIBAIO_H +#include +#endif + +#endif diff --git a/replace/system/capability.h b/replace/system/capability.h new file mode 100644 index 000000000..a7b78f027 --- /dev/null +++ b/replace/system/capability.h @@ -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 . +*/ + +#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 + +#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 diff --git a/replace/system/config.m4 b/replace/system/config.m4 new file mode 100644 index 000000000..5c9b53d5c --- /dev/null +++ b/replace/system/config.m4 @@ -0,0 +1,130 @@ +# 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 +AC_CHECK_FUNCS(utime utimes) + +# 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],libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS,[ +AC_TRY_COMPILE([ + #ifdef HAVE_SYS_VFS_H + #include + #endif + #ifdef HAVE_SYS_CAPABILITY_H + #include + #endif + ],[ + int i; + ], + libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=no, + libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=yes +)]) +if test x"$libreplace_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],libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER,[ +AC_TRY_COMPILE([ + #ifdef HAVE_SYS_CAPABILITY_H + #include + #endif + #include + ],[ + __s8 i; + ], + libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER=no, + libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER=yes +)]) +if test x"$libreplace_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 + #include + ]) +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 + #include + ]) +AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf, size_t buflen)], + [ + #ifndef HAVE_GETPWENT_R_DECL + #error missing getpwent_r prototype + #endif + return NULL; + ],[ + AC_DEFINE(SOLARIS_GETPWENT_R, 1, [getpwent_r irix (similar to solaris) function prototype]) + ],[],[ + #include + #include + ]) +AC_CHECK_FUNCS(getgrnam_r getgrgid_r getgrent_r) +AC_HAVE_DECL(getgrent_r, [ + #include + #include + ]) +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 + #include + ]) + +AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, size_t buflen)], + [ + #ifndef HAVE_GETGRENT_R_DECL + #error missing getgrent_r prototype + #endif + return NULL; + ],[ + AC_DEFINE(SOLARIS_GETGRENT_R, 1, [getgrent_r irix (similar to solaris) function prototype]) + ],[],[ + #include + #include + ]) + +# 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 ) diff --git a/replace/system/dir.h b/replace/system/dir.h new file mode 100644 index 000000000..dec2d5464 --- /dev/null +++ b/replace/system/dir.h @@ -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 . +*/ + +#if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# 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 diff --git a/replace/system/filesys.h b/replace/system/filesys.h new file mode 100644 index 000000000..4bf1f6486 --- /dev/null +++ b/replace/system/filesys.h @@ -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 . + +*/ + +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_MOUNT_H +#include +#endif + +#ifdef HAVE_MNTENT_H +#include +#endif + +#ifdef HAVE_SYS_VFS_H +#include +#endif + +#ifdef HAVE_SYS_ACL_H +#include +#endif + +#ifdef HAVE_ACL_LIBACL_H +#include +#endif + +#ifdef HAVE_SYS_FS_S5PARAM_H +#include +#endif + +#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY) +#include +#endif + +#ifdef HAVE_SYS_STATFS_H +# include +#endif + +#ifdef HAVE_DUSTAT_H +#include +#endif + +#ifdef HAVE_SYS_STATVFS_H +#include +#endif + +#ifdef HAVE_SYS_FILIO_H +#include +#endif + +#include + +#ifdef HAVE_FCNTL_H +#include +#else +#ifdef HAVE_SYS_FCNTL_H +#include +#endif +#endif + +#ifdef HAVE_SYS_MODE_H +/* apparently AIX needs this for S_ISLNK */ +#ifndef S_ISLNK +#include +#endif +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include +#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 +#endif + +/* mutually exclusive (SuSE 8.2) */ +#if HAVE_ATTR_XATTR_H +#include +#elif HAVE_SYS_XATTR_H +#include +#endif + + +#ifdef HAVE_SYS_RESOURCE_H +#include +#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 diff --git a/replace/system/glob.h b/replace/system/glob.h new file mode 100644 index 000000000..3e23db682 --- /dev/null +++ b/replace/system/glob.h @@ -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 . + +*/ + +#ifdef HAVE_GLOB_H +#include +#endif + +#ifdef HAVE_FNMATCH_H +#include +#endif + +#endif diff --git a/replace/system/iconv.h b/replace/system/iconv.h new file mode 100644 index 000000000..3c8a71f2f --- /dev/null +++ b/replace/system/iconv.h @@ -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 . + +*/ + +#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 +#elif defined(HAVE_GICONV) +#include +#elif defined(HAVE_BICONV) +#include +#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 diff --git a/replace/system/kerberos.h b/replace/system/kerberos.h new file mode 100644 index 000000000..2981024be --- /dev/null +++ b/replace/system/kerberos.h @@ -0,0 +1,137 @@ +#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 . + +*/ + +#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 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 +#include + +#endif + +#endif diff --git a/replace/system/locale.h b/replace/system/locale.h new file mode 100644 index 000000000..e73a9bb27 --- /dev/null +++ b/replace/system/locale.h @@ -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 . + +*/ + +#ifdef HAVE_CTYPE_H +#include +#endif + +#ifdef HAVE_LOCALE_H +#include +#endif + +#endif diff --git a/replace/system/network.h b/replace/system/network.h new file mode 100644 index 000000000..077892a54 --- /dev/null +++ b/replace/system/network.h @@ -0,0 +1,332 @@ +#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 . + +*/ + +#ifndef LIBREPLACE_NETWORK_CHECKS +#error "AC_LIBREPLACE_NETWORK_CHECKS missing in configure" +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_UNIXSOCKET +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_NETINET_TCP_H +#include +#endif + +/* + * The next three defines are needed to access the IPTOS_* options + * on some systems. + */ + +#ifdef HAVE_NETINET_IN_SYSTM_H +#include +#endif + +#ifdef HAVE_NETINET_IN_IP_H +#include +#endif + +#ifdef HAVE_NETINET_IP_H +#include +#endif + +#ifdef HAVE_NET_IF_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_STROPTS_H +#include +#endif + +#ifndef HAVE_SOCKLEN_T +#define HAVE_SOCKLEN_T +typedef int socklen_t; +#endif + +#if !defined (HAVE_INET_NTOA) || defined(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 + +#ifndef HAVE_INET_ATON +/* define is in "replace.h" */ +int rep_inet_aton(const char *src, struct in_addr *dst); +#endif + +#ifndef HAVE_CONNECT +/* define is in "replace.h" */ +int rep_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +#endif + +#ifndef HAVE_GETHOSTBYNAME +/* define is in "replace.h" */ +struct hostent *rep_gethostbyname(const char *name); +#endif + +#ifdef HAVE_IFADDRS_H +#include +#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 + +#ifndef HAVE_SOCKETPAIR +/* define is in "replace.h" */ +int rep_socketpair(int d, int type, int protocol, int sv[2]); +#endif + +/* + * Some systems have getaddrinfo but not the + * defines needed to use it. + */ + +/* Various macros that ought to be in , 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 +/* + * logic copied from AI_NUMERICHOST + */ +#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) +#define AI_ADDRCONFIG 0 +#else +#define AI_ADDRCONFIG 0x0020 +#endif +#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_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_addr +#endif + +#ifdef SOCKET_WRAPPER +#ifndef SOCKET_WRAPPER_NOT_REPLACE +#define SOCKET_WRAPPER_REPLACE +#endif +#include "lib/socket_wrapper/socket_wrapper.h" +#endif + +#endif diff --git a/replace/system/passwd.h b/replace/system/passwd.h new file mode 100644 index 000000000..cad3197cc --- /dev/null +++ b/replace/system/passwd.h @@ -0,0 +1,110 @@ +#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 . + +*/ + +/* this needs to be included before nss_wrapper.h on some systems */ +#include + +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif +#ifdef HAVE_SYS_PRIV_H +#include +#endif +#ifdef HAVE_SYS_ID_H +#include +#endif + +#ifdef HAVE_CRYPT_H +#include +#endif + +#ifdef HAVE_SHADOW_H +#include +#endif + +#ifdef HAVE_SYS_SECURITY_H +#include +#include +#define PASSWORD_LENGTH 16 +#endif /* HAVE_SYS_SECURITY_H */ + +#ifdef HAVE_GETPWANAM +#include +#include +#include +#endif + +#ifdef HAVE_COMPAT_H +#include +#endif + +#ifdef REPLACE_GETPASS +#if defined(REPLACE_GETPASS_BY_GETPASSPHRASE) +#define getpass(prompt) getpassphrase(prompt) +#else +#define getpass(prompt) rep_getpass(prompt) +char *rep_getpass(const char *prompt); +#endif +#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 diff --git a/replace/system/readline.h b/replace/system/readline.h new file mode 100644 index 000000000..ba34dc6a6 --- /dev/null +++ b/replace/system/readline.h @@ -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 . + +*/ + +#ifdef HAVE_LIBREADLINE +# ifdef HAVE_READLINE_READLINE_H +# include +# ifdef HAVE_READLINE_HISTORY_H +# include +# endif +# else +# ifdef HAVE_READLINE_H +# include +# ifdef HAVE_HISTORY_H +# include +# 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 diff --git a/replace/system/select.h b/replace/system/select.h new file mode 100644 index 000000000..da18de0cf --- /dev/null +++ b/replace/system/select.h @@ -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 . + +*/ + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#ifdef HAVE_SYS_EPOLL_H +#include +#endif + +#ifndef SELECT_CAST +#define SELECT_CAST +#endif + +#endif diff --git a/replace/system/shmem.h b/replace/system/shmem.h new file mode 100644 index 000000000..64fe39b6c --- /dev/null +++ b/replace/system/shmem.h @@ -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 . + +*/ + +#if defined(HAVE_SYS_IPC_H) +#include +#endif /* HAVE_SYS_IPC_H */ + +#if defined(HAVE_SYS_SHM_H) +#include +#endif /* HAVE_SYS_SHM_H */ + +#ifdef HAVE_SYS_MMAN_H +#include +#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 diff --git a/replace/system/syslog.h b/replace/system/syslog.h new file mode 100644 index 000000000..104be1df8 --- /dev/null +++ b/replace/system/syslog.h @@ -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 . + +*/ + +#ifdef HAVE_SYSLOG_H +#include +#else +#ifdef HAVE_SYS_SYSLOG_H +#include +#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 diff --git a/replace/system/terminal.h b/replace/system/terminal.h new file mode 100644 index 000000000..9ad601ace --- /dev/null +++ b/replace/system/terminal.h @@ -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 . + +*/ + +#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 +#elif defined(HAVE_TERMIO_H) +/* Older SYSV terminal handling - don't use if we can avoid it. */ +#include +#elif defined(HAVE_SYS_TERMIO_H) +/* Older SYSV terminal handling - don't use if we can avoid it. */ +#include +#endif + +#endif diff --git a/replace/system/time.h b/replace/system/time.h new file mode 100644 index 000000000..4abf295d1 --- /dev/null +++ b/replace/system/time.h @@ -0,0 +1,69 @@ +#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 . + +*/ + +#ifdef TIME_WITH_SYS_TIME +#include +#include +#else +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#ifdef HAVE_UTIME_H +#include +#else +struct utimbuf { + time_t actime; /* access time */ + time_t modtime; /* modification time */ +}; +#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 + +#ifndef HAVE_UTIME +/* define is in "replace.h" */ +int rep_utime(const char *filename, const struct utimbuf *buf); +#endif + +#ifndef HAVE_UTIMES +/* define is in "replace.h" */ +int rep_utimes(const char *filename, const struct timeval tv[2]); +#endif + +#endif diff --git a/replace/system/wait.h b/replace/system/wait.h new file mode 100644 index 000000000..5784b1ae9 --- /dev/null +++ b/replace/system/wait.h @@ -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 . + +*/ + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#include + +#ifndef SIGCLD +#define SIGCLD SIGCHLD +#endif + +#ifndef SIGNAL_CAST +#define SIGNAL_CAST (RETSIGTYPE (*)(int)) +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifndef SA_RESETHAND +#define SA_RESETHAND SA_ONESHOT +#endif + +#if !defined(HAVE_SIG_ATOMIC_T_TYPE) +typedef int sig_atomic_t; +#endif + +#endif diff --git a/replace/test/getifaddrs.c b/replace/test/getifaddrs.c new file mode 100644 index 000000000..8b00ac2f4 --- /dev/null +++ b/replace/test/getifaddrs.c @@ -0,0 +1,100 @@ +/* + * Unix SMB/CIFS implementation. + * + * libreplace getifaddrs test + * + * Copyright (C) Michael Adam 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 . + */ + +#ifndef AUTOCONF_TEST +#include "replace.h" +#include "system/network.h" +#endif + +#ifdef HAVE_INET_NTOP +#define rep_inet_ntop inet_ntop +#endif + +static const char *format_sockaddr(struct sockaddr *addr, + char *addrstring, + socklen_t addrlen) +{ + const char *result = NULL; + + if (addr->sa_family == AF_INET) { + result = rep_inet_ntop(AF_INET, + &((struct sockaddr_in *)addr)->sin_addr, + addrstring, + addrlen); +#ifdef HAVE_STRUCT_SOCKADDR_IN6 + } else if (addr->sa_family == AF_INET6) { + result = rep_inet_ntop(AF_INET6, + &((struct sockaddr_in6 *)addr)->sin6_addr, + addrstring, + addrlen); +#endif + } + return result; +} + +int getifaddrs_test(void) +{ + struct ifaddrs *ifs = NULL; + struct ifaddrs *ifs_head = NULL; + int ret; + + ret = getifaddrs(&ifs); + ifs_head = ifs; + if (ret != 0) { + fprintf(stderr, "getifaddrs() failed: %s\n", strerror(errno)); + return 1; + } + + while (ifs) { + printf("%-10s ", ifs->ifa_name); + if (ifs->ifa_addr != NULL) { + char addrstring[INET6_ADDRSTRLEN]; + const char *result; + + result = format_sockaddr(ifs->ifa_addr, + addrstring, + sizeof(addrstring)); + if (result != NULL) { + printf("IP=%s ", addrstring); + } + + if (ifs->ifa_netmask != NULL) { + result = format_sockaddr(ifs->ifa_netmask, + addrstring, + sizeof(addrstring)); + if (result != NULL) { + printf("NETMASK=%s", addrstring); + } + } else { + printf("AF=%d ", ifs->ifa_addr->sa_family); + } + } else { + printf(""); + } + + printf("\n"); + ifs = ifs->ifa_next; + } + + freeifaddrs(ifs_head); + + return 0; +} diff --git a/replace/test/os2_delete.c b/replace/test/os2_delete.c new file mode 100644 index 000000000..b45c13535 --- /dev/null +++ b/replace/test/os2_delete.c @@ -0,0 +1,124 @@ +/* + test readdir/unlink pattern that OS/2 uses + tridge@samba.org July 2005 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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;id_name); + } + + if (i == 0) { + return 0; + } + + /* delete the first few */ + for (j=0; jd_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"); + + system("rm -rf " TESTDIR); + + return test_readdir_os2_delete_ret; +} diff --git a/replace/test/shared_mmap.c b/replace/test/shared_mmap.c new file mode 100644 index 000000000..50dad8d69 --- /dev/null +++ b/replace/test/shared_mmap.c @@ -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 +#endif +#include +#include +#include +#include + +#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); +} diff --git a/replace/test/strptime.c b/replace/test/strptime.c new file mode 100644 index 000000000..fade3ecc5 --- /dev/null +++ b/replace/test/strptime.c @@ -0,0 +1,172 @@ + +#ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME + +#include +#include +#include + +#define true 1 +#define false 0 + +#ifndef __STRING +#define __STRING(x) #x +#endif + +/* make printf a no-op */ +#define printf if(0) printf + +#else /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */ + +#include "replace.h" +#include "system/time.h" + +#endif /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */ + +int libreplace_test_strptime(void) +{ + const char *s = "20070414101546Z"; + char *ret; + struct tm t, t2; + + memset(&t, 0, sizeof(t)); + memset(&t2, 0, sizeof(t2)); + + printf("test: strptime\n"); + + ret = strptime(s, "%Y%m%d%H%M%S", &t); + if ( ret == NULL ) { + printf("failure: strptime [\n" + "returned NULL\n" + "]\n"); + return false; + } + + if ( *ret != 'Z' ) { + printf("failure: strptime [\n" + "ret doesn't point to 'Z'\n" + "]\n"); + return false; + } + + ret = strptime(s, "%Y%m%d%H%M%SZ", &t2); + if ( ret == NULL ) { + printf("failure: strptime [\n" + "returned NULL with Z\n" + "]\n"); + return false; + } + + if ( *ret != '\0' ) { + printf("failure: strptime [\n" + "ret doesn't point to '\\0'\n" + "]\n"); + return false; + } + +#define CMP_TM_ELEMENT(t1,t2,elem) \ + if (t1.elem != t2.elem) { \ + printf("failure: strptime [\n" \ + "result differs if the format string has a 'Z' at the end\n" \ + "element: %s %d != %d\n" \ + "]\n", \ + __STRING(elen), t1.elem, t2.elem); \ + return false; \ + } + + CMP_TM_ELEMENT(t,t2,tm_sec); + CMP_TM_ELEMENT(t,t2,tm_min); + CMP_TM_ELEMENT(t,t2,tm_hour); + CMP_TM_ELEMENT(t,t2,tm_mday); + CMP_TM_ELEMENT(t,t2,tm_mon); + CMP_TM_ELEMENT(t,t2,tm_year); + CMP_TM_ELEMENT(t,t2,tm_wday); + CMP_TM_ELEMENT(t,t2,tm_yday); + CMP_TM_ELEMENT(t,t2,tm_isdst); + + if (t.tm_sec != 46) { + printf("failure: strptime [\n" + "tm_sec: expected: 46, got: %d\n" + "]\n", + t.tm_sec); + return false; + } + + if (t.tm_min != 15) { + printf("failure: strptime [\n" + "tm_min: expected: 15, got: %d\n" + "]\n", + t.tm_min); + return false; + } + + if (t.tm_hour != 10) { + printf("failure: strptime [\n" + "tm_hour: expected: 10, got: %d\n" + "]\n", + t.tm_hour); + return false; + } + + if (t.tm_mday != 14) { + printf("failure: strptime [\n" + "tm_mday: expected: 14, got: %d\n" + "]\n", + t.tm_mday); + return false; + } + + if (t.tm_mon != 3) { + printf("failure: strptime [\n" + "tm_mon: expected: 3, got: %d\n" + "]\n", + t.tm_mon); + return false; + } + + if (t.tm_year != 107) { + printf("failure: strptime [\n" + "tm_year: expected: 107, got: %d\n" + "]\n", + t.tm_year); + return false; + } + + if (t.tm_wday != 6) { /* saturday */ + printf("failure: strptime [\n" + "tm_wday: expected: 6, got: %d\n" + "]\n", + t.tm_wday); + return false; + } + + if (t.tm_yday != 103) { + printf("failure: strptime [\n" + "tm_yday: expected: 103, got: %d\n" + "]\n", + t.tm_yday); + return false; + } + + /* we don't test this as it depends on the host configuration + if (t.tm_isdst != 0) { + printf("failure: strptime [\n" + "tm_isdst: expected: 0, got: %d\n" + "]\n", + t.tm_isdst); + return false; + }*/ + + printf("success: strptime\n"); + + return true; +} + +#ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME +int main (void) +{ + int ret; + ret = libreplace_test_strptime(); + if (ret == false) return 1; + return 0; +} +#endif diff --git a/replace/test/testsuite.c b/replace/test/testsuite.c new file mode 100644 index 000000000..dcb05fbbf --- /dev/null +++ b/replace/test/testsuite.c @@ -0,0 +1,1081 @@ +/* + 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 . +*/ + +#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/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) +{ + char tmp[10]; + printf("test: strlcat\n"); + strlcpy(tmp, "", sizeof(tmp)); + if (strlcat(tmp, "bla", 3) != 3) { + printf("failure: strlcat [\ninvalid return code\n]\n"); + return false; + } + if (strcmp(tmp, "bl") != 0) { + printf("failure: strlcat [\nexpected \"bl\", got \"%s\"\n]\n", + tmp); + return false; + } + + strlcpy(tmp, "da", sizeof(tmp)); + if (strlcat(tmp, "me", 4) != 4) { + printf("failure: strlcat [\nexpected \"dam\", got \"%s\"\n]\n", + tmp); + return false; + } + + printf("success: strlcat\n"); + return true; +} + +static int test_mktime(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) +{ + char *x; + printf("test: strdup\n"); + x = strdup("bla"); + if (strcmp("bla", x) != 0) { + printf("failure: strdup [\nfailed: expected \"bla\", got \"%s\"\n]\n", + x); + return false; + } + free(x); + printf("success: strdup\n"); + 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) +{ +#define TEST_SETENV(key, value, overwrite, result) do { \ + int _ret; \ + char *_v; \ + _ret = setenv(key, value, overwrite); \ + if (_ret != 0) { \ + printf("failure: setenv [\n" \ + "setenv(%s, %s, %d) failed\n" \ + "]\n", \ + key, value, overwrite); \ + return false; \ + } \ + _v=getenv(key); \ + if (!_v) { \ + printf("failure: setenv [\n" \ + "getenv(%s) returned NULL\n" \ + "]\n", \ + key); \ + return false; \ + } \ + if (strcmp(result, _v) != 0) { \ + printf("failure: setenv [\n" \ + "getenv(%s): '%s' != '%s'\n" \ + "]\n", \ + key, result, _v); \ + return false; \ + } \ +} while(0) + +#define TEST_UNSETENV(key) do { \ + char *_v; \ + unsetenv(key); \ + _v=getenv(key); \ + if (_v) { \ + printf("failure: setenv [\n" \ + "getenv(%s): NULL != '%s'\n" \ + "]\n", \ + SETENVTEST_KEY, _v); \ + return false; \ + } \ +} while (0) + +#define SETENVTEST_KEY "SETENVTESTKEY" +#define SETENVTEST_VAL "SETENVTESTVAL" + + printf("test: setenv\n"); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"1", 0, SETENVTEST_VAL"1"); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"2", 0, SETENVTEST_VAL"1"); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"3", 1, SETENVTEST_VAL"3"); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"4", 1, SETENVTEST_VAL"4"); + TEST_UNSETENV(SETENVTEST_KEY); + TEST_UNSETENV(SETENVTEST_KEY); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"5", 0, SETENVTEST_VAL"5"); + TEST_UNSETENV(SETENVTEST_KEY); + TEST_UNSETENV(SETENVTEST_KEY); + printf("success: setenv\n"); + return true; +} + +static int test_strndup(void) +{ + char *x; + printf("test: strndup\n"); + x = strndup("bla", 0); + if (strcmp(x, "") != 0) { + printf("failure: strndup [\ninvalid\n]\n"); + return false; + } + free(x); + x = strndup("bla", 2); + if (strcmp(x, "bl") != 0) { + printf("failure: strndup [\ninvalid\n]\n"); + return false; + } + free(x); + x = strndup("bla", 10); + if (strcmp(x, "bla") != 0) { + printf("failure: strndup [\ninvalid\n]\n"); + return false; + } + free(x); + printf("success: strndup\n"); + return true; +} + +static int test_strnlen(void) +{ + printf("test: strnlen\n"); + if (strnlen("bla", 2) != 2) { + printf("failure: strnlen [\nunexpected length\n]\n"); + return false; + } + + if (strnlen("some text\n", 0) != 0) { + printf("failure: strnlen [\nunexpected length\n]\n"); + return false; + } + + if (strnlen("some text", 20) != 9) { + printf("failure: strnlen [\nunexpected length\n]\n"); + return false; + } + + printf("success: strnlen\n"); + 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) +{ + char *x; + printf("test: asprintf\n"); + if (asprintf(&x, "%d", 9) != 1) { + printf("failure: asprintf [\ngenerate asprintf\n]\n"); + return false; + } + if (strcmp(x, "9") != 0) { + printf("failure: asprintf [\ngenerate asprintf\n]\n"); + return false; + } + if (asprintf(&x, "dat%s", "a") != 4) { + printf("failure: asprintf [\ngenerate asprintf\n]\n"); + return false; + } + if (strcmp(x, "data") != 0) { + printf("failure: asprintf [\ngenerate asprintf\n]\n"); + return false; + } + printf("success: asprintf\n"); + return true; +} + +static int test_snprintf(void) +{ + char tmp[10]; + printf("test: snprintf\n"); + if (snprintf(tmp, 3, "foo%d", 9) != 4) { + printf("failure: snprintf [\nsnprintf return code failed\n]\n"); + return false; + } + + if (strcmp(tmp, "fo") != 0) { + printf("failure: snprintf [\nsnprintf failed\n]\n"); + return false; + } + + printf("success: snprintf\n"); + 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) +{ + printf("test: errno\n"); + errno = 3; + if (errno != 3) { + printf("failure: errno [\nerrno failed\n]\n"); + return false; + } + + printf("success: errno\n"); + 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; +} + +#define TEST_STRTO_X(type,fmt,func,str,base,res,diff,rrnoo) do {\ + type _v; \ + char _s[64]; \ + char *_p = NULL;\ + char *_ep = NULL; \ + strlcpy(_s, str, sizeof(_s));\ + if (diff >= 0) { \ + _ep = &_s[diff]; \ + } \ + errno = 0; \ + _v = func(_s, &_p, base); \ + if (errno != rrnoo) { \ + printf("failure: %s [\n" \ + "\t%s\n" \ + "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \ + "\terrno: %d != %d\n" \ + "]\n", \ + __STRING(func), __location__, __STRING(func), \ + str, diff, base, res, _v, rrnoo, errno); \ + return false; \ + } else if (_v != res) { \ + printf("failure: %s [\n" \ + "\t%s\n" \ + "\t%s(\"%s\",%d,%d): " fmt " != " fmt "\n" \ + "]\n", \ + __STRING(func), __location__, __STRING(func), \ + str, diff, base, res, _v); \ + return false; \ + } else if (_p != _ep) { \ + printf("failure: %s [\n" \ + "\t%s\n" \ + "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \ + "\tptr: %p - %p = %d != %d\n" \ + "]\n", \ + __STRING(func), __location__, __STRING(func), \ + str, diff, base, res, _v, _ep, _p, (int)(diff - (_ep - _p)), diff); \ + return false; \ + } \ +} while (0) + +static int test_strtoll(void) +{ + printf("test: strtoll\n"); + +#define TEST_STRTOLL(str,base,res,diff,errnoo) TEST_STRTO_X(long long int, "%lld", strtoll,str,base,res,diff,errnoo) + + TEST_STRTOLL("15", 10, 15LL, 2, 0); + TEST_STRTOLL(" 15", 10, 15LL, 4, 0); + TEST_STRTOLL("15", 0, 15LL, 2, 0); + TEST_STRTOLL(" 15 ", 0, 15LL, 3, 0); + TEST_STRTOLL("+15", 10, 15LL, 3, 0); + TEST_STRTOLL(" +15", 10, 15LL, 5, 0); + TEST_STRTOLL("+15", 0, 15LL, 3, 0); + TEST_STRTOLL(" +15 ", 0, 15LL, 4, 0); + TEST_STRTOLL("-15", 10, -15LL, 3, 0); + TEST_STRTOLL(" -15", 10, -15LL, 5, 0); + TEST_STRTOLL("-15", 0, -15LL, 3, 0); + TEST_STRTOLL(" -15 ", 0, -15LL, 4, 0); + TEST_STRTOLL("015", 10, 15LL, 3, 0); + TEST_STRTOLL(" 015", 10, 15LL, 5, 0); + TEST_STRTOLL("015", 0, 13LL, 3, 0); + TEST_STRTOLL(" 015", 0, 13LL, 5, 0); + TEST_STRTOLL("0x15", 10, 0LL, 1, 0); + TEST_STRTOLL(" 0x15", 10, 0LL, 3, 0); + TEST_STRTOLL("0x15", 0, 21LL, 4, 0); + TEST_STRTOLL(" 0x15", 0, 21LL, 6, 0); + + TEST_STRTOLL("10", 16, 16LL, 2, 0); + TEST_STRTOLL(" 10 ", 16, 16LL, 4, 0); + TEST_STRTOLL("0x10", 16, 16LL, 4, 0); + TEST_STRTOLL("0x10", 0, 16LL, 4, 0); + TEST_STRTOLL(" 0x10 ", 0, 16LL, 5, 0); + TEST_STRTOLL("+10", 16, 16LL, 3, 0); + TEST_STRTOLL(" +10 ", 16, 16LL, 5, 0); + TEST_STRTOLL("+0x10", 16, 16LL, 5, 0); + TEST_STRTOLL("+0x10", 0, 16LL, 5, 0); + TEST_STRTOLL(" +0x10 ", 0, 16LL, 6, 0); + TEST_STRTOLL("-10", 16, -16LL, 3, 0); + TEST_STRTOLL(" -10 ", 16, -16LL, 5, 0); + TEST_STRTOLL("-0x10", 16, -16LL, 5, 0); + TEST_STRTOLL("-0x10", 0, -16LL, 5, 0); + TEST_STRTOLL(" -0x10 ", 0, -16LL, 6, 0); + TEST_STRTOLL("010", 16, 16LL, 3, 0); + TEST_STRTOLL(" 010 ", 16, 16LL, 5, 0); + TEST_STRTOLL("-010", 16, -16LL, 4, 0); + + TEST_STRTOLL("11", 8, 9LL, 2, 0); + TEST_STRTOLL("011", 8, 9LL, 3, 0); + TEST_STRTOLL("011", 0, 9LL, 3, 0); + TEST_STRTOLL("-11", 8, -9LL, 3, 0); + TEST_STRTOLL("-011", 8, -9LL, 4, 0); + TEST_STRTOLL("-011", 0, -9LL, 4, 0); + + TEST_STRTOLL("011", 8, 9LL, 3, 0); + TEST_STRTOLL("011", 0, 9LL, 3, 0); + TEST_STRTOLL("-11", 8, -9LL, 3, 0); + TEST_STRTOLL("-011", 8, -9LL, 4, 0); + TEST_STRTOLL("-011", 0, -9LL, 4, 0); + + TEST_STRTOLL("Text", 0, 0LL, 0, 0); + + TEST_STRTOLL("9223372036854775807", 10, 9223372036854775807LL, 19, 0); + TEST_STRTOLL("9223372036854775807", 0, 9223372036854775807LL, 19, 0); + TEST_STRTOLL("9223372036854775808", 0, 9223372036854775807LL, 19, ERANGE); + TEST_STRTOLL("9223372036854775808", 10, 9223372036854775807LL, 19, ERANGE); + TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LL, 18, 0); + TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 18, 0); + TEST_STRTOLL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 16, 0); + TEST_STRTOLL("0x8000000000000000", 0, 9223372036854775807LL, 18, ERANGE); + TEST_STRTOLL("0x8000000000000000", 16, 9223372036854775807LL, 18, ERANGE); + TEST_STRTOLL("80000000000000000", 16, 9223372036854775807LL, 17, ERANGE); + TEST_STRTOLL("0777777777777777777777", 0, 9223372036854775807LL, 22, 0); + TEST_STRTOLL("0777777777777777777777", 8, 9223372036854775807LL, 22, 0); + TEST_STRTOLL("777777777777777777777", 8, 9223372036854775807LL, 21, 0); + TEST_STRTOLL("01000000000000000000000", 0, 9223372036854775807LL, 23, ERANGE); + TEST_STRTOLL("01000000000000000000000", 8, 9223372036854775807LL, 23, ERANGE); + TEST_STRTOLL("1000000000000000000000", 8, 9223372036854775807LL, 22, ERANGE); + + TEST_STRTOLL("-9223372036854775808", 10, -9223372036854775807LL -1, 20, 0); + TEST_STRTOLL("-9223372036854775808", 0, -9223372036854775807LL -1, 20, 0); + TEST_STRTOLL("-9223372036854775809", 0, -9223372036854775807LL -1, 20, ERANGE); + TEST_STRTOLL("-9223372036854775809", 10, -9223372036854775807LL -1, 20, ERANGE); + TEST_STRTOLL("-0x8000000000000000", 0, -9223372036854775807LL -1, 19, 0); + TEST_STRTOLL("-0x8000000000000000", 16, -9223372036854775807LL -1, 19, 0); + TEST_STRTOLL("-8000000000000000", 16, -9223372036854775807LL -1, 17, 0); + TEST_STRTOLL("-0x8000000000000001", 0, -9223372036854775807LL -1, 19, ERANGE); + TEST_STRTOLL("-0x8000000000000001", 16, -9223372036854775807LL -1, 19, ERANGE); + TEST_STRTOLL("-80000000000000001", 16, -9223372036854775807LL -1, 18, ERANGE); + TEST_STRTOLL("-01000000000000000000000",0, -9223372036854775807LL -1, 24, 0); + TEST_STRTOLL("-01000000000000000000000",8, -9223372036854775807LL -1, 24, 0); + TEST_STRTOLL("-1000000000000000000000", 8, -9223372036854775807LL -1, 23, 0); + TEST_STRTOLL("-01000000000000000000001",0, -9223372036854775807LL -1, 24, ERANGE); + TEST_STRTOLL("-01000000000000000000001",8, -9223372036854775807LL -1, 24, ERANGE); + TEST_STRTOLL("-1000000000000000000001", 8, -9223372036854775807LL -1, 23, ERANGE); + + printf("success: strtoll\n"); + return true; +} + +static int test_strtoull(void) +{ + printf("test: strtoull\n"); + +#define TEST_STRTOULL(str,base,res,diff,errnoo) TEST_STRTO_X(long long unsigned int,"%llu",strtoull,str,base,res,diff,errnoo) + + TEST_STRTOULL("15", 10, 15LLU, 2, 0); + TEST_STRTOULL(" 15", 10, 15LLU, 4, 0); + TEST_STRTOULL("15", 0, 15LLU, 2, 0); + TEST_STRTOULL(" 15 ", 0, 15LLU, 3, 0); + TEST_STRTOULL("+15", 10, 15LLU, 3, 0); + TEST_STRTOULL(" +15", 10, 15LLU, 5, 0); + TEST_STRTOULL("+15", 0, 15LLU, 3, 0); + TEST_STRTOULL(" +15 ", 0, 15LLU, 4, 0); + TEST_STRTOULL("-15", 10, 18446744073709551601LLU, 3, 0); + TEST_STRTOULL(" -15", 10, 18446744073709551601LLU, 5, 0); + TEST_STRTOULL("-15", 0, 18446744073709551601LLU, 3, 0); + TEST_STRTOULL(" -15 ", 0, 18446744073709551601LLU, 4, 0); + TEST_STRTOULL("015", 10, 15LLU, 3, 0); + TEST_STRTOULL(" 015", 10, 15LLU, 5, 0); + TEST_STRTOULL("015", 0, 13LLU, 3, 0); + TEST_STRTOULL(" 015", 0, 13LLU, 5, 0); + TEST_STRTOULL("0x15", 10, 0LLU, 1, 0); + TEST_STRTOULL(" 0x15", 10, 0LLU, 3, 0); + TEST_STRTOULL("0x15", 0, 21LLU, 4, 0); + TEST_STRTOULL(" 0x15", 0, 21LLU, 6, 0); + + TEST_STRTOULL("10", 16, 16LLU, 2, 0); + TEST_STRTOULL(" 10 ", 16, 16LLU, 4, 0); + TEST_STRTOULL("0x10", 16, 16LLU, 4, 0); + TEST_STRTOULL("0x10", 0, 16LLU, 4, 0); + TEST_STRTOULL(" 0x10 ", 0, 16LLU, 5, 0); + TEST_STRTOULL("+10", 16, 16LLU, 3, 0); + TEST_STRTOULL(" +10 ", 16, 16LLU, 5, 0); + TEST_STRTOULL("+0x10", 16, 16LLU, 5, 0); + TEST_STRTOULL("+0x10", 0, 16LLU, 5, 0); + TEST_STRTOULL(" +0x10 ", 0, 16LLU, 6, 0); + TEST_STRTOULL("-10", 16, -16LLU, 3, 0); + TEST_STRTOULL(" -10 ", 16, -16LLU, 5, 0); + TEST_STRTOULL("-0x10", 16, -16LLU, 5, 0); + TEST_STRTOULL("-0x10", 0, -16LLU, 5, 0); + TEST_STRTOULL(" -0x10 ", 0, -16LLU, 6, 0); + TEST_STRTOULL("010", 16, 16LLU, 3, 0); + TEST_STRTOULL(" 010 ", 16, 16LLU, 5, 0); + TEST_STRTOULL("-010", 16, -16LLU, 4, 0); + + TEST_STRTOULL("11", 8, 9LLU, 2, 0); + TEST_STRTOULL("011", 8, 9LLU, 3, 0); + TEST_STRTOULL("011", 0, 9LLU, 3, 0); + TEST_STRTOULL("-11", 8, -9LLU, 3, 0); + TEST_STRTOULL("-011", 8, -9LLU, 4, 0); + TEST_STRTOULL("-011", 0, -9LLU, 4, 0); + + TEST_STRTOULL("011", 8, 9LLU, 3, 0); + TEST_STRTOULL("011", 0, 9LLU, 3, 0); + TEST_STRTOULL("-11", 8, -9LLU, 3, 0); + TEST_STRTOULL("-011", 8, -9LLU, 4, 0); + TEST_STRTOULL("-011", 0, -9LLU, 4, 0); + + TEST_STRTOULL("Text", 0, 0LLU, 0, 0); + + TEST_STRTOULL("9223372036854775807", 10, 9223372036854775807LLU, 19, 0); + TEST_STRTOULL("9223372036854775807", 0, 9223372036854775807LLU, 19, 0); + TEST_STRTOULL("9223372036854775808", 0, 9223372036854775808LLU, 19, 0); + TEST_STRTOULL("9223372036854775808", 10, 9223372036854775808LLU, 19, 0); + TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LLU, 18, 0); + TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 18, 0); + TEST_STRTOULL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 16, 0); + TEST_STRTOULL("0x8000000000000000", 0, 9223372036854775808LLU, 18, 0); + TEST_STRTOULL("0x8000000000000000", 16, 9223372036854775808LLU, 18, 0); + TEST_STRTOULL("8000000000000000", 16, 9223372036854775808LLU, 16, 0); + TEST_STRTOULL("0777777777777777777777", 0, 9223372036854775807LLU, 22, 0); + TEST_STRTOULL("0777777777777777777777", 8, 9223372036854775807LLU, 22, 0); + TEST_STRTOULL("777777777777777777777", 8, 9223372036854775807LLU, 21, 0); + TEST_STRTOULL("01000000000000000000000",0, 9223372036854775808LLU, 23, 0); + TEST_STRTOULL("01000000000000000000000",8, 9223372036854775808LLU, 23, 0); + TEST_STRTOULL("1000000000000000000000", 8, 9223372036854775808LLU, 22, 0); + + TEST_STRTOULL("-9223372036854775808", 10, 9223372036854775808LLU, 20, 0); + TEST_STRTOULL("-9223372036854775808", 0, 9223372036854775808LLU, 20, 0); + TEST_STRTOULL("-9223372036854775809", 0, 9223372036854775807LLU, 20, 0); + TEST_STRTOULL("-9223372036854775809", 10, 9223372036854775807LLU, 20, 0); + TEST_STRTOULL("-0x8000000000000000", 0, 9223372036854775808LLU, 19, 0); + TEST_STRTOULL("-0x8000000000000000", 16, 9223372036854775808LLU, 19, 0); + TEST_STRTOULL("-8000000000000000", 16, 9223372036854775808LLU, 17, 0); + TEST_STRTOULL("-0x8000000000000001", 0, 9223372036854775807LLU, 19, 0); + TEST_STRTOULL("-0x8000000000000001", 16, 9223372036854775807LLU, 19, 0); + TEST_STRTOULL("-8000000000000001", 16, 9223372036854775807LLU, 17, 0); + TEST_STRTOULL("-01000000000000000000000",0, 9223372036854775808LLU, 24, 0); + TEST_STRTOULL("-01000000000000000000000",8, 9223372036854775808LLU, 24, 0); + TEST_STRTOULL("-1000000000000000000000",8, 9223372036854775808LLU, 23, 0); + TEST_STRTOULL("-01000000000000000000001",0, 9223372036854775807LLU, 24, 0); + TEST_STRTOULL("-01000000000000000000001",8, 9223372036854775807LLU, 24, 0); + TEST_STRTOULL("-1000000000000000000001",8, 9223372036854775807LLU, 23, 0); + + TEST_STRTOULL("18446744073709551615", 0, 18446744073709551615LLU, 20, 0); + TEST_STRTOULL("18446744073709551615", 10, 18446744073709551615LLU, 20, 0); + TEST_STRTOULL("18446744073709551616", 0, 18446744073709551615LLU, 20, ERANGE); + TEST_STRTOULL("18446744073709551616", 10, 18446744073709551615LLU, 20, ERANGE); + TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 0, 18446744073709551615LLU, 18, 0); + TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 18, 0); + TEST_STRTOULL("FFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 16, 0); + TEST_STRTOULL("0x10000000000000000", 0, 18446744073709551615LLU, 19, ERANGE); + TEST_STRTOULL("0x10000000000000000", 16, 18446744073709551615LLU, 19, ERANGE); + TEST_STRTOULL("10000000000000000", 16, 18446744073709551615LLU, 17, ERANGE); + TEST_STRTOULL("01777777777777777777777",0, 18446744073709551615LLU, 23, 0); + TEST_STRTOULL("01777777777777777777777",8, 18446744073709551615LLU, 23, 0); + TEST_STRTOULL("1777777777777777777777", 8, 18446744073709551615LLU, 22, 0); + TEST_STRTOULL("02000000000000000000000",0, 18446744073709551615LLU, 23, ERANGE); + TEST_STRTOULL("02000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE); + TEST_STRTOULL("2000000000000000000000", 8, 18446744073709551615LLU, 22, ERANGE); + + TEST_STRTOULL("-18446744073709551615", 0, 1LLU, 21, 0); + TEST_STRTOULL("-18446744073709551615", 10, 1LLU, 21, 0); + TEST_STRTOULL("-18446744073709551616", 0, 18446744073709551615LLU, 21, ERANGE); + TEST_STRTOULL("-18446744073709551616", 10, 18446744073709551615LLU, 21, ERANGE); + TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 0, 1LLU, 19, 0); + TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 16, 1LLU, 19, 0); + TEST_STRTOULL("-FFFFFFFFFFFFFFFF", 16, 1LLU, 17, 0); + TEST_STRTOULL("-0x10000000000000000", 0, 18446744073709551615LLU, 20, ERANGE); + TEST_STRTOULL("-0x10000000000000000", 16, 18446744073709551615LLU, 20, ERANGE); + TEST_STRTOULL("-10000000000000000", 16, 18446744073709551615LLU, 18, ERANGE); + TEST_STRTOULL("-01777777777777777777777",0, 1LLU, 24, 0); + TEST_STRTOULL("-01777777777777777777777",8, 1LLU, 24, 0); + TEST_STRTOULL("-1777777777777777777777",8, 1LLU, 23, 0); + TEST_STRTOULL("-02000000000000000000000",0, 18446744073709551615LLU, 24, ERANGE); + TEST_STRTOULL("-02000000000000000000000",8, 18446744073709551615LLU, 24, ERANGE); + TEST_STRTOULL("-2000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE); + + printf("success: strtoull\n"); + 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) +{ + printf("test: FUNCTION\n"); + if (strcmp(__FUNCTION__, "test_FUNCTION") != 0) { + printf("failure: FAILURE [\nFAILURE invalid\n]\n"); + return false; + } + printf("success: FUNCTION\n"); + return true; +} + +static int test_MIN(void) +{ + printf("test: MIN\n"); + if (MIN(20, 1) != 1) { + printf("failure: MIN [\nMIN invalid\n]\n"); + return false; + } + if (MIN(1, 20) != 1) { + printf("failure: MIN [\nMIN invalid\n]\n"); + return false; + } + printf("success: MIN\n"); + return true; +} + +static int test_MAX(void) +{ + printf("test: MAX\n"); + if (MAX(20, 1) != 20) { + printf("failure: MAX [\nMAX invalid\n]\n"); + return false; + } + if (MAX(1, 20) != 20) { + printf("failure: MAX [\nMAX invalid\n]\n"); + return false; + } + printf("success: MAX\n"); + 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; +} + +extern int libreplace_test_strptime(void); + +static int test_strptime(void) +{ + return libreplace_test_strptime(); +} + +extern int getifaddrs_test(void); + +static int test_getifaddrs(void) +{ + + printf("test: getifaddrs\n"); + + if (getifaddrs_test() != 0) { + printf("failure: getifaddrs\n"); + return false; + } + + printf("success: getifaddrs\n"); + return true; +} + +static int test_utime(void) +{ + struct utimbuf u; + struct stat st1, st2, st3; + int fd; + + printf("test: utime\n"); + unlink(TESTFILE); + + fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); + if (fd == -1) { + printf("failure: utime [\n" + "creating '%s' failed - %s\n]\n", + TESTFILE, strerror(errno)); + return false; + } + + if (fstat(fd, &st1) != 0) { + printf("failure: utime [\n" + "fstat (1) failed - %s\n]\n", + strerror(errno)); + return false; + } + + u.actime = st1.st_atime + 300; + u.modtime = st1.st_mtime - 300; + if (utime(TESTFILE, &u) != 0) { + printf("failure: utime [\n" + "utime(&u) failed - %s\n]\n", + strerror(errno)); + return false; + } + + if (fstat(fd, &st2) != 0) { + printf("failure: utime [\n" + "fstat (2) failed - %s\n]\n", + strerror(errno)); + return false; + } + + if (utime(TESTFILE, NULL) != 0) { + printf("failure: utime [\n" + "utime(NULL) failed - %s\n]\n", + strerror(errno)); + return false; + } + + if (fstat(fd, &st3) != 0) { + printf("failure: utime [\n" + "fstat (3) failed - %s\n]\n", + strerror(errno)); + return false; + } + +#define CMP_VAL(a,c,b) do { \ + if (a c b) { \ + printf("failure: utime [\n" \ + "%s: %s(%d) %s %s(%d)\n]\n", \ + __location__, \ + #a, (int)a, #c, #b, (int)b); \ + return false; \ + } \ +} while(0) +#define EQUAL_VAL(a,b) CMP_VAL(a,!=,b) +#define GREATER_VAL(a,b) CMP_VAL(a,<=,b) +#define LESSER_VAL(a,b) CMP_VAL(a,>=,b) + + EQUAL_VAL(st2.st_atime, st1.st_atime + 300); + EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300); + LESSER_VAL(st3.st_atime, st2.st_atime); + GREATER_VAL(st3.st_mtime, st2.st_mtime); + +#undef CMP_VAL +#undef EQUAL_VAL +#undef GREATER_VAL +#undef LESSER_VAL + + unlink(TESTFILE); + printf("success: utime\n"); + return true; +} + +static int test_utimes(void) +{ + struct timeval tv[2]; + struct stat st1, st2; + int fd; + + printf("test: utimes\n"); + unlink(TESTFILE); + + fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); + if (fd == -1) { + printf("failure: utimes [\n" + "creating '%s' failed - %s\n]\n", + TESTFILE, strerror(errno)); + return false; + } + + if (fstat(fd, &st1) != 0) { + printf("failure: utimes [\n" + "fstat (1) failed - %s\n]\n", + strerror(errno)); + return false; + } + + ZERO_STRUCT(tv); + tv[0].tv_sec = st1.st_atime + 300; + tv[1].tv_sec = st1.st_mtime - 300; + if (utimes(TESTFILE, tv) != 0) { + printf("failure: utimes [\n" + "utimes(tv) failed - %s\n]\n", + strerror(errno)); + return false; + } + + if (fstat(fd, &st2) != 0) { + printf("failure: utimes [\n" + "fstat (2) failed - %s\n]\n", + strerror(errno)); + return false; + } + +#define EQUAL_VAL(a,b) do { \ + if (a != b) { \ + printf("failure: utimes [\n" \ + "%s: %s(%d) != %s(%d)\n]\n", \ + __location__, \ + #a, (int)a, #b, (int)b); \ + return false; \ + } \ +} while(0) + + EQUAL_VAL(st2.st_atime, st1.st_atime + 300); + EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300); + +#undef EQUAL_VAL + + unlink(TESTFILE); + printf("success: utimes\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_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_strtoull(); + ret &= test_va_copy(); + ret &= test_FUNCTION(); + ret &= test_MIN(); + ret &= test_MAX(); + ret &= test_socketpair(); + ret &= test_strptime(); + ret &= test_getifaddrs(); + ret &= test_utime(); + ret &= test_utimes(); + + return ret; +} + +#if _SAMBA_BUILD_>3 +#else +int main(void) +{ + bool ret = torture_local_replace(NULL); + if (ret) + return 0; + return -1; +} +#endif diff --git a/replace/timegm.c b/replace/timegm.c new file mode 100644 index 000000000..395c684e1 --- /dev/null +++ b/replace/timegm.c @@ -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; +} diff --git a/replace/timegm.m4 b/replace/timegm.m4 new file mode 100644 index 000000000..59f3ae052 --- /dev/null +++ b/replace/timegm.m4 @@ -0,0 +1 @@ +AC_CHECK_FUNCS(timegm,[],[LIBREPLACEOBJ="${LIBREPLACEOBJ} timegm.o"]) diff --git a/replace/win32.m4 b/replace/win32.m4 new file mode 100644 index 000000000..eb364e2cb --- /dev/null +++ b/replace/win32.m4 @@ -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], libreplace_cv_mkdir_has_mode, + AC_TRY_COMPILE([ + #include + #ifdef HAVE_DIRECT_H + #include + #endif],[ + mkdir("foo",0777); + return 0; + ], + libreplace_cv_mkdir_has_mode="yes", + libreplace_cv_mkdir_has_mode="no") ) + +if test "$libreplace_cv_mkdir_has_mode" = "yes" +then + AC_DEFINE(HAVE_MKDIR_MODE, 1, [Define if target mkdir supports mode option]) +fi diff --git a/replace/win32_replace.h b/replace/win32_replace.h new file mode 100644 index 000000000..9901e72f6 --- /dev/null +++ b/replace/win32_replace.h @@ -0,0 +1,159 @@ +#ifndef _WIN32_REPLACE_H +#define _WIN32_REPLACE_H + +#ifdef HAVE_WINSOCK2_H +#include +#endif + +#ifdef HAVE_WS2TCPIP_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#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 */ diff --git a/talloc/Makefile.in b/talloc/Makefile.in new file mode 100644 index 000000000..9b1b6320b --- /dev/null +++ b/talloc/Makefile.in @@ -0,0 +1,53 @@ +#!gmake +# +prefix = @prefix@ +datarootdir = @datarootdir@ +exec_prefix = @exec_prefix@ +includedir = @includedir@ +libdir = @libdir@ +mandir = @mandir@ +VPATH = @srcdir@:@libreplacedir@ +srcdir = @srcdir@ +builddir = @builddir@ +buildinstdir = @buildinstdir@ +XSLTPROC = @XSLTPROC@ +INSTALLCMD = @INSTALL@ +CC = @CC@ +CFLAGS = @CFLAGS@ -DHAVE_CONFIG_H= -I. -I@srcdir@ +EXTRA_TARGETS = @DOC_TARGET@ +PICFLAG = @PICFLAG@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +SHLIBEXT = @SHLIBEXT@ +SHLD = @SHLD@ +SHLD_FLAGS = @SHLD_FLAGS@ +tallocdir = @tallocdir@ + +LIBOBJ = $(TALLOC_OBJ) @LIBREPLACEOBJ@ + +all:: showflags $(EXTRA_TARGETS) + +include $(tallocdir)/rules.mk +include $(tallocdir)/talloc.mk + +$(TALLOC_SOLIB): $(LIBOBJ) + $(SHLD) $(SHLD_FLAGS) -o $@ $(LIBOBJ) @SONAMEFLAG@$(TALLOC_SONAME) + +build-install:: all + ${INSTALLCMD} -d $(buildinstdir)/lib + ${INSTALLCMD} -m 755 libtalloc.a $(buildinstdir)/lib + ${INSTALLCMD} -m 755 $(TALLOC_SOLIB) $(buildinstdir)/lib + ln -sf $(TALLOC_SOLIB) $(buildinstdir)/lib/$(TALLOC_SONAME) + ln -sf $(TALLOC_SOLIB) $(buildinstdir)/lib/libtalloc.so + ${INSTALLCMD} -d $(buildinstdir)/include + ${INSTALLCMD} -m 644 $(srcdir)/talloc.h $(buildinstdir)/include + +check: test + +installcheck:: test install + +distclean:: clean + rm -f Makefile + rm -f config.log config.status config.h config.cache + +realdistclean:: distclean + rm -f configure config.h.in diff --git a/talloc/NEWS b/talloc/NEWS new file mode 100644 index 000000000..e5b3aa073 --- /dev/null +++ b/talloc/NEWS @@ -0,0 +1,13 @@ +1.0.1 26 May 2007 + + BUGS + + * Set name of correctly when using talloc_append_string() (metze) + + LICENSE + + * Change license of files in lib/replace to LGPL (was GPL). (jelmer) + +1.0.0 30 April 2007 + + Initial release. diff --git a/talloc/aclocal.m4 b/talloc/aclocal.m4 new file mode 100644 index 000000000..5605e476b --- /dev/null +++ b/talloc/aclocal.m4 @@ -0,0 +1 @@ +m4_include(libreplace.m4) diff --git a/talloc/autogen.sh b/talloc/autogen.sh new file mode 100755 index 000000000..bf84eeee1 --- /dev/null +++ b/talloc/autogen.sh @@ -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 + diff --git a/talloc/build_macros.m4 b/talloc/build_macros.m4 new file mode 100644 index 000000000..bb05a5822 --- /dev/null +++ b/talloc/build_macros.m4 @@ -0,0 +1,14 @@ +AC_DEFUN(BUILD_WITH_BUILD_INST_DIR, + [ AC_ARG_WITH([build-install-dir], + [AC_HELP_STRING([--with-build-install-dir=DIR], + [temporary build directory where libraries are installed [$srcdir/buildinst]])]) + + buildinstdir="$srcdir/buildinst" + if test x"$with_build_install_dir" != x; then + buildinstdir=$with_build_install_dir + CFLAGS="$CFLAGS -I$with_build_install_dir/include" + CPPFLAGS="$CPPFLAGS -I$with_build_install_dir/include" + LIBS="$LIBS -L$with_build_install_dir/lib" + fi + AC_SUBST(buildinstdir) + ]) diff --git a/talloc/config.guess b/talloc/config.guess new file mode 100755 index 000000000..354dbe175 --- /dev/null +++ b/talloc/config.guess @@ -0,0 +1,1464 @@ +#! /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 Free Software Foundation, Inc. + +timestamp='2005-08-03' + +# 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 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 . +# +# 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 . +# Please send patches to . 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 ." + +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 +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 -q "$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@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 ;; + *) 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 ;; + macppc:MirBSD:*:*) + echo powerppc-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@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 ;; + 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.*:*) + echo i386-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 /* 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 + + 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:*:[45]) + 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 + #include + + 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 + 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:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*: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 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [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:*:*) + 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 | grep ^CPU=` + 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 | grep ^CPU=` + 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 ;; + 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 ;; + x86_64:Linux:*:*) + echo x86_64-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 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + 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 + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + 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' /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 i386. + echo i386-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; } ;; + 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 + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@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 ;; + 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 ;; + 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 + *86) UNAME_PROCESSOR=i686 ;; + 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 ;; +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 < +# include +#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 + 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 +# 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 < 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: diff --git a/talloc/config.mk b/talloc/config.mk new file mode 100644 index 000000000..c13e1b79a --- /dev/null +++ b/talloc/config.mk @@ -0,0 +1,7 @@ +[LIBRARY::LIBTALLOC] +OUTPUT_TYPE = MERGED_OBJ +CFLAGS = -Ilib/talloc + +LIBTALLOC_OBJ_FILES = lib/talloc/talloc.o + +MANPAGES += $(tallocdir)/talloc.3 diff --git a/talloc/config.sub b/talloc/config.sub new file mode 100755 index 000000000..23cd6fd75 --- /dev/null +++ b/talloc/config.sub @@ -0,0 +1,1577 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-08' + +# 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 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 . +# +# 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 . 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 ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +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-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-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 + ;; + -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/'` + ;; + -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 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + 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) + ;; + + # 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-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | 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[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # 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 + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + 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 + ;; + cr16c) + basic_machine=cr16c-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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + 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 + ;; + 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 + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + 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 + ;; + 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 + ;; + 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[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + 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* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -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* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -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*) + # 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 + ;; + -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 + *-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 + ;; + 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: diff --git a/talloc/configure.ac b/talloc/configure.ac new file mode 100644 index 000000000..60314dcc7 --- /dev/null +++ b/talloc/configure.ac @@ -0,0 +1,27 @@ +AC_PREREQ(2.50) +AC_INIT(talloc, 1.2.0) +AC_CONFIG_SRCDIR([talloc.c]) +AC_SUBST(datarootdir) +AC_CONFIG_HEADER(config.h) + +AC_LIBREPLACE_ALL_CHECKS + +m4_include(libtalloc.m4) + +AC_PATH_PROG(XSLTPROC,xsltproc) +DOC_TARGET="" +if test -n "$XSLTPROC"; then + DOC_TARGET=doc +fi +AC_SUBST(DOC_TARGET) + +AC_LD_PICFLAG +AC_LD_SHLIBEXT +AC_LD_SONAMEFLAG +AC_LIBREPLACE_SHLD +AC_LIBREPLACE_SHLD_FLAGS + +m4_include(build_macros.m4) +BUILD_WITH_BUILD_INST_DIR + +AC_OUTPUT(Makefile talloc.pc) diff --git a/talloc/install-sh b/talloc/install-sh new file mode 100755 index 000000000..58719246f --- /dev/null +++ b/talloc/install-sh @@ -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 diff --git a/talloc/libtalloc.m4 b/talloc/libtalloc.m4 new file mode 100644 index 000000000..d2e8eba81 --- /dev/null +++ b/talloc/libtalloc.m4 @@ -0,0 +1,33 @@ +dnl find the talloc sources. This is meant to work both for +dnl talloc standalone builds, and builds of packages using talloc +tallocdir="" +tallocpaths="$srcdir $srcdir/lib/talloc $srcdir/talloc $srcdir/../talloc" +for d in $tallocpaths; do + if test -f "$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$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 ]) + 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 diff --git a/talloc/rules.mk b/talloc/rules.mk new file mode 100644 index 000000000..6cee12652 --- /dev/null +++ b/talloc/rules.mk @@ -0,0 +1,18 @@ +.SUFFIXES: .c .o .3 .3.xml .xml .html + +showflags:: + @echo 'talloc will be compiled with flags:' + @echo ' CFLAGS = $(CFLAGS)' + @echo ' LIBS = $(LIBS)' + +.c.o: + $(CC) $(PICFLAG) -o $@ -c $< $(CFLAGS) + +.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 $< + +distclean:: + rm -f *~ */*~ diff --git a/talloc/talloc.3.xml b/talloc/talloc.3.xml new file mode 100644 index 000000000..67de15bfc --- /dev/null +++ b/talloc/talloc.3.xml @@ -0,0 +1,738 @@ + + + + + talloc + 3 + + + talloc +hierarchical reference counted memory pool system with destructors + + +#include <talloc/talloc.h> + + DESCRIPTION + + If you are used to talloc from Samba3 then please read this + carefully, as talloc has changed a lot. + + + 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 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. + + + TALLOC API + + The following is a complete guide to the talloc API. Read it all at + least twice. + + (type *)talloc(const void *ctx, type); + + The talloc() macro is the core of the talloc library. It takes a + memory ctx 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 ctx 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 ctx then the new child disappears as + well. Alternatively you can free just the child. + + + The ctx argument to talloc() + can be NULL, in which case a new top level context is created. + + + void *talloc_size(const void *ctx, 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. The only + possible failure condition is if ptr had a destructor attached to it and + the destructor returned -1. See talloc_set_destructor() + for details on destructors. + + + 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. + + + void *talloc_reference(const void *ctx, const void *ptr); + + The talloc_reference() function makes ctx 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 *ctx, const void *ptr); + + The talloc_unlink() function removes a specific parent from + ptr. The ctx 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 ptr 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 *<emphasis role="italic">ptr</emphasis>); + + 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 *<emphasis role="italic">ptr</emphasis>); + + 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_depth_cb(), + talloc_report_depth_file(), + talloc_report() + 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 *<emphasis role="italic">ptr</emphasis>, const char *<emphasis role="italic">name</emphasis>); + + 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 ptr is freed + with talloc_free(). + + + void *talloc_named(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...); + + The talloc_named() function creates a named talloc pointer. It + is equivalent to: + + ptr = talloc_size(ctx, size); +talloc_set_name(ptr, fmt, ....); + + 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>); + + This is equivalent to: + + ptr = talloc_size(ctx, size); +talloc_set_name_const(ptr, name); + + const char *talloc_get_name(const void *<emphasis role="italic">ptr</emphasis>); + + This returns the current name for the given talloc pointer, + ptr. See talloc_set_name() + for details. + + + void *talloc_init(const char *<emphasis role="italic">fmt</emphasis>, ...); + + 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 *<emphasis role="italic">ctx</emphasis>); + + 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. + + + (<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>); + + The talloc_realloc() macro changes the size of a talloc pointer. + It has the following equivalences: + + talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type); +talloc_realloc(ctx, ptr, type, 0) ==> talloc_free(ptr); + + The ctx argument is only used + if ptr is not 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 *ctx, void *ptr, size_t size); + + the talloc_realloc_size() function is useful when the type is not + known so the type-safe talloc_realloc() cannot be used. + + + TYPE *talloc_steal(const void *<emphasis role="italic">new_ctx</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>); + + 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. + + + TYPE *talloc_move(const void *<emphasis role="italic">new_ctx</emphasis>, TYPE **<emphasis role="italic">ptr</emphasis>); + + 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. + + + size_t talloc_total_size(const void *<emphasis role="italic">ptr</emphasis>); + + 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 *<emphasis role="italic">ptr</emphasis>); + + 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(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 *<emphasis role="italic">ptr</emphasis>, FILE *<emphasis role="italic">f</emphasis>); + + 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. + + + 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_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_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) + + + (<emphasis role="italic">type</emphasis> *)talloc_zero(const void *<emphasis role="italic">ctx</emphasis>, <emphasis role="italic">type</emphasis>); + + The talloc_zero() macro is equivalent to: + + ptr = talloc(ctx, type); +if (ptr) memset(ptr, 0, sizeof(type)); + + void *talloc_zero_size(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>) + + The talloc_zero_size() function is useful when you don't have a + known type. + + + void *talloc_memdup(const void *<emphasis role="italic">ctx</emphasis>, const void *<emphasis role="italic">p</emphasis>, 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 *<emphasis role="italic">ctx</emphasis>, const char *<emphasis role="italic">p</emphasis>); + + The talloc_strdup() function is equivalent to: + + ptr = talloc_size(ctx, strlen(p)+1); +if (ptr) memcpy(ptr, p, strlen(p)+1); + + This function 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 *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">p</emphasis>, size_t <emphasis role="italic">n</emphasis>); + + The talloc_strndup() function is the talloc equivalent of the C + library function strndup(3). + + + This function 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 *<emphasis role="italic">t</emphasis>, char *<emphasis role="italic">orig</emphasis>, const char *<emphasis role="italic">append</emphasis>); + + 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 *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, va_list <emphasis role="italic">ap</emphasis>); + + The talloc_vasprintf() function is the talloc equivalent of the C + library function vasprintf(3). + + + 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_asprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...); + + The talloc_asprintf() function is the talloc equivalent of the C + library function asprintf(3). + + + This function sets the name of the new pointer to the passed + 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. + + + This function 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, uint_t 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, uint_t 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, uint_t 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 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. + + + 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) + + + PERFORMANCE + + 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. + + + SEE ALSO + + malloc(3), strndup(3), vasprintf(3), asprintf(3), + + + + COPYRIGHT/LICENSE + + 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/. + + + diff --git a/talloc/talloc.c b/talloc/talloc.c new file mode 100644 index 000000000..12b85f5a6 --- /dev/null +++ b/talloc/talloc.c @@ -0,0 +1,1724 @@ +/* + 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 . +*/ + +/* + inspired by http://swapped.cc/halloc/ +*/ + +#ifdef _SAMBA_BUILD_ +#include "version.h" +#if (SAMBA_VERSION_MAJOR<4) +#include "includes.h" +/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file + * we trust ourselves... */ +#ifdef malloc +#undef malloc +#endif +#ifdef realloc +#undef realloc +#endif +#define _TALLOC_SAMBA3 +#endif /* (SAMBA_VERSION_MAJOR<4) */ +#endif /* _SAMBA_BUILD_ */ + +#ifndef _TALLOC_SAMBA3 +#include "replace.h" +#include "talloc.h" +#endif /* not _TALLOC_SAMBA3 */ + +/* 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 0xe814ec70 +#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 */ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) x +#define unlikely(x) x +#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; +}; + +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)) + +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 & TALLOC_FLAG_FREE) { + talloc_abort_double_free(); + } else { + talloc_abort_unknown_value(); + } + } + 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; +} + +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 +*/ +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 + */ + +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 +*/ +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. +*/ +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 +*/ +void *_talloc_reference(const void *context, const void *ptr) +{ + 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); + _TLIST_ADD(tc->refs, handle); + return handle->ptr; +} + + +/* + internal talloc_free call +*/ +static inline int _talloc_free(void *ptr) +{ + 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(tc->refs); + if (is_child) { + return _talloc_free(ptr); + } + 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(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(new_parent, child); + } + } + + tc->flags |= TALLOC_FLAG_FREE; + + 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!"); + } + + *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. +*/ +void *_talloc_steal(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); +} + + + +/* + 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(h); +} + +/* + remove a specific parent context from a pointer. This is a more + controlled varient of talloc_free() +*/ +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(ptr); + } + + 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(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 +*/ +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. +*/ +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(ptr); + return NULL; + } + + return ptr; +} + +/* + return the name of a talloc ptr, or "UNNAMED" +*/ +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 +*/ +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; +} + + +/* + this is for compatibility with older versions of talloc +*/ +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(ptr); + 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. +*/ +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(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 +*/ +void *_talloc(const void *context, size_t size) +{ + return __talloc(context, size); +} + +/* + externally callable talloc_set_name_const() +*/ +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. +*/ +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 +*/ +int talloc_free(void *ptr) +{ + return _talloc_free(ptr); +} + + + +/* + A talloc version of realloc. The context argument is only used if + ptr is NULL +*/ +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_free(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 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, tc->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 +*/ +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, *pptr); + (*pptr) = NULL; + return ret; +} + +/* + return the total size of a talloc pool (subtree) +*/ +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; + + 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) +*/ +size_t talloc_total_blocks(const void *ptr) +{ + size_t total = 0; + struct talloc_chunk *c, *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 +*/ +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 +*/ +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 +*/ +void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *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 +*/ +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 +*/ +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 +*/ +void talloc_enable_null_tracking(void) +{ + if (null_context == NULL) { + null_context = _talloc_named_const(NULL, 0, "null_context"); + } +} + +/* + disable tracking of the NULL context +*/ +void talloc_disable_null_tracking(void) +{ + _talloc_free(null_context); + null_context = NULL; +} + +/* + enable leak reporting on exit +*/ +void talloc_enable_leak_report(void) +{ + talloc_enable_null_tracking(); + atexit(talloc_report_null); +} + +/* + enable full leak reporting on exit +*/ +void talloc_enable_leak_report_full(void) +{ + talloc_enable_null_tracking(); + atexit(talloc_report_null_full); +} + +/* + talloc and zero memory. +*/ +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. +*/ +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 +*/ +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 +*/ +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. + */ +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. + */ +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. + */ +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. + */ +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 + +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. + */ +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. + **/ +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. + **/ +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. + */ +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. + */ +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 +*/ +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 +*/ +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 +*/ +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) +*/ +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 +*/ +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; +} + +size_t talloc_get_size(const void *context) +{ + struct talloc_chunk *tc; + + 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 +*/ +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 +*/ +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 +*/ +int talloc_is_parent(const void *context, const void *ptr) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(context); + while (tc) { + if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } + return 0; +} diff --git a/talloc/talloc.h b/talloc/talloc.h new file mode 100644 index 000000000..543197165 --- /dev/null +++ b/talloc/talloc.h @@ -0,0 +1,183 @@ +#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 . +*/ + +#include +#include +#include + +/* this is only needed for compatibility with the old talloc */ +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 + +/* 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((ctx),(ptr)); __talloc_steal_ret; }) +#else +#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((ctx),(ptr)) +#endif + +#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr)) +#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr)) + +/* useful macros for creating type checked pointers */ +#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type) +#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__) +#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr))) + +#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__) + +#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type) +#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__) + +#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type) +#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type) +#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__) +#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count) + +#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type) +#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__) + +#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__) + +#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type) +#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type) + +#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type) + +#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 + +/* The following definitions come from talloc.c */ +void *_talloc(const void *context, size_t size); +void *talloc_pool(const void *context, size_t size); +void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)); +int talloc_increase_ref_count(const void *ptr); +size_t talloc_reference_count(const void *ptr); +void *_talloc_reference(const void *context, const void *ptr); +int talloc_unlink(const void *context, void *ptr); +const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); +void talloc_set_name_const(const void *ptr, const char *name); +void *talloc_named(const void *context, size_t size, + const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); +void *talloc_named_const(const void *context, size_t size, const char *name); +const char *talloc_get_name(const void *ptr); +void *talloc_check_name(const void *ptr, const char *name); +void *talloc_parent(const void *ptr); +const char *talloc_parent_name(const void *ptr); +void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); +int talloc_free(void *ptr); +void talloc_free_children(void *ptr); +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name); +void *_talloc_steal(const void *new_ctx, const void *ptr); +void *_talloc_move(const void *new_ctx, const void *pptr); +size_t talloc_total_size(const void *ptr); +size_t talloc_total_blocks(const void *ptr); +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); +void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f); +void talloc_report_full(const void *ptr, FILE *f); +void talloc_report(const void *ptr, FILE *f); +void talloc_enable_null_tracking(void); +void talloc_disable_null_tracking(void); +void talloc_enable_leak_report(void); +void talloc_enable_leak_report_full(void); +void *_talloc_zero(const void *ctx, size_t size, const char *name); +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name); +void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name); +void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name); +void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name); +void *talloc_realloc_fn(const void *context, void *ptr, size_t size); +void *talloc_autofree_context(void); +size_t talloc_get_size(const void *ctx); +void *talloc_find_parent_byname(const void *ctx, const char *name); +void talloc_show_parents(const void *context, FILE *file); +int talloc_is_parent(const void *context, const void *ptr); + +char *talloc_strdup(const void *t, const char *p); +char *talloc_strdup_append(char *s, const char *a); +char *talloc_strdup_append_buffer(char *s, const char *a); + +char *talloc_strndup(const void *t, const char *p, size_t n); +char *talloc_strndup_append(char *s, const char *a, size_t n); +char *talloc_strndup_append_buffer(char *s, const char *a, size_t n); + +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); +char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); +char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); + +char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); +char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); +char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); + +#endif diff --git a/talloc/talloc.i b/talloc/talloc.i new file mode 100644 index 000000000..a9afb97ed --- /dev/null +++ b/talloc/talloc.i @@ -0,0 +1,31 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Jelmer Vernooij 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 . +*/ + +/* Don't expose talloc contexts in Python code. Python does reference + counting for us, so just create a new top-level talloc context. + */ +%typemap(in, numinputs=0, noblock=1) TALLOC_CTX * { + $1 = NULL; +} + +%define %talloctype(TYPE) +%nodefaultctor TYPE; +%extend TYPE { + ~TYPE() { talloc_free($self); } +} +%enddef diff --git a/talloc/talloc.mk b/talloc/talloc.mk new file mode 100644 index 000000000..23331b636 --- /dev/null +++ b/talloc/talloc.mk @@ -0,0 +1,37 @@ +TALLOC_OBJ = $(tallocdir)/talloc.o + +TALLOC_SOLIB = libtalloc.$(SHLIBEXT).$(PACKAGE_VERSION) +TALLOC_SONAME = libtalloc.$(SHLIBEXT).1 + +all:: libtalloc.a $(TALLOC_SOLIB) testsuite + +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} -m 755 $(TALLOC_SOLIB) $(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 + which swig >/dev/null 2>&1 && ${INSTALLCMD} -d $(DESTDIR)$(prefix)`swig -swiglib` || true + which swig >/dev/null 2>&1 && ${INSTALLCMD} -m 644 talloc.i $(DESTDIR)$(prefix)`swig -swiglib` || true + +doc:: talloc.3 talloc.3.html + +clean:: + rm -f *~ $(LIBOBJ) $(TALLOC_SOLIB) libtalloc.a testsuite testsuite.o *.gc?? talloc.3 talloc.3.html + +test:: testsuite + ./testsuite + +gcov:: + gcov talloc.c diff --git a/talloc/talloc.pc.in b/talloc/talloc.pc.in new file mode 100644 index 000000000..459cce70b --- /dev/null +++ b/talloc/talloc.pc.in @@ -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: @PACKAGE_VERSION@ +Libs: -L${libdir} -ltalloc +Cflags: -I${includedir} +URL: http://talloc.samba.org/ diff --git a/talloc/talloc_guide.txt b/talloc/talloc_guide.txt new file mode 100644 index 000000000..18663b370 --- /dev/null +++ b/talloc/talloc_guide.txt @@ -0,0 +1,685 @@ +Using talloc in Samba4 +---------------------- + +Andrew Tridgell +September 2004 + +The most current version of this document is available at + http://samba.org/ftp/unpacked/samba4/source/lib/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. The only 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. + +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. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +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. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +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, uint_t 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, uint_t 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, uint_t 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. + diff --git a/talloc/testsuite.c b/talloc/testsuite.c new file mode 100644 index 000000000..3f06eee56 --- /dev/null +++ b/talloc/testsuite.c @@ -0,0 +1,1152 @@ +/* + 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 . +*/ + +#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 [\nwrong '%s' tree size: got %u expected %u\n]\n", \ + test, #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 [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \ + test, #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' has wrong parent: got %p expected %p\n]\n", \ + test, #ptr, \ + talloc_parent(ptr), \ + (parent)); \ + talloc_report_full(ptr, stdout); \ + talloc_report_full(parent, stdout); \ + talloc_report_full(NULL, stdout); \ + return false; \ + } \ +} while (0) + + +/* + 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_free(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_free(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_free(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_free(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_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, 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, 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;ireq2 = 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; +} + +struct torture_context; +bool torture_local_talloc(struct torture_context *tctx) +{ + bool ret = true; + + setlinebuf(stdout); + + talloc_disable_null_tracking(); + talloc_enable_null_tracking(); + + ret &= test_ref1(); + ret &= test_ref2(); + ret &= test_ref3(); + ret &= test_ref4(); + ret &= test_unlink1(); + ret &= test_misc(); + ret &= test_realloc(); + ret &= test_realloc_child(); + ret &= test_steal(); + ret &= test_move(); + ret &= test_unref_reparent(); + ret &= test_realloc_fn(); + ret &= test_type(); + ret &= test_lifeless(); + ret &= test_loop(); + ret &= test_free_parent_deny_child(); + ret &= test_talloc_ptrtype(); + ret &= test_talloc_free_in_destructor(); + ret &= test_pool(); + + if (ret) { + ret &= test_speed(); + } + ret &= test_autofree(); + + return ret; +} + +#if _SAMBA_BUILD_ < 4 +int main(void) +{ + bool ret = torture_local_talloc(NULL); + if (!ret) + return -1; + return 0; +} +#endif diff --git a/talloc/web/index.html b/talloc/web/index.html new file mode 100644 index 000000000..5deab9366 --- /dev/null +++ b/talloc/web/index.html @@ -0,0 +1,46 @@ + + + +talloc + + + +

talloc

+ +talloc is a hierarchical pool based memory allocator with +destructors. It is the core memory allocator used in Samba4, and has +made a huge difference in many aspects of Samba4 development.

+ +To get started with talloc, I would recommend you read the talloc guide. + +

Discussion and bug reports

+ +talloc does not currently have its own mailing list or bug tracking +system. For now, please use the samba-technical +mailing list, and the Samba +bugzilla bug tracking system. + +

Download

+ +You can download the latest release either via rsync or git.
+
+To fetch via git see the following guide:
+Using Git for Samba Development
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/talloc directory.
+
+To fetch via rsync use this command: + +
+  rsync -Pavz samba.org::ftp/unpacked/talloc .
+
+ +
+ +Andrew Tridgell
+talloc AT tridgell.net +
+ + + diff --git a/tdb/Makefile.in b/tdb/Makefile.in new file mode 100644 index 000000000..0ec6c1a8d --- /dev/null +++ b/tdb/Makefile.in @@ -0,0 +1,70 @@ +#!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@ +buildinstdir = @buildinstdir@ +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@ +SWIG = swig +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@ + +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) @SONAMEFLAG@$(TDB_SONAME) + +build-install: all + ${INSTALLCMD} -d $(buildinstdir)/lib + ${INSTALLCMD} -m 755 libtdb.a $(buildinstdir)/lib + ${INSTALLCMD} -m 755 $(TDB_SOLIB) $(buildinstdir)/lib + ln -sf $(TDB_SOLIB) $(buildinstdir)/lib/$(TDB_SONAME) + ln -sf $(TDB_SOLIB) $(buildinstdir)/lib/libtdb.so + ${INSTALLCMD} -d $(buildinstdir)/include + ${INSTALLCMD} -m 644 $(srcdir)/include/tdb.h $(buildinstdir)/include + +check: test + +test:: $(PYTHON_CHECK_TARGET) +installcheck:: test install + +clean:: + rm -f *.o *.a */*.o + +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 diff --git a/tdb/aclocal.m4 b/tdb/aclocal.m4 new file mode 100644 index 000000000..5605e476b --- /dev/null +++ b/tdb/aclocal.m4 @@ -0,0 +1 @@ +m4_include(libreplace.m4) diff --git a/tdb/autogen.sh b/tdb/autogen.sh new file mode 100755 index 000000000..88ac4cfcf --- /dev/null +++ b/tdb/autogen.sh @@ -0,0 +1,16 @@ +#!/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 + +swig -O -Wall -python -keyword tdb.i # Ignore errors for now + +echo "Now run ./configure and then make." +exit 0 + diff --git a/tdb/build_macros.m4 b/tdb/build_macros.m4 new file mode 100644 index 000000000..bb05a5822 --- /dev/null +++ b/tdb/build_macros.m4 @@ -0,0 +1,14 @@ +AC_DEFUN(BUILD_WITH_BUILD_INST_DIR, + [ AC_ARG_WITH([build-install-dir], + [AC_HELP_STRING([--with-build-install-dir=DIR], + [temporary build directory where libraries are installed [$srcdir/buildinst]])]) + + buildinstdir="$srcdir/buildinst" + if test x"$with_build_install_dir" != x; then + buildinstdir=$with_build_install_dir + CFLAGS="$CFLAGS -I$with_build_install_dir/include" + CPPFLAGS="$CPPFLAGS -I$with_build_install_dir/include" + LIBS="$LIBS -L$with_build_install_dir/lib" + fi + AC_SUBST(buildinstdir) + ]) diff --git a/tdb/common/dump.c b/tdb/common/dump.c new file mode 100644 index 000000000..d1c902ddf --- /dev/null +++ b/tdb/common/dump.c @@ -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 . +*/ + +#include "tdb_private.h" + +static tdb_off_t tdb_dump_record(struct tdb_context *tdb, int hash, + tdb_off_t offset) +{ + struct list_struct 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;iheader.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 list_struct 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); +} + diff --git a/tdb/common/error.c b/tdb/common/error.c new file mode 100644 index 000000000..195ab2381 --- /dev/null +++ b/tdb/common/error.c @@ -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 . +*/ + +#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"; +} + diff --git a/tdb/common/freelist.c b/tdb/common/freelist.c new file mode 100644 index 000000000..2f2a4c379 --- /dev/null +++ b/tdb/common/freelist.c @@ -0,0 +1,382 @@ + /* + 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 . +*/ + +#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 list_struct *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 TDB_ERRCODE(TDB_ERR_CORRUPT, -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_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off)); + return TDB_ERRCODE(TDB_ERR_CORRUPT, -1); +} +#endif + + +/* update a record tailer (must hold allocation lock) */ +static int update_tailer(struct tdb_context *tdb, tdb_off_t offset, + const struct list_struct *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 + neccessary. */ +int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *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 list_struct 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 list_struct 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 list_struct *rec, tdb_off_t last_ptr) +{ +#define MIN_REC_SIZE (sizeof(struct list_struct) + 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 list_struct 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 list_struct *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; + + /* 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; +} diff --git a/tdb/common/freelistcheck.c b/tdb/common/freelistcheck.c new file mode 100644 index 000000000..efc050df9 --- /dev/null +++ b/tdb/common/freelistcheck.c @@ -0,0 +1,107 @@ +/* + 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 . +*/ + +#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 list_struct 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) { + ret = TDB_ERRCODE(TDB_ERR_CORRUPT, -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)) { + ret = TDB_ERRCODE(TDB_ERR_CORRUPT, -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; +} diff --git a/tdb/common/io.c b/tdb/common/io.c new file mode 100644 index 000000000..172ab69d8 --- /dev/null +++ b/tdb/common/io.c @@ -0,0 +1,471 @@ + /* + 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 . +*/ + + +#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 TDB_ERRCODE(TDB_ERR_IO, -1); + } + + if (fstat(tdb->fd, &st) == -1) { + return TDB_ERRCODE(TDB_ERR_IO, -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 TDB_ERRCODE(TDB_ERR_IO, -1); + } + + /* Unmap, update size, remap */ + if (tdb_munmap(tdb) == -1) + return TDB_ERRCODE(TDB_ERR_IO, -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_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only " + "%d of %d bytes at %d, trying once more\n", + (int)written, len, off)); + errno = ENOSPC; + written = pwrite(tdb->fd, (const void *)((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 TDB_ERRCODE(TDB_ERR_IO, -1); + } else if (written != (ssize_t)len) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to " + "write %d bytes at %d in two attempts\n", + len, off)); + errno = ENOSPC; + return TDB_ERRCODE(TDB_ERR_IO, -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 TDB_ERRCODE(TDB_ERR_IO, -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 = 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 list_struct 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 (len == 0) { + len = 1; + } + + if (!(buf = (unsigned char *)malloc(len))) { + /* 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 TDB_ERRCODE(TDB_ERR_OOM, buf); + } + 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 list_struct *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 TDB_ERRCODE(TDB_ERR_CORRUPT, -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 list_struct *rec) +{ + struct list_struct 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, + tdb_brlock +}; + +/* + initialise the default methods table +*/ +void tdb_io_init(struct tdb_context *tdb) +{ + tdb->methods = &io_methods; +} diff --git a/tdb/common/lock.c b/tdb/common/lock.c new file mode 100644 index 000000000..f156c0fa7 --- /dev/null +++ b/tdb/common/lock.c @@ -0,0 +1,553 @@ + /* + 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 . +*/ + +#include "tdb_private.h" + +#define TDB_MARK_LOCK 0x80000000 + +void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr) +{ + tdb->interrupt_sig_ptr = ptr; +} + +/* 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, tdb_off_t offset, + int rw_type, int lck_type, int probe, size_t len) +{ + struct flock fl; + int ret; + + if (tdb->flags & TDB_NOLOCK) { + return 0; + } + + if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) { + tdb->ecode = TDB_ERR_RDONLY; + return -1; + } + + fl.l_type = rw_type; + fl.l_whence = SEEK_SET; + fl.l_start = offset; + fl.l_len = len; + fl.l_pid = 0; + + do { + ret = fcntl(tdb->fd,lck_type,&fl); + + /* 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) { + /* Generic lock error. errno set by fcntl. + * EAGAIN is an expected return from non-blocking + * locks. */ + if (!probe && lck_type != F_SETLK) { + /* Ensure error code is set for log fun to examine. */ + tdb->ecode = TDB_ERR_LOCK; + TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n", + tdb->fd, offset, rw_type, lck_type, (int)len)); + } + return TDB_ERRCODE(TDB_ERR_LOCK, -1); + } + return 0; +} + + +/* + 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_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len) +{ + int count = 1000; + while (count--) { + struct timeval tv; + if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 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_brlock_upgrade failed at offset %d\n", offset)); + return -1; +} + + +/* lock a list in the database. list -1 is the alloc list */ +static int _tdb_lock(struct tdb_context *tdb, int list, int ltype, int op) +{ + struct tdb_lock_type *new_lck; + int i; + bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); + + ltype &= ~TDB_MARK_LOCK; + + /* a global lock allows us to avoid per chain locks */ + if (tdb->global_lock.count && + (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { + return 0; + } + + if (tdb->global_lock.count) { + return TDB_ERRCODE(TDB_ERR_LOCK, -1); + } + + if (list < -1 || list >= (int)tdb->header.hash_size) { + TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n", + list, ltype)); + return -1; + } + if (tdb->flags & TDB_NOLOCK) + return 0; + + for (i=0; inum_lockrecs; i++) { + if (tdb->lockrecs[i].list == list) { + if (tdb->lockrecs[i].count == 0) { + /* + * Can't happen, see tdb_unlock(). It should + * be an assert. + */ + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: " + "lck->count == 0 for list %d", list)); + } + /* + * Just increment the in-memory struct, posix locks + * don't stack. + */ + tdb->lockrecs[i].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 (!mark_lock && + tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list, ltype, op, + 0, 1)) { + return -1; + } + + tdb->num_locks++; + + tdb->lockrecs[tdb->num_lockrecs].list = list; + tdb->lockrecs[tdb->num_lockrecs].count = 1; + tdb->lockrecs[tdb->num_lockrecs].ltype = ltype; + tdb->num_lockrecs += 1; + + return 0; +} + +/* 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(tdb, list, ltype, F_SETLKW); + 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(tdb, list, ltype, F_SETLK); +} + + +/* unlock the database: returns void because it's too late for errors. */ + /* changed to return int it may be interesting to know there + has been an error --simo */ +int tdb_unlock(struct tdb_context *tdb, int list, int ltype) +{ + int ret = -1; + int i; + struct tdb_lock_type *lck = NULL; + bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); + + ltype &= ~TDB_MARK_LOCK; + + /* a global lock allows us to avoid per chain locks */ + if (tdb->global_lock.count && + (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { + return 0; + } + + if (tdb->global_lock.count) { + return TDB_ERRCODE(TDB_ERR_LOCK, -1); + } + + if (tdb->flags & TDB_NOLOCK) + return 0; + + /* Sanity checks */ + if (list < -1 || list >= (int)tdb->header.hash_size) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size)); + return ret; + } + + for (i=0; inum_lockrecs; i++) { + if (tdb->lockrecs[i].list == list) { + lck = &tdb->lockrecs[i]; + break; + } + } + + 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->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, + F_SETLKW, 0, 1); + } + tdb->num_locks--; + + /* + * Shrink the array by overwriting the element just unlocked with the + * last array element. + */ + + if (tdb->num_lockrecs > 1) { + *lck = tdb->lockrecs[tdb->num_lockrecs-1]; + } + tdb->num_lockrecs -= 1; + + /* + * 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; +} + +/* + get the transaction lock + */ +int tdb_transaction_lock(struct tdb_context *tdb, int ltype) +{ + if (tdb->have_transaction_lock || tdb->global_lock.count) { + return 0; + } + if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype, + F_SETLKW, 0, 1) == -1) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_lock: failed to get transaction lock\n")); + tdb->ecode = TDB_ERR_LOCK; + return -1; + } + tdb->have_transaction_lock = 1; + return 0; +} + +/* + release the transaction lock + */ +int tdb_transaction_unlock(struct tdb_context *tdb) +{ + int ret; + if (!tdb->have_transaction_lock) { + return 0; + } + ret = tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); + if (ret == 0) { + tdb->have_transaction_lock = 0; + } + return ret; +} + + + + +/* lock/unlock entire database */ +static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op) +{ + bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); + + ltype &= ~TDB_MARK_LOCK; + + /* There are no locks on read-only dbs */ + if (tdb->read_only || tdb->traverse_read) + return TDB_ERRCODE(TDB_ERR_LOCK, -1); + + if (tdb->global_lock.count && tdb->global_lock.ltype == ltype) { + tdb->global_lock.count++; + return 0; + } + + if (tdb->global_lock.count) { + /* a global lock of a different type exists */ + return TDB_ERRCODE(TDB_ERR_LOCK, -1); + } + + if (tdb->num_locks != 0) { + /* can't combine global and chain locks */ + return TDB_ERRCODE(TDB_ERR_LOCK, -1); + } + + if (!mark_lock && + tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, op, + 0, 4*tdb->header.hash_size)) { + if (op == F_SETLKW) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno))); + } + return -1; + } + + tdb->global_lock.count = 1; + tdb->global_lock.ltype = ltype; + + return 0; +} + + + +/* unlock entire db */ +static int _tdb_unlockall(struct tdb_context *tdb, int ltype) +{ + bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); + + ltype &= ~TDB_MARK_LOCK; + + /* There are no locks on read-only dbs */ + if (tdb->read_only || tdb->traverse_read) { + return TDB_ERRCODE(TDB_ERR_LOCK, -1); + } + + if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) { + return TDB_ERRCODE(TDB_ERR_LOCK, -1); + } + + if (tdb->global_lock.count > 1) { + tdb->global_lock.count--; + return 0; + } + + if (!mark_lock && + tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, + 0, 4*tdb->header.hash_size)) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno))); + return -1; + } + + tdb->global_lock.count = 0; + tdb->global_lock.ltype = 0; + + return 0; +} + +/* lock entire database with write lock */ +int tdb_lockall(struct tdb_context *tdb) +{ + return _tdb_lockall(tdb, F_WRLCK, F_SETLKW); +} + +/* lock entire database with write lock - mark only */ +int tdb_lockall_mark(struct tdb_context *tdb) +{ + return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW); +} + +/* unlock entire database with write lock - unmark only */ +int tdb_lockall_unmark(struct tdb_context *tdb) +{ + return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK); +} + +/* lock entire database with write lock - nonblocking varient */ +int tdb_lockall_nonblock(struct tdb_context *tdb) +{ + return _tdb_lockall(tdb, F_WRLCK, F_SETLK); +} + +/* unlock entire database with write lock */ +int tdb_unlockall(struct tdb_context *tdb) +{ + return _tdb_unlockall(tdb, F_WRLCK); +} + +/* lock entire database with read lock */ +int tdb_lockall_read(struct tdb_context *tdb) +{ + return _tdb_lockall(tdb, F_RDLCK, F_SETLKW); +} + +/* lock entire database with read lock - nonblock varient */ +int tdb_lockall_read_nonblock(struct tdb_context *tdb) +{ + return _tdb_lockall(tdb, F_RDLCK, F_SETLK); +} + +/* unlock entire database with read lock */ +int tdb_unlockall_read(struct tdb_context *tdb) +{ + return _tdb_unlockall(tdb, F_RDLCK); +} + +/* 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) +{ + return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); +} + +/* 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) +{ + return tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); +} + +/* 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) +{ + return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); +} + +/* 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) +{ + return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); +} + +int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) +{ + return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); +} + +int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key) +{ + return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); +} + +int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA 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->global_lock.count) { + return 0; + } + return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 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; + return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1); +} + +/* + 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_unlock_record(struct tdb_context *tdb, tdb_off_t off) +{ + return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 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->global_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->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0); +} diff --git a/tdb/common/open.c b/tdb/common/open.c new file mode 100644 index 000000000..b19e4cea2 --- /dev/null +++ b/tdb/common/open.c @@ -0,0 +1,488 @@ + /* + 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 . +*/ + +#include "tdb_private.h" + +/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */ +static struct tdb_context *tdbs = NULL; + + +/* This is based on the hash algorithm from gdbm */ +static unsigned int default_tdb_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); +} + + +/* 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; + ssize_t written; + + /* 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))) + return TDB_ERRCODE(TDB_ERR_OOM, -1); + + /* Fill in the header */ + newdb->version = TDB_VERSION; + newdb->hash_size = hash_size; + 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 */ + written = write(tdb->fd, newdb, size); + if (written == size) { + ret = 0; + } else if (written != -1) { + /* call write once again, this usually should return -1 and + * set errno appropriately */ + size -= written; + written = write(tdb->fd, newdb+written, size); + if (written == size) { + ret = 0; + } else if (written >= 0) { + /* a second incomplete write - we give up. + * guessing the errno... */ + errno = ENOSPC; + } + } + + 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, ...) +{ +} + + +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; + + if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) { + /* Can't log this */ + errno = ENOMEM; + goto fail; + } + tdb_io_init(tdb); + tdb->fd = -1; + 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; + } + tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash; + + /* 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; + } + + /* 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->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global 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->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 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 + || (tdb->header.version != TDB_VERSION + && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) { + /* its not a valid database - possibly initialise it */ + 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); + } + 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_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n")); + 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->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " + "failed to take 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->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1) + goto fail; + } + + /* if needed, run recovery */ + if (tdb_transaction_recover(tdb) == -1) { + goto fail; + } + + internal: + /* Internal (memory-only) databases skip all the code above to + * do with disk files, and resume here by releasing their + * global lock and hooking into the active list. */ + if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1) + goto fail; + tdb->next = tdbs; + tdbs = tdb; + return tdb; + + fail: + { int save_errno = errno; + + if (!tdb) + return NULL; + + 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); + 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); + } + + 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); + SAFE_FREE(tdb->lockrecs); + + /* Remove from contexts list */ + for (i = &tdbs; *i; i = &(*i)->next) { + if (*i == tdb) { + *i = tdb->next; + break; + } + } + + 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; +} + +/* 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) +{ + struct stat st; + + if (tdb->flags & TDB_INTERNAL) { + return 0; /* Nothing to do. */ + } + + if (tdb->num_locks != 0 || tdb->global_lock.count) { + 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 (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 ((tdb->flags & TDB_CLEAR_IF_FIRST) && + (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n")); + 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); + + return 0; + +fail: + tdb_close(tdb); + return -1; +} + +/* reopen all tdb's */ +int tdb_reopen_all(int parent_longlived) +{ + struct tdb_context *tdb; + + for (tdb=tdbs; tdb; tdb = tdb->next) { + /* + * 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. */ + tdb->flags &= ~TDB_CLEAR_IF_FIRST; + } + + if (tdb_reopen(tdb) != 0) + return -1; + } + + return 0; +} diff --git a/tdb/common/tdb.c b/tdb/common/tdb.c new file mode 100644 index 000000000..767452c9b --- /dev/null +++ b/tdb/common/tdb.c @@ -0,0 +1,802 @@ + /* + 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 . +*/ + +#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_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) { + return; + } + + tdb_increment_seqnum_nonblock(tdb); + + tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1); +} + +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 list_struct *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; + } + rec_ptr = r->next; + } + return TDB_ERRCODE(TDB_ERR_NOEXIST, 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 list_struct *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; +} + + +/* 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 list_struct rec; + tdb_off_t rec_ptr; + + /* find entry */ + if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) + return -1; + + /* 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 + */ +TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key) +{ + tdb_off_t rec_ptr; + struct list_struct 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; +} + +/* + * 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. + * + * DONT 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. + */ + +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 list_struct 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))) { + return TDB_ERRCODE(TDB_ERR_NOEXIST, 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 list_struct 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); + return tdb_exists_hash(tdb, key, hash); +} + +/* actually delete an entry in the database given the offset */ +int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *rec) +{ + tdb_off_t last_ptr, i; + struct list_struct lastrec; + + if (tdb->read_only || tdb->traverse_read) return -1; + + if (tdb->traverse_write != 0 || + 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 list_struct 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 list_struct 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 list_struct 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); + return tdb_delete_hash(tdb, key, hash); +} + +/* + * 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 list_struct *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; +} + +/* 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) +{ + struct list_struct rec; + uint32_t hash; + tdb_off_t rec_ptr; + char *p = NULL; + int ret = -1; + + if (tdb->read_only || tdb->traverse_read) { + tdb->ecode = TDB_ERR_RDONLY; + 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; + + /* 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); + 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 char *new_dptr = (unsigned char *)realloc(dbuf.dptr, + dbuf.dsize + new_dbuf.dsize); + 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); + +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) +{ + tdb->flags |= flags; +} + +void tdb_remove_flags(struct tdb_context *tdb, unsigned flags) +{ + 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 list_struct 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 global 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; + } + + /* 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 list_struct 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;iheader.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; +} diff --git a/tdb/common/tdb_private.h b/tdb/common/tdb_private.h new file mode 100644 index 000000000..ffac89ff0 --- /dev/null +++ b/tdb/common/tdb_private.h @@ -0,0 +1,213 @@ + /* + 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 . +*/ + +#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" + +#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_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 + +/* lock offsets */ +#define GLOBAL_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 list_struct for the free space + plus a separate data list for each hash value */ +struct list_struct { + 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 */ + tdb_off_t reserved[29]; +}; + +struct tdb_lock_type { + int list; + uint32_t count; + uint32_t ltype; +}; + +struct tdb_traverse_lock { + struct tdb_traverse_lock *next; + uint32_t off; + uint32_t hash; + int lock_rw; +}; + + +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 ); + int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int, size_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 global_lock; + 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 */ + unsigned int num_locks; /* number of chain locks held */ + const struct tdb_methods *methods; + struct tdb_transaction *transaction; + int page_size; + int max_dead_records; + bool have_transaction_lock; + 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_unlock(struct tdb_context *tdb, int list, int ltype); +int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len); +int tdb_transaction_lock(struct tdb_context *tdb, int ltype); +int tdb_transaction_unlock(struct tdb_context *tdb); +int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len); +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 list_struct *rec); +tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_struct *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); +int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec); +int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec); +int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *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 list_struct *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 list_struct *rec); + + diff --git a/tdb/common/transaction.c b/tdb/common/transaction.c new file mode 100644 index 000000000..4e2127be6 --- /dev/null +++ b/tdb/common/transaction.c @@ -0,0 +1,1119 @@ + /* + 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 . +*/ + +#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 + global 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. + +*/ + + +/* + 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; + + /* old file size before transaction */ + tdb_len_t old_map_size; +}; + + +/* + 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; + + /* 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; + } + return TDB_ERRCODE(TDB_ERR_IO, -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; + } + + return 0; +} + +/* + brlock during a transaction - ignore them +*/ +static int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset, + int rw_type, int lck_type, int probe, size_t len) +{ + return 0; +} + +static const struct tdb_methods transaction_methods = { + transaction_read, + transaction_write, + transaction_next_hash_chain, + transaction_oob, + transaction_expand_file, + transaction_brlock +}; + + +/* + start a tdb transaction. No token is returned, as only a single + transaction is allowed to be pending per tdb_context +*/ +int tdb_transaction_start(struct tdb_context *tdb) +{ + /* 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) { + tdb->transaction->nesting++; + TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", + tdb->transaction->nesting)); + return 0; + } + + if (tdb->num_locks != 0 || tdb->global_lock.count) { + /* 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) == -1) { + SAFE_FREE(tdb->transaction->blocks); + SAFE_FREE(tdb->transaction); + 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_brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n")); + tdb->ecode = TDB_ERR_LOCK; + goto fail; + } + + /* 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; + + return 0; + +fail: + tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0); + tdb_transaction_unlock(tdb); + SAFE_FREE(tdb->transaction->blocks); + SAFE_FREE(tdb->transaction->hash_heads); + SAFE_FREE(tdb->transaction); + return -1; +} + + +/* + cancel the current transaction +*/ +int tdb_transaction_cancel(struct tdb_context *tdb) +{ + int i; + + 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;itransaction->num_blocks;i++) { + if (tdb->transaction->blocks[i] != NULL) { + free(tdb->transaction->blocks[i]); + } + } + SAFE_FREE(tdb->transaction->blocks); + + /* remove any global lock created during the transaction */ + if (tdb->global_lock.count != 0) { + tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size); + tdb->global_lock.count = 0; + } + + /* remove any locks created during the transaction */ + if (tdb->num_locks != 0) { + for (i=0;inum_lockrecs;i++) { + tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list, + F_UNLCK,F_SETLKW, 0, 1); + } + tdb->num_locks = 0; + tdb->num_lockrecs = 0; + SAFE_FREE(tdb->lockrecs); + } + + /* restore the normal io methods */ + tdb->methods = tdb->transaction->io_methods; + + tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0); + tdb_transaction_unlock(tdb); + SAFE_FREE(tdb->transaction->hash_heads); + SAFE_FREE(tdb->transaction); + + return 0; +} + +/* + sync to disk +*/ +static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length) +{ + if (fsync(tdb->fd) != 0) { + tdb->ecode = TDB_ERR_IO; + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n")); + return -1; + } +#ifdef MS_SYNC + 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; +} + + +/* + 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;itransaction->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 list_struct 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 && + 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; + } + + *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 list_struct *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 list_struct *)data; + memset(rec, 0, sizeof(*rec)); + + rec->magic = 0; + 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;itransaction->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 list_struct, 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; +} + +/* + commit the current transaction +*/ +int tdb_transaction_commit(struct tdb_context *tdb) +{ + const struct tdb_methods *methods; + tdb_off_t magic_offset = 0; + uint32_t zero = 0; + int i; + + if (tdb->transaction == NULL) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\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_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; + } + + 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->num_locks || tdb->global_lock.count) { + tdb->ecode = TDB_ERR_LOCK; + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: locks pending on commit\n")); + tdb_transaction_cancel(tdb); + return -1; + } + + /* upgrade the main transaction lock region to a write lock */ + if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to upgrade hash locks\n")); + tdb->ecode = TDB_ERR_LOCK; + tdb_transaction_cancel(tdb); + return -1; + } + + /* get the global lock - this prevents new users attaching to the database + during the commit */ + if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: failed to get global lock\n")); + tdb->ecode = TDB_ERR_LOCK; + 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, &magic_offset) == -1) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to setup recovery data\n")); + tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); + tdb_transaction_cancel(tdb); + return -1; + } + } + + /* 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_commit: expansion failed\n")); + tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); + tdb_transaction_cancel(tdb); + return -1; + } + tdb->map_size = tdb->transaction->old_map_size; + methods->tdb_oob(tdb, tdb->map_size + 1, 1); + } + + /* perform all the writes */ + for (i=0;itransaction->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_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); + + 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; + + if (!(tdb->flags & TDB_NOSYNC)) { + /* ensure the new data is on disk */ + if (transaction_sync(tdb, 0, tdb->map_size) == -1) { + return -1; + } + + /* remove the recovery marker */ + if (methods->tdb_write(tdb, magic_offset, &zero, 4) == -1) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to remove recovery magic\n")); + return -1; + } + + /* ensure the recovery marker has been removed on disk */ + if (transaction_sync(tdb, magic_offset, 4) == -1) { + return -1; + } + } + + tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 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 + + /* use a transaction cancel to free memory and remove the + transaction locks */ + tdb_transaction_cancel(tdb); + + return 0; +} + + +/* + recover from an aborted transaction. Must be called with exclusive + database write access already established (including the global + 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 list_struct 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 list_struct, 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; + } + + /* reduce the file size to the old size */ + tdb_munmap(tdb); + if (ftruncate(tdb->fd, recovery_eof) != 0) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to reduce to recovery size\n")); + tdb->ecode = TDB_ERR_IO; + return -1; + } + tdb->map_size = recovery_eof; + tdb_mmap(tdb); + + 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; +} diff --git a/tdb/common/traverse.c b/tdb/common/traverse.c new file mode 100644 index 000000000..69c81e6e9 --- /dev/null +++ b/tdb/common/traverse.c @@ -0,0 +1,348 @@ + /* + 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 . +*/ + +#include "tdb_private.h" + +/* Uses traverse lock: 0 = finish, -1 = error, other = record offset */ +static int tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tlock, + struct list_struct *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 -1; + + /* 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" . */ + if (tlock->off == rec->next) { + 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 */ + return TDB_ERRCODE(TDB_SUCCESS, 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 -1; +} + +/* 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 list_struct rec; + int ret, count = 0; + + /* 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 ((ret = tdb_next_lock(tdb, tl, &rec)) > 0) { + 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; + + /* 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 */ + ret = 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); + } +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; + bool in_transaction = (tdb->transaction != NULL); + + /* we need to get a read lock on the transaction lock here to + cope with the lock ordering semantics of solaris10 */ + if (!in_transaction) { + if (tdb_transaction_lock(tdb, F_RDLCK)) { + return -1; + } + } + + tdb->traverse_read++; + ret = tdb_traverse_internal(tdb, fn, private_data, &tl); + tdb->traverse_read--; + + if (!in_transaction) { + tdb_transaction_unlock(tdb); + } + + 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; + bool in_transaction = (tdb->transaction != NULL); + + if (tdb->read_only || tdb->traverse_read) { + return tdb_traverse_read(tdb, fn, private_data); + } + + if (!in_transaction) { + if (tdb_transaction_lock(tdb, F_WRLCK)) { + return -1; + } + } + + tdb->traverse_write++; + ret = tdb_traverse_internal(tdb, fn, private_data, &tl); + tdb->traverse_write--; + + if (!in_transaction) { + tdb_transaction_unlock(tdb); + } + + 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 list_struct rec; + + /* 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. */ + if (tdb_next_lock(tdb, &tdb->travlocks, &rec) <= 0) + 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); + + /* 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 list_struct rec; + unsigned char *k = NULL; + + /* 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) { + 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) + 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 */ + if (tdb_next_lock(tdb, &tdb->travlocks, &rec) > 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")); + return key; +} + diff --git a/tdb/config.guess b/tdb/config.guess new file mode 100755 index 000000000..354dbe175 --- /dev/null +++ b/tdb/config.guess @@ -0,0 +1,1464 @@ +#! /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 Free Software Foundation, Inc. + +timestamp='2005-08-03' + +# 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 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 . +# +# 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 . +# Please send patches to . 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 ." + +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 +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 -q "$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@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 ;; + *) 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 ;; + macppc:MirBSD:*:*) + echo powerppc-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@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 ;; + 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.*:*) + echo i386-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 /* 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 + + 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:*:[45]) + 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 + #include + + 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 + 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:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*: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 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [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:*:*) + 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 | grep ^CPU=` + 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 | grep ^CPU=` + 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 ;; + 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 ;; + x86_64:Linux:*:*) + echo x86_64-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 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + 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 + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + 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' /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 i386. + echo i386-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; } ;; + 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 + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@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 ;; + 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 ;; + 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 + *86) UNAME_PROCESSOR=i686 ;; + 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 ;; +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 < +# include +#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 + 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 +# 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 < 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: diff --git a/tdb/config.mk b/tdb/config.mk new file mode 100644 index 000000000..b9a8f80dd --- /dev/null +++ b/tdb/config.mk @@ -0,0 +1,57 @@ +################################################ +# Start SUBSYSTEM LIBTDB +[LIBRARY::LIBTDB] +OUTPUT_TYPE = STATIC_LIBRARY +CFLAGS = -Ilib/tdb/include +# +# End SUBSYSTEM ldb +################################################ + +LIBTDB_OBJ_FILES = $(addprefix lib/tdb/common/, \ + tdb.o dump.o io.o lock.o \ + open.o traverse.o freelist.o \ + error.o transaction.o) + +################################################ +# Start BINARY tdbtool +[BINARY::tdbtool] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBTDB +# End BINARY tdbtool +################################################ + +tdbtool_OBJ_FILES = lib/tdb/tools/tdbtool.o + +################################################ +# Start BINARY tdbtorture +[BINARY::tdbtorture] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBTDB +# End BINARY tdbtorture +################################################ + +tdbtorture_OBJ_FILES = lib/tdb/tools/tdbtorture.o + +################################################ +# Start BINARY tdbdump +[BINARY::tdbdump] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBTDB +# End BINARY tdbdump +################################################ + +tdbdump_OBJ_FILES = lib/tdb/tools/tdbdump.o + +################################################ +# Start BINARY tdbbackup +[BINARY::tdbbackup] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBTDB +# End BINARY tdbbackup +################################################ + +tdbbackup_OBJ_FILES = lib/tdb/tools/tdbbackup.o diff --git a/tdb/config.sub b/tdb/config.sub new file mode 100755 index 000000000..23cd6fd75 --- /dev/null +++ b/tdb/config.sub @@ -0,0 +1,1577 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-08' + +# 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 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 . +# +# 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 . 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 ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +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-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-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 + ;; + -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/'` + ;; + -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 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + 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) + ;; + + # 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-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | 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[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # 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 + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + 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 + ;; + cr16c) + basic_machine=cr16c-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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + 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 + ;; + 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 + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + 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 + ;; + 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 + ;; + 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[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + 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* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -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* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -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*) + # 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 + ;; + -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 + *-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 + ;; + 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: diff --git a/tdb/configure.ac b/tdb/configure.ac new file mode 100644 index 000000000..5e07b5eb6 --- /dev/null +++ b/tdb/configure.ac @@ -0,0 +1,34 @@ +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.1.2) +AC_CONFIG_SRCDIR([common/tdb.c]) +AC_CONFIG_HEADER(include/config.h) +AC_LIBREPLACE_ALL_CHECKS +AC_LD_SONAMEFLAG +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 + +m4_include(build_macros.m4) +BUILD_WITH_BUILD_INST_DIR + +AC_OUTPUT(Makefile tdb.pc) diff --git a/tdb/docs/README b/tdb/docs/README new file mode 100644 index 000000000..63fcf5e04 --- /dev/null +++ b/tdb/docs/README @@ -0,0 +1,238 @@ +tdb - a trivial database system +tridge@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_CONTEXT *tdb_open_ex(char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode, + tdb_log_func log_fn, + 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 + +---------------------------------------------------------------------- +int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf); + + 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 + +---------------------------------------------------------------------- +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_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. + diff --git a/tdb/docs/tdb.magic b/tdb/docs/tdb.magic new file mode 100644 index 000000000..f5619e732 --- /dev/null +++ b/tdb/docs/tdb.magic @@ -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 diff --git a/tdb/include/tdb.h b/tdb/include/tdb.h new file mode 100644 index 000000000..c41c9941f --- /dev/null +++ b/tdb/include/tdb.h @@ -0,0 +1,168 @@ +#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 . +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "signal.h" + +/* 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_ERRCODE(code, ret) ((tdb->ecode = (code)), ret) + +/* 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}; + +/* 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; +}; + +struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode); +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); +void tdb_set_max_dead(struct tdb_context *tdb, int max_dead); + +int tdb_reopen(struct tdb_context *tdb); +int tdb_reopen_all(int parent_longlived); +void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log_ctx); +enum TDB_ERROR tdb_error(struct tdb_context *tdb); +const char *tdb_errorstr(struct tdb_context *tdb); +TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key); +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); +int tdb_delete(struct tdb_context *tdb, TDB_DATA key); +int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag); +int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf); +int tdb_close(struct tdb_context *tdb); +TDB_DATA tdb_firstkey(struct tdb_context *tdb); +TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA key); +int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *); +int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *); +int tdb_exists(struct tdb_context *tdb, TDB_DATA key); +int tdb_lockall(struct tdb_context *tdb); +int tdb_lockall_nonblock(struct tdb_context *tdb); +int tdb_unlockall(struct tdb_context *tdb); +int tdb_lockall_read(struct tdb_context *tdb); +int tdb_lockall_read_nonblock(struct tdb_context *tdb); +int tdb_unlockall_read(struct tdb_context *tdb); +int tdb_lockall_mark(struct tdb_context *tdb); +int tdb_lockall_unmark(struct tdb_context *tdb); +const char *tdb_name(struct tdb_context *tdb); +int tdb_fd(struct tdb_context *tdb); +tdb_log_func tdb_log_fn(struct tdb_context *tdb); +void *tdb_get_logging_private(struct tdb_context *tdb); +int tdb_transaction_start(struct tdb_context *tdb); +int tdb_transaction_commit(struct tdb_context *tdb); +int tdb_transaction_cancel(struct tdb_context *tdb); +int tdb_transaction_recover(struct tdb_context *tdb); +int tdb_get_seqnum(struct tdb_context *tdb); +int tdb_hash_size(struct tdb_context *tdb); +size_t tdb_map_size(struct tdb_context *tdb); +int tdb_get_flags(struct tdb_context *tdb); +void tdb_add_flags(struct tdb_context *tdb, unsigned flag); +void tdb_remove_flags(struct tdb_context *tdb, unsigned flag); +void tdb_enable_seqnum(struct tdb_context *tdb); +void tdb_increment_seqnum_nonblock(struct tdb_context *tdb); + +/* Low level locking functions: use with care */ +int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key); +int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key); +int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key); +int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key); +int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key); +int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key); +int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key); + +void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr); + +/* Debug functions. Not used in production. */ +void tdb_dump_all(struct tdb_context *tdb); +int tdb_printfreelist(struct tdb_context *tdb); +int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries); +int tdb_wipe_all(struct tdb_context *tdb); +int tdb_freelist_size(struct tdb_context *tdb); + +extern TDB_DATA tdb_null; + +#ifdef __cplusplus +} +#endif + +#endif /* tdb.h */ diff --git a/tdb/install-sh b/tdb/install-sh new file mode 100755 index 000000000..58719246f --- /dev/null +++ b/tdb/install-sh @@ -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 diff --git a/tdb/libtdb.m4 b/tdb/libtdb.m4 new file mode 100644 index 000000000..1e17a7a4f --- /dev/null +++ b/tdb/libtdb.m4 @@ -0,0 +1,30 @@ +dnl find the tdb sources. This is meant to work both for +dnl tdb standalone builds, and builds of packages using tdb +tdbdir="" +tdbpaths="$srcdir $srcdir/lib/tdb $srcdir/tdb $srcdir/../tdb" +for d in $tdbpaths; do + if test -f "$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" +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 ]) +AC_HAVE_DECL(pwrite, [#include ]) diff --git a/tdb/python.mk b/tdb/python.mk new file mode 100644 index 000000000..12e8217df --- /dev/null +++ b/tdb/python.mk @@ -0,0 +1,10 @@ +[PYTHON::swig_tdb] +LIBRARY_REALNAME = _tdb.$(SHLIBEXT) +PUBLIC_DEPENDENCIES = LIBTDB DYNCONFIG + +swig_tdb_OBJ_FILES = $(tdbsrcdir)/tdb_wrap.o + +$(eval $(call python_py_module_template,tdb.py,$(tdbsrcdir)/tdb.py)) + +$(swig_tdb_OBJ_FILES): CFLAGS+=$(CFLAG_NO_UNUSED_MACROS) $(CFLAG_NO_CAST_QUAL) + diff --git a/tdb/python/tdbdump.py b/tdb/python/tdbdump.py new file mode 100644 index 000000000..d759d771c --- /dev/null +++ b/tdb/python/tdbdump.py @@ -0,0 +1,12 @@ +#!/usr/bin/python +# Trivial reimplementation of tdbdump in Python + +import tdb, sys + +if len(sys.argv) < 2: + print "Usage: tdbdump.py " + 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) diff --git a/tdb/python/tests/simple.py b/tdb/python/tests/simple.py new file mode 100644 index 000000000..7147718c9 --- /dev/null +++ b/tdb/python/tests/simple.py @@ -0,0 +1,152 @@ +#!/usr/bin/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 +# 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 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_name(self): + self.tdb.name + + def test_iterator(self): + self.tdb["bla"] = "1" + self.tdb["brainslug"] = "2" + self.assertEquals(["bla", "brainslug"], list(self.tdb)) + + def test_items(self): + self.tdb["bla"] = "1" + self.tdb["brainslug"] = "2" + self.assertEquals([("bla", "1"), ("brainslug", "2")], self.tdb.items()) + + def test_iteritems(self): + self.tdb["bloe"] = "2" + self.tdb["bla"] = "25" + i = self.tdb.iteritems() + self.assertEquals(set([("bla", "25"), ("bloe", "2")]), + set([i.next(), i.next()])) + + 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_iterator(self): + self.tdb["bloe"] = "2" + self.tdb["bla"] = "hoi" + i = iter(self.tdb) + self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()])) + + def test_keys(self): + self.tdb["bloe"] = "2" + self.tdb["bla"] = "25" + self.assertEquals(["bla", "bloe"], self.tdb.keys()) + + 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_values(self): + self.tdb["bloe"] = "2" + self.tdb["bla"] = "25" + self.assertEquals(["25", "2"], self.tdb.values()) + + def test_itervalues(self): + self.tdb["bloe"] = "2" + self.tdb["bla"] = "25" + i = self.tdb.itervalues() + self.assertEquals(set(["25", "2"]), set([i.next(), i.next()])) + + def test_clear(self): + self.tdb["bloe"] = "2" + self.tdb["bla"] = "25" + self.assertEquals(2, len(self.tdb)) + self.tdb.clear() + self.assertEquals(0, len(self.tdb)) + + def test_len(self): + self.assertEquals(0, len(self.tdb)) + self.tdb["entry"] = "value" + self.assertEquals(1, len(self.tdb)) + + +if __name__ == '__main__': + import unittest + unittest.TestProgram() diff --git a/tdb/rules.mk b/tdb/rules.mk new file mode 100644 index 000000000..7b765625d --- /dev/null +++ b/tdb/rules.mk @@ -0,0 +1,21 @@ +.SUFFIXES: .i _wrap.c + +.i_wrap.c: + $(SWIG) -O -Wall -python -keyword $< + +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) -c $< -o $@ + +distclean:: + rm -f *~ */*~ diff --git a/tdb/tdb.i b/tdb/tdb.i new file mode 100644 index 000000000..3d8b69773 --- /dev/null +++ b/tdb/tdb.i @@ -0,0 +1,323 @@ +/* + Unix SMB/CIFS implementation. + + Swig interface to tdb. + + Copyright (C) 2004-2006 Tim Potter + Copyright (C) 2007 Jelmer Vernooij + + ** 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 . +*/ + +%define DOCSTRING +"TDB is a simple key-value database similar to GDBM that supports multiple writers." +%enddef + +%module(docstring=DOCSTRING) tdb + +%{ + +/* This symbol is used in both includes.h and Python.h which causes an + annoying compiler warning. */ + +#ifdef HAVE_FSTAT +#undef HAVE_FSTAT +#endif + +/* Include tdb headers */ +#include +#include +#include +#include + +typedef TDB_CONTEXT tdb; +%} + +/* The tdb functions will crash if a NULL tdb context is passed */ + +%import exception.i +%import stdint.i + +%typemap(check,noblock=1) TDB_CONTEXT* { + if ($1 == NULL) + SWIG_exception(SWIG_ValueError, + "tdb context must be non-NULL"); +} + +/* In and out typemaps for the TDB_DATA structure. This is converted to + and from the Python string type which can contain arbitrary binary + data.. */ + +%typemap(in,noblock=1) TDB_DATA { + if ($input == Py_None) { + $1.dsize = 0; + $1.dptr = NULL; + } else if (!PyString_Check($input)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + $1.dsize = PyString_Size($input); + $1.dptr = (uint8_t *)PyString_AsString($input); + } +} + +%typemap(out,noblock=1) TDB_DATA { + if ($1.dptr == NULL && $1.dsize == 0) { + $result = Py_None; + } else { + $result = PyString_FromStringAndSize((const char *)$1.dptr, $1.dsize); + free($1.dptr); + } +} + +/* Treat a mode_t as an unsigned integer */ +typedef int mode_t; + +/* flags to tdb_store() */ +%constant int REPLACE = TDB_REPLACE; +%constant int INSERT = TDB_INSERT; +%constant int MODIFY = TDB_MODIFY; + +/* flags for tdb_open() */ +%constant int DEFAULT = TDB_DEFAULT; +%constant int CLEAR_IF_FIRST = TDB_CLEAR_IF_FIRST; +%constant int INTERNAL = TDB_INTERNAL; +%constant int NOLOCK = TDB_NOLOCK; +%constant int NOMMAP = TDB_NOMMAP; +%constant int CONVERT = TDB_CONVERT; +%constant int BIGENDIAN = TDB_BIGENDIAN; + +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 +}; + +%rename(lock_all) tdb_context::lockall; +%rename(unlock_all) tdb_context::unlockall; + +%rename(read_lock_all) tdb_context::lockall_read; +%rename(read_unlock_all) tdb_context::unlockall_read; + +%typemap(default,noblock=1) int tdb_flags { + $1 = TDB_DEFAULT; +} + +%typemap(default,noblock=1) int flags { + $1 = O_RDWR; +} + +%typemap(default,noblock=1) int hash_size { + $1 = 0; +} + +%typemap(default,noblock=1) mode_t mode { + $1 = 0600; +} + +%typemap(default,noblock=1) int flag { + $1 = TDB_REPLACE; +} + +%rename(Tdb) tdb_context; +%feature("docstring") tdb_context "A TDB file."; +%typemap(out,noblock=1) tdb * { + /* Throw an IOError exception from errno if tdb_open() returns NULL */ + if ($1 == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + SWIG_fail; + } + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); +} + +typedef struct tdb_context { + %extend { + %feature("docstring") tdb "S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600)\n" + "Open a TDB file."; + tdb(const char *name, int hash_size, int tdb_flags, int flags, mode_t mode) { + return tdb_open(name, hash_size, tdb_flags, flags, mode); + } + %feature("docstring") error "S.error() -> int\n" + "Find last error number returned by operation on this TDB."; + enum TDB_ERROR error(); + ~tdb() { tdb_close($self); } + %feature("docstring") close "S.close() -> None\n" + "Close the TDB file."; + int close(); + int append(TDB_DATA key, TDB_DATA new_dbuf); + %feature("docstring") errorstr "S.errorstr() -> errorstring\n" + "Obtain last error message."; + const char *errorstr(); + %rename(get) fetch; + %feature("docstring") fetch "S.fetch(key) -> value\n" + "Fetch a value."; + TDB_DATA fetch(TDB_DATA key); + %feature("docstring") delete "S.delete(key) -> None\n" + "Delete an entry."; + int delete(TDB_DATA key); + %feature("docstring") store "S.store(key, value, flag=TDB_REPLACE) -> None\n" + "Store an entry."; + int store(TDB_DATA key, TDB_DATA dbuf, int flag); + %feature("docstring") exists "S.exists(key) -> bool\n" + "Check whether key exists in this database."; + int exists(TDB_DATA key); + %feature("docstring") firstkey "S.firstkey() -> data\n" + "Return the first key in this database."; + TDB_DATA firstkey(); + %feature("docstring") nextkey "S.nextkey(prev) -> data\n" + "Return the next key in this database."; + TDB_DATA nextkey(TDB_DATA key); + %feature("docstring") lockall "S.lockall() -> bool"; + int lockall(); + %feature("docstring") unlockall "S.unlockall() -> bool"; + int unlockall(); + %feature("docstring") unlockall "S.lockall_read() -> bool"; + int lockall_read(); + %feature("docstring") unlockall "S.unlockall_read() -> bool"; + int unlockall_read(); + %feature("docstring") reopen "S.reopen() -> bool\n" + "Reopen this file."; + int reopen(); + %feature("docstring") transaction_start "S.transaction_start() -> None\n" + "Start a new transaction."; + int transaction_start(); + %feature("docstring") transaction_commit "S.transaction_commit() -> None\n" + "Commit the currently active transaction."; + int transaction_commit(); + %feature("docstring") transaction_cancel "S.transaction_cancel() -> None\n" + "Cancel the currently active transaction."; + int transaction_cancel(); + int transaction_recover(); + %feature("docstring") hash_size "S.hash_size() -> int"; + int hash_size(); + %feature("docstring") map_size "S.map_size() -> int"; + size_t map_size(); + %feature("docstring") get_flags "S.get_flags() -> int"; + int get_flags(); + %feature("docstring") set_max_dead "S.set_max_dead(int) -> None"; + void set_max_dead(int max_dead); + %feature("docstring") name "S.name() -> path\n" \ + "Return filename of this TDB file."; + const char *name(); + } + + %pythoncode { + def __repr__(self): + return "Tdb('%s')" % self.name() + + # Random access to keys, values + def __getitem__(self, key): + result = self.get(key) + if result is None: + raise KeyError, '%s: %s' % (key, self.errorstr()) + return result + + def __setitem__(self, key, item): + if self.store(key, item) == -1: + raise IOError, self.errorstr() + + def __delitem__(self, key): + if not self.exists(key): + raise KeyError, '%s: %s' % (key, self.errorstr()) + self.delete(key) + + def __contains__(self, key): + return self.exists(key) != 0 + + def has_key(self, key): + return self.exists(key) != 0 + + def fetch_uint32(self, key): + data = self.get(key) + if data is None: + return None + import struct + return struct.unpack("" % (self.__class__.__module__, self.__class__.__name__, strthis,) + +import types +try: + _object = types.ObjectType + _newclass = 1 +except AttributeError: + class _object : pass + _newclass = 0 +del types + + +def _swig_setattr_nondynamic_method(set): + def set_attr(self,name,value): + if (name == "thisown"): return self.this.own(value) + if hasattr(self,name) or (name == "this"): + set(self,name,value) + else: + raise AttributeError("You cannot add attributes to %s" % self) + return set_attr + + +REPLACE = _tdb.REPLACE +INSERT = _tdb.INSERT +MODIFY = _tdb.MODIFY +DEFAULT = _tdb.DEFAULT +CLEAR_IF_FIRST = _tdb.CLEAR_IF_FIRST +INTERNAL = _tdb.INTERNAL +NOLOCK = _tdb.NOLOCK +NOMMAP = _tdb.NOMMAP +CONVERT = _tdb.CONVERT +BIGENDIAN = _tdb.BIGENDIAN +TDB_SUCCESS = _tdb.TDB_SUCCESS +TDB_ERR_CORRUPT = _tdb.TDB_ERR_CORRUPT +TDB_ERR_IO = _tdb.TDB_ERR_IO +TDB_ERR_LOCK = _tdb.TDB_ERR_LOCK +TDB_ERR_OOM = _tdb.TDB_ERR_OOM +TDB_ERR_EXISTS = _tdb.TDB_ERR_EXISTS +TDB_ERR_NOLOCK = _tdb.TDB_ERR_NOLOCK +TDB_ERR_LOCK_TIMEOUT = _tdb.TDB_ERR_LOCK_TIMEOUT +TDB_ERR_NOEXIST = _tdb.TDB_ERR_NOEXIST +TDB_ERR_EINVAL = _tdb.TDB_ERR_EINVAL +TDB_ERR_RDONLY = _tdb.TDB_ERR_RDONLY +class Tdb(object): + """A TDB file.""" + thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') + __repr__ = _swig_repr + def __init__(self, *args, **kwargs): + """ + S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600) + Open a TDB file. + """ + _tdb.Tdb_swiginit(self,_tdb.new_Tdb(*args, **kwargs)) + def error(*args, **kwargs): + """ + S.error() -> int + Find last error number returned by operation on this TDB. + """ + return _tdb.Tdb_error(*args, **kwargs) + + __swig_destroy__ = _tdb.delete_Tdb + def close(*args, **kwargs): + """ + S.close() -> None + Close the TDB file. + """ + return _tdb.Tdb_close(*args, **kwargs) + + def errorstr(*args, **kwargs): + """ + S.errorstr() -> errorstring + Obtain last error message. + """ + return _tdb.Tdb_errorstr(*args, **kwargs) + + def get(*args, **kwargs): + """ + S.fetch(key) -> value + Fetch a value. + """ + return _tdb.Tdb_get(*args, **kwargs) + + def delete(*args, **kwargs): + """ + S.delete(key) -> None + Delete an entry. + """ + return _tdb.Tdb_delete(*args, **kwargs) + + def store(*args, **kwargs): + """ + S.store(key, value, flag=TDB_REPLACE) -> None + Store an entry. + """ + return _tdb.Tdb_store(*args, **kwargs) + + def exists(*args, **kwargs): + """ + S.exists(key) -> bool + Check whether key exists in this database. + """ + return _tdb.Tdb_exists(*args, **kwargs) + + def firstkey(*args, **kwargs): + """ + S.firstkey() -> data + Return the first key in this database. + """ + return _tdb.Tdb_firstkey(*args, **kwargs) + + def nextkey(*args, **kwargs): + """ + S.nextkey(prev) -> data + Return the next key in this database. + """ + return _tdb.Tdb_nextkey(*args, **kwargs) + + def lock_all(*args, **kwargs): + """S.lockall() -> bool""" + return _tdb.Tdb_lock_all(*args, **kwargs) + + def unlock_all(*args, **kwargs): + """S.unlockall() -> bool""" + return _tdb.Tdb_unlock_all(*args, **kwargs) + + def reopen(*args, **kwargs): + """ + S.reopen() -> bool + Reopen this file. + """ + return _tdb.Tdb_reopen(*args, **kwargs) + + def transaction_start(*args, **kwargs): + """ + S.transaction_start() -> None + Start a new transaction. + """ + return _tdb.Tdb_transaction_start(*args, **kwargs) + + def transaction_commit(*args, **kwargs): + """ + S.transaction_commit() -> None + Commit the currently active transaction. + """ + return _tdb.Tdb_transaction_commit(*args, **kwargs) + + def transaction_cancel(*args, **kwargs): + """ + S.transaction_cancel() -> None + Cancel the currently active transaction. + """ + return _tdb.Tdb_transaction_cancel(*args, **kwargs) + + def hash_size(*args, **kwargs): + """S.hash_size() -> int""" + return _tdb.Tdb_hash_size(*args, **kwargs) + + def map_size(*args, **kwargs): + """S.map_size() -> int""" + return _tdb.Tdb_map_size(*args, **kwargs) + + def get_flags(*args, **kwargs): + """S.get_flags() -> int""" + return _tdb.Tdb_get_flags(*args, **kwargs) + + def set_max_dead(*args, **kwargs): + """S.set_max_dead(int) -> None""" + return _tdb.Tdb_set_max_dead(*args, **kwargs) + + def name(*args, **kwargs): + """ + S.name() -> path + Return filename of this TDB file. + """ + return _tdb.Tdb_name(*args, **kwargs) + + def __repr__(self): + return "Tdb('%s')" % self.name() + + + def __getitem__(self, key): + result = self.get(key) + if result is None: + raise KeyError, '%s: %s' % (key, self.errorstr()) + return result + + def __setitem__(self, key, item): + if self.store(key, item) == -1: + raise IOError, self.errorstr() + + def __delitem__(self, key): + if not self.exists(key): + raise KeyError, '%s: %s' % (key, self.errorstr()) + self.delete(key) + + def __contains__(self, key): + return self.exists(key) != 0 + + def has_key(self, key): + return self.exists(key) != 0 + + def fetch_uint32(self, key): + data = self.get(key) + if data is None: + return None + import struct + return struct.unpack(" 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + + + +/* Python.h has to appear first */ +#include + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The swig conversion methods, as ConvertPtr, return and integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old swig versions, you usually write code as: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit as: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + that seems to be the same, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + requires also to SWIG_ConvertPtr to return new result values, as + + int SWIG_ConvertPtr(obj, ptr,...) { + if () { + if () { + *ptr = ; + return SWIG_NEWOBJ; + } else { + *ptr = ; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + swig errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() + + + */ +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class" == "Class", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like ||... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like ||... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCompare(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + + +/* think of this as a c++ template<> or a scheme macro */ +#define SWIG_TypeCheck_Template(comparison, ty) \ + if (ty) { \ + swig_cast_info *iter = ty->cast; \ + while (iter) { \ + if (comparison) { \ + if (iter == ty->cast) return iter; \ + /* Move iter to the top of the linked list */ \ + iter->prev->next = iter->next; \ + if (iter->next) \ + iter->next->prev = iter->prev; \ + iter->next = ty->cast; \ + iter->prev = 0; \ + if (ty->cast) ty->cast->prev = iter; \ + ty->cast = iter; \ + return iter; \ + } \ + iter = iter->next; \ + } \ + } \ + return 0 + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty); +} + +/* Same as previous function, except strcmp is replaced with a pointer comparison */ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) { + SWIG_TypeCheck_Template(iter->type == from, into); +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + + +/* Add PyOS_snprintf for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# define PyOS_snprintf _snprintf +# else +# define PyOS_snprintf snprintf +# endif +#endif + +/* A crude PyString_FromFormat implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 + +#ifndef SWIG_PYBUFFER_SIZE +# define SWIG_PYBUFFER_SIZE 1024 +#endif + +static PyObject * +PyString_FromFormat(const char *fmt, ...) { + va_list ap; + char buf[SWIG_PYBUFFER_SIZE * 2]; + int res; + va_start(ap, fmt); + res = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); +} +#endif + +/* Add PyObject_Del for old Pythons */ +#if PY_VERSION_HEX < 0x01060000 +# define PyObject_Del(op) PyMem_DEL((op)) +#endif +#ifndef PyObject_DEL +# define PyObject_DEL PyObject_Del +#endif + +/* A crude PyExc_StopIteration exception for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# ifndef PyExc_StopIteration +# define PyExc_StopIteration PyExc_RuntimeError +# endif +# ifndef PyObject_GenericGetAttr +# define PyObject_GenericGetAttr 0 +# endif +#endif +/* Py_NotImplemented is defined in 2.1 and up. */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef Py_NotImplemented +# define Py_NotImplemented PyExc_RuntimeError +# endif +#endif + + +/* A crude PyString_AsStringAndSize implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef PyString_AsStringAndSize +# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} +# endif +#endif + +/* PySequence_Size for old Pythons */ +#if PY_VERSION_HEX < 0x02000000 +# ifndef PySequence_Size +# define PySequence_Size PySequence_Length +# endif +#endif + + +/* PyBool_FromLong for old Pythons */ +#if PY_VERSION_HEX < 0x02030000 +static +PyObject *PyBool_FromLong(long ok) +{ + PyObject *result = ok ? Py_True : Py_False; + Py_INCREF(result); + return result; +} +#endif + +/* Py_ssize_t for old Pythons */ +/* This code is as recommended by: */ +/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +#endif + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIME PyObject* +SWIG_Python_ErrorType(int code) { + PyObject* type = 0; + switch(code) { + case SWIG_MemoryError: + type = PyExc_MemoryError; + break; + case SWIG_IOError: + type = PyExc_IOError; + break; + case SWIG_RuntimeError: + type = PyExc_RuntimeError; + break; + case SWIG_IndexError: + type = PyExc_IndexError; + break; + case SWIG_TypeError: + type = PyExc_TypeError; + break; + case SWIG_DivisionByZero: + type = PyExc_ZeroDivisionError; + break; + case SWIG_OverflowError: + type = PyExc_OverflowError; + break; + case SWIG_SyntaxError: + type = PyExc_SyntaxError; + break; + case SWIG_ValueError: + type = PyExc_ValueError; + break; + case SWIG_SystemError: + type = PyExc_SystemError; + break; + case SWIG_AttributeError: + type = PyExc_AttributeError; + break; + default: + type = PyExc_RuntimeError; + } + return type; +} + + +SWIGRUNTIME void +SWIG_Python_AddErrorMsg(const char* mesg) +{ + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + + if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + PyErr_Clear(); + Py_XINCREF(type); + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + Py_DECREF(old_str); + Py_DECREF(value); + } else { + PyErr_SetString(PyExc_RuntimeError, mesg); + } +} + + + +#if defined(SWIG_PYTHON_NO_THREADS) +# if defined(SWIG_PYTHON_THREADS) +# undef SWIG_PYTHON_THREADS +# endif +#endif +#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ +# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) +# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ +# define SWIG_PYTHON_USE_GIL +# endif +# endif +# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ +# ifndef SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() +# endif +# ifdef __cplusplus /* C++ code */ + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + public: + void end() { if (status) { PyEval_RestoreThread(save); status = false; }} + SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} + ~SWIG_Python_Thread_Allow() { end(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow +# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() +# else /* C code */ +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() +# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() +# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) +# define SWIG_PYTHON_INITIALIZE_THREADS +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif + +/* ----------------------------------------------------------------------------- + * Python API portion that goes into the runtime + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_PY_POINTER 4 +#define SWIG_PY_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * pyrun.swg + * + * This file contains the runtime support for Python modules + * and includes code for managing global variables and pointer + * type checking. + * + * ----------------------------------------------------------------------------- */ + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) +#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) +#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(ptr, type, flags) +#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) +#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) +#define swig_owntype int + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Python_GetModule() +#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) +#define SWIG_NewClientData(obj) PySwigClientData_New(obj) + +#define SWIG_SetErrorObj SWIG_Python_SetErrorObj +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Runtime API implementation */ + +/* Error manipulation */ + +SWIGINTERN void +SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetObject(errtype, obj); + Py_DECREF(obj); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +SWIGINTERN void +SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(errtype, (char *) msg); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) + +/* Set a constant value */ + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { + PyDict_SetItemString(d, (char*) name, obj); + Py_DECREF(obj); +} + +/* Append a value to the result obj */ + +SWIGINTERN PyObject* +SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { +#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyList_Check(result)) { + PyObject *o2 = result; + result = PyList_New(1); + PyList_SetItem(result, 0, o2); + } + PyList_Append(result,obj); + Py_DECREF(obj); + } + return result; +#else + PyObject* o2; + PyObject* o3; + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyTuple_Check(result)) { + o2 = result; + result = PyTuple_New(1); + PyTuple_SET_ITEM(result, 0, o2); + } + o3 = PyTuple_New(1); + PyTuple_SET_ITEM(o3, 0, obj); + o2 = result; + result = PySequence_Concat(o2, o3); + Py_DECREF(o2); + Py_DECREF(o3); + } + return result; +#endif +} + +/* Unpack the argument tuple */ + +SWIGINTERN int +SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) +{ + if (!args) { + if (!min && !max) { + return 1; + } else { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", + name, (min == max ? "" : "at least "), (int)min); + return 0; + } + } + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); + return 0; + } else { + register Py_ssize_t l = PyTuple_GET_SIZE(args); + if (l < min) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at least "), (int)min, (int)l); + return 0; + } else if (l > max) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at most "), (int)max, (int)l); + return 0; + } else { + register int i; + for (i = 0; i < l; ++i) { + objs[i] = PyTuple_GET_ITEM(args, i); + } + for (; l < max; ++l) { + objs[l] = 0; + } + return i + 1; + } + } +} + +/* A functor is a function object with one single object argument */ +#if PY_VERSION_HEX >= 0x02020000 +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); +#else +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); +#endif + +/* + Helper for static pointer initialization for both C and C++ code, for example + static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); +*/ +#ifdef __cplusplus +#define SWIG_STATIC_POINTER(var) var +#else +#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var +#endif + +/* ----------------------------------------------------------------------------- + * Pointer declarations + * ----------------------------------------------------------------------------- */ + +/* Flags for new pointer objects */ +#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) +#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) + +#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* How to access Py_None */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# ifndef SWIG_PYTHON_NO_BUILD_NONE +# ifndef SWIG_PYTHON_BUILD_NONE +# define SWIG_PYTHON_BUILD_NONE +# endif +# endif +#endif + +#ifdef SWIG_PYTHON_BUILD_NONE +# ifdef Py_None +# undef Py_None +# define Py_None SWIG_Py_None() +# endif +SWIGRUNTIMEINLINE PyObject * +_SWIG_Py_None(void) +{ + PyObject *none = Py_BuildValue((char*)""); + Py_DECREF(none); + return none; +} +SWIGRUNTIME PyObject * +SWIG_Py_None(void) +{ + static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); + return none; +} +#endif + +/* The python void return value */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Py_Void(void) +{ + PyObject *none = Py_None; + Py_INCREF(none); + return none; +} + +/* PySwigClientData */ + +typedef struct { + PyObject *klass; + PyObject *newraw; + PyObject *newargs; + PyObject *destroy; + int delargs; + int implicitconv; +} PySwigClientData; + +SWIGRUNTIMEINLINE int +SWIG_Python_CheckImplicit(swig_type_info *ty) +{ + PySwigClientData *data = (PySwigClientData *)ty->clientdata; + return data ? data->implicitconv : 0; +} + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_ExceptionType(swig_type_info *desc) { + PySwigClientData *data = desc ? (PySwigClientData *) desc->clientdata : 0; + PyObject *klass = data ? data->klass : 0; + return (klass ? klass : PyExc_RuntimeError); +} + + +SWIGRUNTIME PySwigClientData * +PySwigClientData_New(PyObject* obj) +{ + if (!obj) { + return 0; + } else { + PySwigClientData *data = (PySwigClientData *)malloc(sizeof(PySwigClientData)); + /* the klass element */ + data->klass = obj; + Py_INCREF(data->klass); + /* the newraw method and newargs arguments used to create a new raw instance */ + if (PyClass_Check(obj)) { + data->newraw = 0; + data->newargs = obj; + Py_INCREF(obj); + } else { +#if (PY_VERSION_HEX < 0x02020000) + data->newraw = 0; +#else + data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); +#endif + if (data->newraw) { + Py_INCREF(data->newraw); + data->newargs = PyTuple_New(1); + PyTuple_SetItem(data->newargs, 0, obj); + } else { + data->newargs = obj; + } + Py_INCREF(data->newargs); + } + /* the destroy method, aka as the C++ delete method */ + data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); + if (PyErr_Occurred()) { + PyErr_Clear(); + data->destroy = 0; + } + if (data->destroy) { + int flags; + Py_INCREF(data->destroy); + flags = PyCFunction_GET_FLAGS(data->destroy); +#ifdef METH_O + data->delargs = !(flags & (METH_O)); +#else + data->delargs = 0; +#endif + } else { + data->delargs = 0; + } + data->implicitconv = 0; + return data; + } +} + +SWIGRUNTIME void +PySwigClientData_Del(PySwigClientData* data) +{ + Py_XDECREF(data->newraw); + Py_XDECREF(data->newargs); + Py_XDECREF(data->destroy); +} + +/* =============== PySwigObject =====================*/ + +typedef struct { + PyObject_HEAD + void *ptr; + swig_type_info *ty; + int own; + PyObject *next; +} PySwigObject; + +SWIGRUNTIME PyObject * +PySwigObject_long(PySwigObject *v) +{ + return PyLong_FromVoidPtr(v->ptr); +} + +SWIGRUNTIME PyObject * +PySwigObject_format(const char* fmt, PySwigObject *v) +{ + PyObject *res = NULL; + PyObject *args = PyTuple_New(1); + if (args) { + if (PyTuple_SetItem(args, 0, PySwigObject_long(v)) == 0) { + PyObject *ofmt = PyString_FromString(fmt); + if (ofmt) { + res = PyString_Format(ofmt,args); + Py_DECREF(ofmt); + } + Py_DECREF(args); + } + } + return res; +} + +SWIGRUNTIME PyObject * +PySwigObject_oct(PySwigObject *v) +{ + return PySwigObject_format("%o",v); +} + +SWIGRUNTIME PyObject * +PySwigObject_hex(PySwigObject *v) +{ + return PySwigObject_format("%x",v); +} + +SWIGRUNTIME PyObject * +#ifdef METH_NOARGS +PySwigObject_repr(PySwigObject *v) +#else +PySwigObject_repr(PySwigObject *v, PyObject *args) +#endif +{ + const char *name = SWIG_TypePrettyName(v->ty); + PyObject *hex = PySwigObject_hex(v); + PyObject *repr = PyString_FromFormat("", name, PyString_AsString(hex)); + Py_DECREF(hex); + if (v->next) { +#ifdef METH_NOARGS + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next); +#else + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next, args); +#endif + PyString_ConcatAndDel(&repr,nrep); + } + return repr; +} + +SWIGRUNTIME int +PySwigObject_print(PySwigObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ +#ifdef METH_NOARGS + PyObject *repr = PySwigObject_repr(v); +#else + PyObject *repr = PySwigObject_repr(v, NULL); +#endif + if (repr) { + fputs(PyString_AsString(repr), fp); + Py_DECREF(repr); + return 0; + } else { + return 1; + } +} + +SWIGRUNTIME PyObject * +PySwigObject_str(PySwigObject *v) +{ + char result[SWIG_BUFFER_SIZE]; + return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ? + PyString_FromString(result) : 0; +} + +SWIGRUNTIME int +PySwigObject_compare(PySwigObject *v, PySwigObject *w) +{ + void *i = v->ptr; + void *j = w->ptr; + return (i < j) ? -1 : ((i > j) ? 1 : 0); +} + +SWIGRUNTIME PyTypeObject* _PySwigObject_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigObject_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigObject_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigObject_Check(PyObject *op) { + return ((op)->ob_type == PySwigObject_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigObject") == 0); +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own); + +SWIGRUNTIME void +PySwigObject_dealloc(PyObject *v) +{ + PySwigObject *sobj = (PySwigObject *) v; + PyObject *next = sobj->next; + if (sobj->own == SWIG_POINTER_OWN) { + swig_type_info *ty = sobj->ty; + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + PyObject *destroy = data ? data->destroy : 0; + if (destroy) { + /* destroy is always a VARARGS method */ + PyObject *res; + if (data->delargs) { + /* we need to create a temporal object to carry the destroy operation */ + PyObject *tmp = PySwigObject_New(sobj->ptr, ty, 0); + res = SWIG_Python_CallFunctor(destroy, tmp); + Py_DECREF(tmp); + } else { + PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); + PyObject *mself = PyCFunction_GET_SELF(destroy); + res = ((*meth)(mself, v)); + } + Py_XDECREF(res); + } +#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) + else { + const char *name = SWIG_TypePrettyName(ty); + printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); + } +#endif + } + Py_XDECREF(next); + PyObject_DEL(v); +} + +SWIGRUNTIME PyObject* +PySwigObject_append(PyObject* v, PyObject* next) +{ + PySwigObject *sobj = (PySwigObject *) v; +#ifndef METH_O + PyObject *tmp = 0; + if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; + next = tmp; +#endif + if (!PySwigObject_Check(next)) { + return NULL; + } + sobj->next = next; + Py_INCREF(next); + return SWIG_Py_Void(); +} + +SWIGRUNTIME PyObject* +#ifdef METH_NOARGS +PySwigObject_next(PyObject* v) +#else +PySwigObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *) v; + if (sobj->next) { + Py_INCREF(sobj->next); + return sobj->next; + } else { + return SWIG_Py_Void(); + } +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_disown(PyObject *v) +#else +PySwigObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = 0; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_acquire(PyObject *v) +#else +PySwigObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = SWIG_POINTER_OWN; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +PySwigObject_own(PyObject *v, PyObject *args) +{ + PyObject *val = 0; +#if (PY_VERSION_HEX < 0x02020000) + if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) +#else + if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) +#endif + { + return NULL; + } + else + { + PySwigObject *sobj = (PySwigObject *)v; + PyObject *obj = PyBool_FromLong(sobj->own); + if (val) { +#ifdef METH_NOARGS + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v); + } else { + PySwigObject_disown(v); + } +#else + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v,args); + } else { + PySwigObject_disown(v,args); + } +#endif + } + return obj; + } +} + +#ifdef METH_O +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_NOARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_O, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_NOARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#else +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_VARARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_VARARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#endif + +#if PY_VERSION_HEX < 0x02020000 +SWIGINTERN PyObject * +PySwigObject_getattr(PySwigObject *sobj,char *name) +{ + return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); +} +#endif + +SWIGRUNTIME PyTypeObject* +_PySwigObject_type(void) { + static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; + + static PyNumberMethods PySwigObject_as_number = { + (binaryfunc)0, /*nb_add*/ + (binaryfunc)0, /*nb_subtract*/ + (binaryfunc)0, /*nb_multiply*/ + (binaryfunc)0, /*nb_divide*/ + (binaryfunc)0, /*nb_remainder*/ + (binaryfunc)0, /*nb_divmod*/ + (ternaryfunc)0,/*nb_power*/ + (unaryfunc)0, /*nb_negative*/ + (unaryfunc)0, /*nb_positive*/ + (unaryfunc)0, /*nb_absolute*/ + (inquiry)0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + (coercion)0, /*nb_coerce*/ + (unaryfunc)PySwigObject_long, /*nb_int*/ + (unaryfunc)PySwigObject_long, /*nb_long*/ + (unaryfunc)0, /*nb_float*/ + (unaryfunc)PySwigObject_oct, /*nb_oct*/ + (unaryfunc)PySwigObject_hex, /*nb_hex*/ +#if PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ +#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ +#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ + 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ +#endif + }; + + static PyTypeObject pyswigobject_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigObject", /* tp_name */ + sizeof(PySwigObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigObject_dealloc, /* tp_dealloc */ + (printfunc)PySwigObject_print, /* tp_print */ +#if PY_VERSION_HEX < 0x02020000 + (getattrfunc)PySwigObject_getattr, /* tp_getattr */ +#else + (getattrfunc)0, /* tp_getattr */ +#endif + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigObject_compare, /* tp_compare */ + (reprfunc)PySwigObject_repr, /* tp_repr */ + &PySwigObject_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigObject_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigobject_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + swigobject_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigobject_type = tmp; + pyswigobject_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigobject_type; +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own) +{ + PySwigObject *sobj = PyObject_NEW(PySwigObject, PySwigObject_type()); + if (sobj) { + sobj->ptr = ptr; + sobj->ty = ty; + sobj->own = own; + sobj->next = 0; + } + return (PyObject *)sobj; +} + +/* ----------------------------------------------------------------------------- + * Implements a simple Swig Packed type, and use it instead of string + * ----------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + void *pack; + swig_type_info *ty; + size_t size; +} PySwigPacked; + +SWIGRUNTIME int +PySwigPacked_print(PySwigPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char result[SWIG_BUFFER_SIZE]; + fputs("pack, v->size, 0, sizeof(result))) { + fputs("at ", fp); + fputs(result, fp); + } + fputs(v->ty->name,fp); + fputs(">", fp); + return 0; +} + +SWIGRUNTIME PyObject * +PySwigPacked_repr(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + return PyString_FromFormat("", result, v->ty->name); + } else { + return PyString_FromFormat("", v->ty->name); + } +} + +SWIGRUNTIME PyObject * +PySwigPacked_str(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ + return PyString_FromFormat("%s%s", result, v->ty->name); + } else { + return PyString_FromString(v->ty->name); + } +} + +SWIGRUNTIME int +PySwigPacked_compare(PySwigPacked *v, PySwigPacked *w) +{ + size_t i = v->size; + size_t j = w->size; + int s = (i < j) ? -1 : ((i > j) ? 1 : 0); + return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); +} + +SWIGRUNTIME PyTypeObject* _PySwigPacked_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigPacked_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigPacked_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigPacked_Check(PyObject *op) { + return ((op)->ob_type == _PySwigPacked_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigPacked") == 0); +} + +SWIGRUNTIME void +PySwigPacked_dealloc(PyObject *v) +{ + if (PySwigPacked_Check(v)) { + PySwigPacked *sobj = (PySwigPacked *) v; + free(sobj->pack); + } + PyObject_DEL(v); +} + +SWIGRUNTIME PyTypeObject* +_PySwigPacked_type(void) { + static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; + static PyTypeObject pyswigpacked_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigPacked", /* tp_name */ + sizeof(PySwigPacked), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigPacked_dealloc, /* tp_dealloc */ + (printfunc)PySwigPacked_print, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigPacked_compare, /* tp_compare */ + (reprfunc)PySwigPacked_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigPacked_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigpacked_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigpacked_type = tmp; + pyswigpacked_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigpacked_type; +} + +SWIGRUNTIME PyObject * +PySwigPacked_New(void *ptr, size_t size, swig_type_info *ty) +{ + PySwigPacked *sobj = PyObject_NEW(PySwigPacked, PySwigPacked_type()); + if (sobj) { + void *pack = malloc(size); + if (pack) { + memcpy(pack, ptr, size); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = size; + } else { + PyObject_DEL((PyObject *) sobj); + sobj = 0; + } + } + return (PyObject *) sobj; +} + +SWIGRUNTIME swig_type_info * +PySwigPacked_UnpackData(PyObject *obj, void *ptr, size_t size) +{ + if (PySwigPacked_Check(obj)) { + PySwigPacked *sobj = (PySwigPacked *)obj; + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIMEINLINE PyObject * +_SWIG_This(void) +{ + return PyString_FromString("this"); +} + +SWIGRUNTIME PyObject * +SWIG_This(void) +{ + static PyObject *SWIG_STATIC_POINTER(swig_this) = _SWIG_This(); + return swig_this; +} + +/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ + +SWIGRUNTIME PySwigObject * +SWIG_Python_GetSwigThis(PyObject *pyobj) +{ + if (PySwigObject_Check(pyobj)) { + return (PySwigObject *) pyobj; + } else { + PyObject *obj = 0; +#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) + if (PyInstance_Check(pyobj)) { + obj = _PyInstance_Lookup(pyobj, SWIG_This()); + } else { + PyObject **dictptr = _PyObject_GetDictPtr(pyobj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; + } else { +#ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); + return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; + } +#endif + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } + } + } +#else + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } +#endif + if (obj && !PySwigObject_Check(obj)) { + /* a PyObject is called 'this', try to get the 'real this' + PySwigObject from it */ + return SWIG_Python_GetSwigThis(obj); + } + return (PySwigObject *)obj; + } +} + +/* Acquire a pointer value */ + +SWIGRUNTIME int +SWIG_Python_AcquirePtr(PyObject *obj, int own) { + if (own == SWIG_POINTER_OWN) { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (sobj) { + int oldown = sobj->own; + sobj->own = own; + return oldown; + } + } + return 0; +} + +/* Convert a pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { + if (!obj) return SWIG_ERROR; + if (obj == Py_None) { + if (ptr) *ptr = 0; + return SWIG_OK; + } else { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (own) + *own = 0; + while (sobj) { + void *vptr = sobj->ptr; + if (ty) { + swig_type_info *to = sobj->ty; + if (to == ty) { + /* no type cast needed */ + if (ptr) *ptr = vptr; + break; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) { + sobj = (PySwigObject *)sobj->next; + } else { + if (ptr) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + } + break; + } + } + } else { + if (ptr) *ptr = vptr; + break; + } + } + if (sobj) { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + return SWIG_OK; + } else { + int res = SWIG_ERROR; + if (flags & SWIG_POINTER_IMPLICIT_CONV) { + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + if (data && !data->implicitconv) { + PyObject *klass = data->klass; + if (klass) { + PyObject *impconv; + data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ + impconv = SWIG_Python_CallFunctor(klass, obj); + data->implicitconv = 0; + if (PyErr_Occurred()) { + PyErr_Clear(); + impconv = 0; + } + if (impconv) { + PySwigObject *iobj = SWIG_Python_GetSwigThis(impconv); + if (iobj) { + void *vptr; + res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); + if (SWIG_IsOK(res)) { + if (ptr) { + *ptr = vptr; + /* transfer the ownership to 'ptr' */ + iobj->own = 0; + res = SWIG_AddCast(res); + res = SWIG_AddNewMask(res); + } else { + res = SWIG_AddCast(res); + } + } + } + Py_DECREF(impconv); + } + } + } + } + return res; + } + } +} + +/* Convert a function ptr value */ + +SWIGRUNTIME int +SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { + if (!PyCFunction_Check(obj)) { + return SWIG_ConvertPtr(obj, ptr, ty, 0); + } else { + void *vptr = 0; + + /* here we get the method pointer for callbacks */ + const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); + const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; + if (desc) { + desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; + if (!desc) return SWIG_ERROR; + } + if (ty) { + swig_cast_info *tc = SWIG_TypeCheck(desc,ty); + if (tc) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } else { + return SWIG_ERROR; + } + } else { + *ptr = vptr; + } + return SWIG_OK; + } +} + +/* Convert a packed value value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = PySwigPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Create a new pointer object + * ----------------------------------------------------------------------------- */ + +/* + Create a new instance object, whitout calling __init__, and set the + 'this' attribute. +*/ + +SWIGRUNTIME PyObject* +SWIG_Python_NewShadowInstance(PySwigClientData *data, PyObject *swig_this) +{ +#if (PY_VERSION_HEX >= 0x02020000) + PyObject *inst = 0; + PyObject *newraw = data->newraw; + if (newraw) { + inst = PyObject_Call(newraw, data->newargs, NULL); + if (inst) { +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + PyDict_SetItem(dict, SWIG_This(), swig_this); + } + } +#else + PyObject *key = SWIG_This(); + PyObject_SetAttr(inst, key, swig_this); +#endif + } + } else { + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + } + return inst; +#else +#if (PY_VERSION_HEX >= 0x02010000) + PyObject *inst; + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + return (PyObject *) inst; +#else + PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); + if (inst == NULL) { + return NULL; + } + inst->in_class = (PyClassObject *)data->newargs; + Py_INCREF(inst->in_class); + inst->in_dict = PyDict_New(); + if (inst->in_dict == NULL) { + Py_DECREF(inst); + return NULL; + } +#ifdef Py_TPFLAGS_HAVE_WEAKREFS + inst->in_weakreflist = NULL; +#endif +#ifdef Py_TPFLAGS_GC + PyObject_GC_Init(inst); +#endif + PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); + return (PyObject *) inst; +#endif +#endif +} + +SWIGRUNTIME void +SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) +{ + PyObject *dict; +#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + } + PyDict_SetItem(dict, SWIG_This(), swig_this); + return; + } +#endif + dict = PyObject_GetAttrString(inst, (char*)"__dict__"); + PyDict_SetItem(dict, SWIG_This(), swig_this); + Py_DECREF(dict); +} + + +SWIGINTERN PyObject * +SWIG_Python_InitShadowInstance(PyObject *args) { + PyObject *obj[2]; + if (!SWIG_Python_UnpackTuple(args,(char*)"swiginit", 2, 2, obj)) { + return NULL; + } else { + PySwigObject *sthis = SWIG_Python_GetSwigThis(obj[0]); + if (sthis) { + PySwigObject_append((PyObject*) sthis, obj[1]); + } else { + SWIG_Python_SetSwigThis(obj[0], obj[1]); + } + return SWIG_Py_Void(); + } +} + +/* Create a new pointer object */ + +SWIGRUNTIME PyObject * +SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int flags) { + if (!ptr) { + return SWIG_Py_Void(); + } else { + int own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; + PyObject *robj = PySwigObject_New(ptr, type, own); + PySwigClientData *clientdata = type ? (PySwigClientData *)(type->clientdata) : 0; + if (clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { + PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); + if (inst) { + Py_DECREF(robj); + robj = inst; + } + } + return robj; + } +} + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? PySwigPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_LINK_RUNTIME +void *SWIG_ReturnGlobalTypeList(void *); +#endif + +SWIGRUNTIME swig_module_info * +SWIG_Python_GetModule(void) { + static void *type_pointer = (void *)0; + /* first check if module already created */ + if (!type_pointer) { +#ifdef SWIG_LINK_RUNTIME + type_pointer = SWIG_ReturnGlobalTypeList((void *)0); +#else + type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); + if (PyErr_Occurred()) { + PyErr_Clear(); + type_pointer = (void *)0; + } +#endif + } + return (swig_module_info *) type_pointer; +} + +#if PY_MAJOR_VERSION < 2 +/* PyModule_AddObject function was introduced in Python 2.0. The following function + is copied out of Python/modsupport.c in python version 2.3.4 */ +SWIGINTERN int +PyModule_AddObject(PyObject *m, char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs module as first arg"); + return SWIG_ERROR; + } + if (!o) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs non-NULL value"); + return SWIG_ERROR; + } + + dict = PyModule_GetDict(m); + if (dict == NULL) { + /* Internal error -- modules must have a dict! */ + PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", + PyModule_GetName(m)); + return SWIG_ERROR; + } + if (PyDict_SetItemString(dict, name, o)) + return SWIG_ERROR; + Py_DECREF(o); + return SWIG_OK; +} +#endif + +SWIGRUNTIME void +SWIG_Python_DestroyModule(void *vptr) +{ + swig_module_info *swig_module = (swig_module_info *) vptr; + swig_type_info **types = swig_module->types; + size_t i; + for (i =0; i < swig_module->size; ++i) { + swig_type_info *ty = types[i]; + if (ty->owndata) { + PySwigClientData *data = (PySwigClientData *) ty->clientdata; + if (data) PySwigClientData_Del(data); + } + } + Py_DECREF(SWIG_This()); +} + +SWIGRUNTIME void +SWIG_Python_SetModule(swig_module_info *swig_module) { + static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} };/* Sentinel */ + + PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + swig_empty_runtime_method_table); + PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +} + +/* The python cached type query */ +SWIGRUNTIME PyObject * +SWIG_Python_TypeCache(void) { + static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); + return cache; +} + +SWIGRUNTIME swig_type_info * +SWIG_Python_TypeQuery(const char *type) +{ + PyObject *cache = SWIG_Python_TypeCache(); + PyObject *key = PyString_FromString(type); + PyObject *obj = PyDict_GetItem(cache, key); + swig_type_info *descriptor; + if (obj) { + descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); + } else { + swig_module_info *swig_module = SWIG_Python_GetModule(); + descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); + if (descriptor) { + obj = PyCObject_FromVoidPtr(descriptor, NULL); + PyDict_SetItem(cache, key, obj); + Py_DECREF(obj); + } + } + Py_DECREF(key); + return descriptor; +} + +/* + For backward compatibility only +*/ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) +#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) + +SWIGRUNTIME int +SWIG_Python_AddErrMesg(const char* mesg, int infront) +{ + if (PyErr_Occurred()) { + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + Py_XINCREF(type); + PyErr_Clear(); + if (infront) { + PyErr_Format(type, "%s %s", mesg, PyString_AsString(old_str)); + } else { + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + } + Py_DECREF(old_str); + } + return 1; + } else { + return 0; + } +} + +SWIGRUNTIME int +SWIG_Python_ArgFail(int argnum) +{ + if (PyErr_Occurred()) { + /* add information about failing argument */ + char mesg[256]; + PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); + return SWIG_Python_AddErrMesg(mesg, 1); + } else { + return 0; + } +} + +SWIGRUNTIMEINLINE const char * +PySwigObject_GetDesc(PyObject *self) +{ + PySwigObject *v = (PySwigObject *)self; + swig_type_info *ty = v ? v->ty : 0; + return ty ? ty->str : (char*)""; +} + +SWIGRUNTIME void +SWIG_Python_TypeError(const char *type, PyObject *obj) +{ + if (type) { +#if defined(SWIG_COBJECT_TYPES) + if (obj && PySwigObject_Check(obj)) { + const char *otype = (const char *) PySwigObject_GetDesc(obj); + if (otype) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'PySwigObject(%s)' is received", + type, otype); + return; + } + } else +#endif + { + const char *otype = (obj ? obj->ob_type->tp_name : 0); + if (otype) { + PyObject *str = PyObject_Str(obj); + const char *cstr = str ? PyString_AsString(str) : 0; + if (cstr) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", + type, otype, cstr); + } else { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", + type, otype); + } + Py_XDECREF(str); + return; + } + } + PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); + } else { + PyErr_Format(PyExc_TypeError, "unexpected type is received"); + } +} + + +/* Convert a pointer value, signal an exception on a type mismatch */ +SWIGRUNTIME void * +SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) { + void *result; + if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { + PyErr_Clear(); + if (flags & SWIG_POINTER_EXCEPTION) { + SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); + SWIG_Python_ArgFail(argnum); + } + } + return result; +} + + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_TDB_DATA swig_types[0] +#define SWIGTYPE_p_char swig_types[1] +#define SWIGTYPE_p_int swig_types[2] +#define SWIGTYPE_p_long_long swig_types[3] +#define SWIGTYPE_p_short swig_types[4] +#define SWIGTYPE_p_signed_char swig_types[5] +#define SWIGTYPE_p_tdb_context swig_types[6] +#define SWIGTYPE_p_unsigned_char swig_types[7] +#define SWIGTYPE_p_unsigned_int swig_types[8] +#define SWIGTYPE_p_unsigned_long_long swig_types[9] +#define SWIGTYPE_p_unsigned_short swig_types[10] +static swig_type_info *swig_types[12]; +static swig_module_info swig_module = {swig_types, 11, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#if (PY_VERSION_HEX <= 0x02000000) +# if !defined(SWIG_PYTHON_CLASSIC) +# error "This python version requires swig to be run with the '-classic' option" +# endif +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodern' option" +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodernargs' option" +#endif +#ifndef METH_O +# error "This python version requires swig to be run with the '-nofastunpack' option" +#endif +#ifdef SWIG_TypeQuery +# undef SWIG_TypeQuery +#endif +#define SWIG_TypeQuery SWIG_Python_TypeQuery + +/*----------------------------------------------- + @(target):= _tdb.so + ------------------------------------------------*/ +#define SWIG_init init_tdb + +#define SWIG_name "_tdb" + +#define SWIGVERSION 0x010335 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + + +/* This symbol is used in both includes.h and Python.h which causes an + annoying compiler warning. */ + +#ifdef HAVE_FSTAT +#undef HAVE_FSTAT +#endif + +/* Include tdb headers */ +#include +#include +#include +#include + +typedef TDB_CONTEXT tdb; + + + #define SWIG_From_long PyInt_FromLong + + +SWIGINTERNINLINE PyObject * +SWIG_From_int (int value) +{ + return SWIG_From_long (value); +} + + +SWIGINTERN swig_type_info* +SWIG_pchar_descriptor(void) +{ + static int init = 0; + static swig_type_info* info = 0; + if (!init) { + info = SWIG_TypeQuery("_p_char"); + init = 1; + } + return info; +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) +{ + if (PyString_Check(obj)) { + char *cstr; Py_ssize_t len; + PyString_AsStringAndSize(obj, &cstr, &len); + if (cptr) { + if (alloc) { + /* + In python the user should not be able to modify the inner + string representation. To warranty that, if you define + SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string + buffer is always returned. + + The default behavior is just to return the pointer value, + so, be careful. + */ +#if defined(SWIG_PYTHON_SAFE_CSTRINGS) + if (*alloc != SWIG_OLDOBJ) +#else + if (*alloc == SWIG_NEWOBJ) +#endif + { + *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + *cptr = PyString_AsString(obj); + } + } + if (psize) *psize = len + 1; + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + void* vptr = 0; + if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = (char *) vptr; + if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + + +#include +#if !defined(SWIG_NO_LLONG_MAX) +# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) +# define LLONG_MAX __LONG_LONG_MAX__ +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +# endif +#endif + + +SWIGINTERN int +SWIG_AsVal_double (PyObject *obj, double *val) +{ + int res = SWIG_TypeError; + if (PyFloat_Check(obj)) { + if (val) *val = PyFloat_AsDouble(obj); + return SWIG_OK; + } else if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + double v = PyLong_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + double d = PyFloat_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = d; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); + } else { + PyErr_Clear(); + } + } + } +#endif + return res; +} + + +#include + + +#include + + +SWIGINTERNINLINE int +SWIG_CanCastAsInteger(double *d, double min, double max) { + double x = *d; + if ((min <= x && x <= max)) { + double fx = floor(x); + double cx = ceil(x); + double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ + if ((errno == EDOM) || (errno == ERANGE)) { + errno = 0; + } else { + double summ, reps, diff; + if (rd < x) { + diff = x - rd; + } else if (rd > x) { + diff = rd - x; + } else { + return 1; + } + summ = rd + x; + reps = diff/summ; + if (reps < 8*DBL_EPSILON) { + *d = rd; + return 1; + } + } + } + return 0; +} + + +SWIGINTERN int +SWIG_AsVal_long (PyObject *obj, long* val) +{ + if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + long v = PyInt_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { + if (val) *val = (long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_int (PyObject * obj, int *val) +{ + long v; + int res = SWIG_AsVal_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v < INT_MIN || v > INT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (int)(v); + } + } + return res; +} + +SWIGINTERN tdb *new_tdb(char const *name,int hash_size,int tdb_flags,int flags,mode_t mode){ + return tdb_open(name, hash_size, tdb_flags, flags, mode); + } +SWIGINTERN void delete_tdb(tdb *self){ tdb_close(self); } + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + if (carray) { + if (size > INT_MAX) { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + return pchar_descriptor ? + SWIG_NewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void(); + } else { + return PyString_FromStringAndSize(carray, (int)(size)); + } + } else { + return SWIG_Py_Void(); + } +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtr(const char *cptr) +{ + return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); +} + + +SWIGINTERNINLINE PyObject* +SWIG_From_unsigned_SS_long (unsigned long value) +{ + return (value > LONG_MAX) ? + PyLong_FromUnsignedLong(value) : PyInt_FromLong((long)(value)); +} + + +SWIGINTERNINLINE PyObject * +SWIG_From_size_t (size_t value) +{ + return SWIG_From_unsigned_SS_long ((unsigned long)(value)); +} + +#ifdef __cplusplus +extern "C" { +#endif +SWIGINTERN PyObject *_wrap_new_Tdb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int arg2 ; + int arg3 ; + int arg4 ; + mode_t arg5 ; + tdb *result = 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + int val5 ; + int ecode5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + char * kwnames[] = { + (char *) "name",(char *) "hash_size",(char *) "tdb_flags",(char *) "flags",(char *) "mode", NULL + }; + + arg2 = 0; + arg3 = TDB_DEFAULT; + arg4 = O_RDWR; + arg5 = 0600; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:new_Tdb",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Tdb" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + if (obj1) { + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_Tdb" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + } + if (obj2) { + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "new_Tdb" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + } + if (obj3) { + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "new_Tdb" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + } + if (obj4) { + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "new_Tdb" "', argument " "5"" of type '" "mode_t""'"); + } + arg5 = (mode_t)(val5); + } + result = (tdb *)new_tdb((char const *)arg1,arg2,arg3,arg4,arg5); + /* Throw an IOError exception from errno if tdb_open() returns NULL */ + if (result == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + SWIG_fail; + } + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_tdb_context, 0); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_error(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + enum TDB_ERROR result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_error" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (enum TDB_ERROR)tdb_error(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_delete_Tdb(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Tdb" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + delete_tdb(arg1); + + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_close(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_close" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_close(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_append(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + TDB_DATA arg2 ; + TDB_DATA arg3 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "key",(char *) "new_dbuf", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Tdb_append",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_append" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + if (obj1 == Py_None) { + (&arg2)->dsize = 0; + (&arg2)->dptr = NULL; + } else if (!PyString_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + (&arg2)->dsize = PyString_Size(obj1); + (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); + } + if (obj2 == Py_None) { + (&arg3)->dsize = 0; + (&arg3)->dptr = NULL; + } else if (!PyString_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + (&arg3)->dsize = PyString_Size(obj2); + (&arg3)->dptr = (uint8_t *)PyString_AsString(obj2); + } + result = (int)tdb_append(arg1,arg2,arg3); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_errorstr(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_errorstr" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (char *)tdb_errorstr(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + TDB_DATA arg2 ; + TDB_DATA result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "key", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_get",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_get" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + if (obj1 == Py_None) { + (&arg2)->dsize = 0; + (&arg2)->dptr = NULL; + } else if (!PyString_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + (&arg2)->dsize = PyString_Size(obj1); + (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); + } + result = tdb_fetch(arg1,arg2); + if ((&result)->dptr == NULL && (&result)->dsize == 0) { + resultobj = Py_None; + } else { + resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize); + free((&result)->dptr); + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_delete(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + TDB_DATA arg2 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "key", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_delete",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_delete" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + if (obj1 == Py_None) { + (&arg2)->dsize = 0; + (&arg2)->dptr = NULL; + } else if (!PyString_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + (&arg2)->dsize = PyString_Size(obj1); + (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); + } + result = (int)tdb_delete(arg1,arg2); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_store(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + TDB_DATA arg2 ; + TDB_DATA arg3 ; + int arg4 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "key",(char *) "dbuf",(char *) "flag", NULL + }; + + arg4 = TDB_REPLACE; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:Tdb_store",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_store" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + if (obj1 == Py_None) { + (&arg2)->dsize = 0; + (&arg2)->dptr = NULL; + } else if (!PyString_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + (&arg2)->dsize = PyString_Size(obj1); + (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); + } + if (obj2 == Py_None) { + (&arg3)->dsize = 0; + (&arg3)->dptr = NULL; + } else if (!PyString_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + (&arg3)->dsize = PyString_Size(obj2); + (&arg3)->dptr = (uint8_t *)PyString_AsString(obj2); + } + if (obj3) { + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Tdb_store" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + } + result = (int)tdb_store(arg1,arg2,arg3,arg4); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_exists(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + TDB_DATA arg2 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "key", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_exists",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_exists" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + if (obj1 == Py_None) { + (&arg2)->dsize = 0; + (&arg2)->dptr = NULL; + } else if (!PyString_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + (&arg2)->dsize = PyString_Size(obj1); + (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); + } + result = (int)tdb_exists(arg1,arg2); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_firstkey(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + TDB_DATA result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_firstkey" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = tdb_firstkey(arg1); + if ((&result)->dptr == NULL && (&result)->dsize == 0) { + resultobj = Py_None; + } else { + resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize); + free((&result)->dptr); + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_nextkey(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + TDB_DATA arg2 ; + TDB_DATA result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "key", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_nextkey",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_nextkey" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + if (obj1 == Py_None) { + (&arg2)->dsize = 0; + (&arg2)->dptr = NULL; + } else if (!PyString_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "string arg expected"); + return NULL; + } else { + (&arg2)->dsize = PyString_Size(obj1); + (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); + } + result = tdb_nextkey(arg1,arg2); + if ((&result)->dptr == NULL && (&result)->dsize == 0) { + resultobj = Py_None; + } else { + resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize); + free((&result)->dptr); + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_lock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_lock_all" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_lockall(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_unlock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_unlock_all" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_unlockall(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_read_lock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_read_lock_all" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_lockall_read(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_read_unlock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_read_unlock_all" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_unlockall_read(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_reopen(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_reopen" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_reopen(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_transaction_start(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_start" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_transaction_start(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_transaction_commit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_commit" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_transaction_commit(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_transaction_cancel(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_cancel" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_transaction_cancel(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_transaction_recover(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_recover" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_transaction_recover(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_hash_size(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_hash_size" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_hash_size(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_map_size(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + size_t result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_map_size" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = tdb_map_size(arg1); + resultobj = SWIG_From_size_t((size_t)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_get_flags(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_get_flags" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (int)tdb_get_flags(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_set_max_dead(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "max_dead", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_set_max_dead",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_set_max_dead" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Tdb_set_max_dead" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + tdb_set_max_dead(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Tdb_name(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + tdb *arg1 = (tdb *) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_name" "', argument " "1"" of type '" "tdb *""'"); + } + arg1 = (tdb *)(argp1); + result = (char *)tdb_name(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *Tdb_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_tdb_context, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject *Tdb_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + return SWIG_Python_InitShadowInstance(args); +} + +static PyMethodDef SwigMethods[] = { + { (char *)"new_Tdb", (PyCFunction) _wrap_new_Tdb, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600)\n" + "Open a TDB file.\n" + ""}, + { (char *)"Tdb_error", (PyCFunction)_wrap_Tdb_error, METH_O, (char *)"\n" + "S.error() -> int\n" + "Find last error number returned by operation on this TDB.\n" + ""}, + { (char *)"delete_Tdb", (PyCFunction)_wrap_delete_Tdb, METH_O, NULL}, + { (char *)"Tdb_close", (PyCFunction)_wrap_Tdb_close, METH_O, (char *)"\n" + "S.close() -> None\n" + "Close the TDB file.\n" + ""}, + { (char *)"Tdb_append", (PyCFunction) _wrap_Tdb_append, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Tdb_errorstr", (PyCFunction)_wrap_Tdb_errorstr, METH_O, (char *)"\n" + "S.errorstr() -> errorstring\n" + "Obtain last error message.\n" + ""}, + { (char *)"Tdb_get", (PyCFunction) _wrap_Tdb_get, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.fetch(key) -> value\n" + "Fetch a value.\n" + ""}, + { (char *)"Tdb_delete", (PyCFunction) _wrap_Tdb_delete, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.delete(key) -> None\n" + "Delete an entry.\n" + ""}, + { (char *)"Tdb_store", (PyCFunction) _wrap_Tdb_store, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.store(key, value, flag=TDB_REPLACE) -> None\n" + "Store an entry.\n" + ""}, + { (char *)"Tdb_exists", (PyCFunction) _wrap_Tdb_exists, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.exists(key) -> bool\n" + "Check whether key exists in this database.\n" + ""}, + { (char *)"Tdb_firstkey", (PyCFunction)_wrap_Tdb_firstkey, METH_O, (char *)"\n" + "S.firstkey() -> data\n" + "Return the first key in this database.\n" + ""}, + { (char *)"Tdb_nextkey", (PyCFunction) _wrap_Tdb_nextkey, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.nextkey(prev) -> data\n" + "Return the next key in this database.\n" + ""}, + { (char *)"Tdb_lock_all", (PyCFunction)_wrap_Tdb_lock_all, METH_O, (char *)"S.lockall() -> bool"}, + { (char *)"Tdb_unlock_all", (PyCFunction)_wrap_Tdb_unlock_all, METH_O, (char *)"S.unlockall() -> bool"}, + { (char *)"Tdb_read_lock_all", (PyCFunction)_wrap_Tdb_read_lock_all, METH_O, NULL}, + { (char *)"Tdb_read_unlock_all", (PyCFunction)_wrap_Tdb_read_unlock_all, METH_O, NULL}, + { (char *)"Tdb_reopen", (PyCFunction)_wrap_Tdb_reopen, METH_O, (char *)"\n" + "S.reopen() -> bool\n" + "Reopen this file.\n" + ""}, + { (char *)"Tdb_transaction_start", (PyCFunction)_wrap_Tdb_transaction_start, METH_O, (char *)"\n" + "S.transaction_start() -> None\n" + "Start a new transaction.\n" + ""}, + { (char *)"Tdb_transaction_commit", (PyCFunction)_wrap_Tdb_transaction_commit, METH_O, (char *)"\n" + "S.transaction_commit() -> None\n" + "Commit the currently active transaction.\n" + ""}, + { (char *)"Tdb_transaction_cancel", (PyCFunction)_wrap_Tdb_transaction_cancel, METH_O, (char *)"\n" + "S.transaction_cancel() -> None\n" + "Cancel the currently active transaction.\n" + ""}, + { (char *)"Tdb_transaction_recover", (PyCFunction)_wrap_Tdb_transaction_recover, METH_O, NULL}, + { (char *)"Tdb_hash_size", (PyCFunction)_wrap_Tdb_hash_size, METH_O, (char *)"S.hash_size() -> int"}, + { (char *)"Tdb_map_size", (PyCFunction)_wrap_Tdb_map_size, METH_O, (char *)"S.map_size() -> int"}, + { (char *)"Tdb_get_flags", (PyCFunction)_wrap_Tdb_get_flags, METH_O, (char *)"S.get_flags() -> int"}, + { (char *)"Tdb_set_max_dead", (PyCFunction) _wrap_Tdb_set_max_dead, METH_VARARGS | METH_KEYWORDS, (char *)"S.set_max_dead(int) -> None"}, + { (char *)"Tdb_name", (PyCFunction)_wrap_Tdb_name, METH_O, (char *)"\n" + "S.name() -> path\n" + "Return filename of this TDB file.\n" + ""}, + { (char *)"Tdb_swigregister", Tdb_swigregister, METH_VARARGS, NULL}, + { (char *)"Tdb_swiginit", Tdb_swiginit, METH_VARARGS, NULL}, + { NULL, NULL, 0, NULL } +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_TDB_DATA = {"_p_TDB_DATA", "TDB_DATA *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *|mode_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_tdb_context = {"_p_tdb_context", "struct tdb_context *|tdb *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_TDB_DATA, + &_swigt__p_char, + &_swigt__p_int, + &_swigt__p_long_long, + &_swigt__p_short, + &_swigt__p_signed_char, + &_swigt__p_tdb_context, + &_swigt__p_unsigned_char, + &_swigt__p_unsigned_int, + &_swigt__p_unsigned_long_long, + &_swigt__p_unsigned_short, +}; + +static swig_cast_info _swigc__p_TDB_DATA[] = { {&_swigt__p_TDB_DATA, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_long_long[] = { {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_short[] = { {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_signed_char[] = { {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_tdb_context[] = { {&_swigt__p_tdb_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_int[] = { {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_long_long[] = { {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_short[] = { {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_TDB_DATA, + _swigc__p_char, + _swigc__p_int, + _swigc__p_long_long, + _swigc__p_short, + _swigc__p_signed_char, + _swigc__p_tdb_context, + _swigc__p_unsigned_char, + _swigc__p_unsigned_int, + _swigc__p_unsigned_long_long, + _swigc__p_unsigned_short, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_const_info swig_const_table[] = { +{0, 0, 0, 0.0, 0, 0}}; + +#ifdef __cplusplus +} +#endif +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found, init; + + clientdata = clientdata; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + init = 1; + } else { + init = 0; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* When multiple interpeters are used, a module could have already been initialized in + a different interpreter, but not yet have a pointer in this interpreter. + In this case, we do not want to continue adding types... everything should be + set up already */ + if (init == 0) return; + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + /* Python-specific SWIG API */ +#define SWIG_newvarlink() SWIG_Python_newvarlink() +#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) +#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) + + /* ----------------------------------------------------------------------------- + * global variable support code. + * ----------------------------------------------------------------------------- */ + + typedef struct swig_globalvar { + char *name; /* Name of global variable */ + PyObject *(*get_attr)(void); /* Return the current value */ + int (*set_attr)(PyObject *); /* Set the value */ + struct swig_globalvar *next; + } swig_globalvar; + + typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar *vars; + } swig_varlinkobject; + + SWIGINTERN PyObject * + swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { + return PyString_FromString(""); + } + + SWIGINTERN PyObject * + swig_varlink_str(swig_varlinkobject *v) { + PyObject *str = PyString_FromString("("); + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + PyString_ConcatAndDel(&str,PyString_FromString(var->name)); + if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); + } + PyString_ConcatAndDel(&str,PyString_FromString(")")); + return str; + } + + SWIGINTERN int + swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + PyObject *str = swig_varlink_str(v); + fprintf(fp,"Swig global variables "); + fprintf(fp,"%s\n", PyString_AsString(str)); + Py_DECREF(str); + return 0; + } + + SWIGINTERN void + swig_varlink_dealloc(swig_varlinkobject *v) { + swig_globalvar *var = v->vars; + while (var) { + swig_globalvar *n = var->next; + free(var->name); + free(var); + var = n; + } + } + + SWIGINTERN PyObject * + swig_varlink_getattr(swig_varlinkobject *v, char *n) { + PyObject *res = NULL; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->get_attr)(); + break; + } + var = var->next; + } + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN int + swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { + int res = 1; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->set_attr)(p); + break; + } + var = var->next; + } + if (res == 1 && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN PyTypeObject* + swig_varlink_type(void) { + static char varlink__doc__[] = "Swig var link object"; + static PyTypeObject varlink_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* Number of items in variable part (ob_size) */ + (char *)"swigvarlink", /* Type name (tp_name) */ + sizeof(swig_varlinkobject), /* Basic size (tp_basicsize) */ + 0, /* Itemsize (tp_itemsize) */ + (destructor) swig_varlink_dealloc, /* Deallocator (tp_dealloc) */ + (printfunc) swig_varlink_print, /* Print (tp_print) */ + (getattrfunc) swig_varlink_getattr, /* get attr (tp_getattr) */ + (setattrfunc) swig_varlink_setattr, /* Set attr (tp_setattr) */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)swig_varlink_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + varlink__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + varlink_type = tmp; + varlink_type.ob_type = &PyType_Type; + type_init = 1; + } + return &varlink_type; + } + + /* Create a variable linking object for use later */ + SWIGINTERN PyObject * + SWIG_Python_newvarlink(void) { + swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); + if (result) { + result->vars = 0; + } + return ((PyObject*) result); + } + + SWIGINTERN void + SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { + swig_varlinkobject *v = (swig_varlinkobject *) p; + swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + if (gv) { + size_t size = strlen(name)+1; + gv->name = (char *)malloc(size); + if (gv->name) { + strncpy(gv->name,name,size); + gv->get_attr = get_attr; + gv->set_attr = set_attr; + gv->next = v->vars; + } + } + v->vars = gv; + } + + SWIGINTERN PyObject * + SWIG_globals(void) { + static PyObject *_SWIG_globals = 0; + if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); + return _SWIG_globals; + } + + /* ----------------------------------------------------------------------------- + * constants/methods manipulation + * ----------------------------------------------------------------------------- */ + + /* Install Constants */ + SWIGINTERN void + SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { + PyObject *obj = 0; + size_t i; + for (i = 0; constants[i].type; ++i) { + switch(constants[i].type) { + case SWIG_PY_POINTER: + obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); + break; + case SWIG_PY_BINARY: + obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); + break; + default: + obj = 0; + break; + } + if (obj) { + PyDict_SetItemString(d, constants[i].name, obj); + Py_DECREF(obj); + } + } + } + + /* -----------------------------------------------------------------------------*/ + /* Fix SwigMethods to carry the callback ptrs when needed */ + /* -----------------------------------------------------------------------------*/ + + SWIGINTERN void + SWIG_Python_FixMethods(PyMethodDef *methods, + swig_const_info *const_table, + swig_type_info **types, + swig_type_info **types_initial) { + size_t i; + for (i = 0; methods[i].ml_name; ++i) { + const char *c = methods[i].ml_doc; + if (c && (c = strstr(c, "swig_ptr: "))) { + int j; + swig_const_info *ci = 0; + const char *name = c + 10; + for (j = 0; const_table[j].type; ++j) { + if (strncmp(const_table[j].name, name, + strlen(const_table[j].name)) == 0) { + ci = &(const_table[j]); + break; + } + } + if (ci) { + size_t shift = (ci->ptype) - types; + swig_type_info *ty = types_initial[shift]; + size_t ldoc = (c - methods[i].ml_doc); + size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; + char *ndoc = (char*)malloc(ldoc + lptr + 10); + if (ndoc) { + char *buff = ndoc; + void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; + if (ptr) { + strncpy(buff, methods[i].ml_doc, ldoc); + buff += ldoc; + strncpy(buff, "swig_ptr: ", 10); + buff += 10; + SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); + methods[i].ml_doc = ndoc; + } + } + } + } + } + } + +#ifdef __cplusplus +} +#endif + +/* -----------------------------------------------------------------------------* + * Partial Init method + * -----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" +#endif +SWIGEXPORT void SWIG_init(void) { + PyObject *m, *d; + + /* Fix SwigMethods to carry the callback ptrs when needed */ + SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); + + m = Py_InitModule((char *) SWIG_name, SwigMethods); + d = PyModule_GetDict(m); + + SWIG_InitializeModule(0); + SWIG_InstallConstants(d,swig_const_table); + + + SWIG_Python_SetConstant(d, "REPLACE",SWIG_From_int((int)(TDB_REPLACE))); + SWIG_Python_SetConstant(d, "INSERT",SWIG_From_int((int)(TDB_INSERT))); + SWIG_Python_SetConstant(d, "MODIFY",SWIG_From_int((int)(TDB_MODIFY))); + SWIG_Python_SetConstant(d, "DEFAULT",SWIG_From_int((int)(TDB_DEFAULT))); + SWIG_Python_SetConstant(d, "CLEAR_IF_FIRST",SWIG_From_int((int)(TDB_CLEAR_IF_FIRST))); + SWIG_Python_SetConstant(d, "INTERNAL",SWIG_From_int((int)(TDB_INTERNAL))); + SWIG_Python_SetConstant(d, "NOLOCK",SWIG_From_int((int)(TDB_NOLOCK))); + SWIG_Python_SetConstant(d, "NOMMAP",SWIG_From_int((int)(TDB_NOMMAP))); + SWIG_Python_SetConstant(d, "CONVERT",SWIG_From_int((int)(TDB_CONVERT))); + SWIG_Python_SetConstant(d, "BIGENDIAN",SWIG_From_int((int)(TDB_BIGENDIAN))); + SWIG_Python_SetConstant(d, "TDB_SUCCESS",SWIG_From_int((int)(TDB_SUCCESS))); + SWIG_Python_SetConstant(d, "TDB_ERR_CORRUPT",SWIG_From_int((int)(TDB_ERR_CORRUPT))); + SWIG_Python_SetConstant(d, "TDB_ERR_IO",SWIG_From_int((int)(TDB_ERR_IO))); + SWIG_Python_SetConstant(d, "TDB_ERR_LOCK",SWIG_From_int((int)(TDB_ERR_LOCK))); + SWIG_Python_SetConstant(d, "TDB_ERR_OOM",SWIG_From_int((int)(TDB_ERR_OOM))); + SWIG_Python_SetConstant(d, "TDB_ERR_EXISTS",SWIG_From_int((int)(TDB_ERR_EXISTS))); + SWIG_Python_SetConstant(d, "TDB_ERR_NOLOCK",SWIG_From_int((int)(TDB_ERR_NOLOCK))); + SWIG_Python_SetConstant(d, "TDB_ERR_LOCK_TIMEOUT",SWIG_From_int((int)(TDB_ERR_LOCK_TIMEOUT))); + SWIG_Python_SetConstant(d, "TDB_ERR_NOEXIST",SWIG_From_int((int)(TDB_ERR_NOEXIST))); + SWIG_Python_SetConstant(d, "TDB_ERR_EINVAL",SWIG_From_int((int)(TDB_ERR_EINVAL))); + SWIG_Python_SetConstant(d, "TDB_ERR_RDONLY",SWIG_From_int((int)(TDB_ERR_RDONLY))); +} + diff --git a/tdb/tools/tdbbackup.c b/tdb/tools/tdbbackup.c new file mode 100644 index 000000000..6f3ca4831 --- /dev/null +++ b/tdb/tools/tdbbackup.c @@ -0,0 +1,300 @@ +/* + 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 . +*/ + +/* + + 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 +#endif + +static int failed; + +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(old_name, 0, 0, O_RDWR, 0); + 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(tmp_name, + hash_size ? hash_size : tdb_hash_size(tdb), + TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL, + st.st_mode & 0777); + if (!tdb_new) { + perror(tmp_name); + free(tmp_name); + return 1; + } + + /* lock the old tdb */ + if (tdb_lockall(tdb) != 0) { + fprintf(stderr,"Failed to lock %s\n", old_name); + 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); + + /* close the new tdb and re-open read-only */ + tdb_close(tdb_new); + tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0); + 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; + } + + /* make sure the new tdb has reached stable storage */ + fsync(tdb_fd(tdb_new)); + + /* 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(fname, 0, 0, O_RDONLY, 0); + + /* 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] \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"; + + 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. +*/ + +#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] \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 \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); +} diff --git a/tdb/tools/tdbtest.c b/tdb/tools/tdbtest.c new file mode 100644 index 000000000..416bc50a5 --- /dev/null +++ b/tdb/tools/tdbtest.c @@ -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 + + +#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. +*/ + +#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_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_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}, + {"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}, + {"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); +} + +/* 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;i8) 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" +" 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" +" ! 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) +{ + if (tdb) tdb_close(tdb); + tdb = tdb_open(tdbname, 0, TDB_CLEAR_IF_FIRST | (disable_mmap?TDB_NOMMAP:0), + O_RDWR | O_CREAT | O_TRUNC, 0600); + if (!tdb) { + printf("Could not create %s: %s\n", tdbname, strerror(errno)); + } +} + +static void open_tdb(const char *tdbname) +{ + if (tdb) tdb_close(tdb); + tdb = tdb_open(tdbname, 0, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600); + 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) +{ + unsigned timelimit = tlimit?atoi(tlimit):0; + double t; + int ops=0; + if (timelimit == 0) timelimit = 10; + printf("Testing traverse speed for %u seconds\n", timelimit); + _start_timer(); + while ((t=_end_timer()) < timelimit) { + tdb_traverse(tdb, traverse_fn, NULL); + printf("%10.3f ops/sec\r", (++ops)/t); + } + printf("\n"); +} + +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 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 */ + system(arg1); + 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_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_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; +} diff --git a/tdb/tools/tdbtorture.c b/tdb/tools/tdbtorture.c new file mode 100644 index 000000000..9265cf07a --- /dev/null +++ b/tdb/tools/tdbtorture.c @@ -0,0 +1,318 @@ +/* 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 +#endif + + +#define REOPEN_PROB 30 +#define DELETE_PROB 8 +#define STORE_PROB 4 +#define APPEND_PROB 6 +#define TRANSACTION_PROB 10 +#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; + +#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; + + error_count++; + + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); + fflush(stdout); +#if 0 + { + char *ptr; + 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 + + +ldb + + + +

tdb

+ +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. + +

Discussion and bug reports

+ +tdb does not currently have its own mailing list or bug tracking +system. For now, please use the samba-technical +mailing list, and the Samba +bugzilla bug tracking system. + +

Download

+ +You can download the latest release either via rsync or git.
+
+To fetch via git see the following guide:
+Using Git for Samba Development
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/tdb directory.
+
+To fetch via rsync use these commands: + +
+  rsync -Pavz samba.org::ftp/unpacked/tdb .
+  rsync -Pavz samba.org::ftp/unpacked/libreplace .
+
+ +and build in tdb. It will find the replace library in the directory +above automatically. + + + -- cgit